* [PATCH v1 0/2] GPIO-based hotplug i2c bus @ 2023-06-19 14:36 Svyatoslav Ryhel 2023-06-19 14:36 ` [PATCH v1 1/2] dt-bindings: i2c: add binding for i2c-hotplug-gpio Svyatoslav Ryhel 2023-06-19 14:36 ` [PATCH v1 2/2] i2c: Add GPIO-based hotplug gate Svyatoslav Ryhel 0 siblings, 2 replies; 6+ messages in thread From: Svyatoslav Ryhel @ 2023-06-19 14:36 UTC (permalink / raw) To: Andi Shyti, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Wolfram Sang, Michał Mirosław, Svyatoslav Ryhel Cc: linux-i2c, devicetree, linux-kernel ASUS Transformers require this driver for proper work with their dock. Dock is controlled by EC and its presence is detected by a GPIO. Michał Mirosław (1): i2c: Add GPIO-based hotplug gate Svyatoslav Ryhel (1): dt-bindings: i2c: add binding for i2c-hotplug-gpio .../bindings/i2c/i2c-hotplug-gpio.yaml | 68 +++++ drivers/i2c/Kconfig | 11 + drivers/i2c/Makefile | 1 + drivers/i2c/i2c-hotplug-gpio.c | 266 ++++++++++++++++++ 4 files changed, 346 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-hotplug-gpio.yaml create mode 100644 drivers/i2c/i2c-hotplug-gpio.c -- 2.39.2 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v1 1/2] dt-bindings: i2c: add binding for i2c-hotplug-gpio 2023-06-19 14:36 [PATCH v1 0/2] GPIO-based hotplug i2c bus Svyatoslav Ryhel @ 2023-06-19 14:36 ` Svyatoslav Ryhel 2023-06-19 14:45 ` Krzysztof Kozlowski 2023-06-19 15:17 ` Rob Herring 2023-06-19 14:36 ` [PATCH v1 2/2] i2c: Add GPIO-based hotplug gate Svyatoslav Ryhel 1 sibling, 2 replies; 6+ messages in thread From: Svyatoslav Ryhel @ 2023-06-19 14:36 UTC (permalink / raw) To: Andi Shyti, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Wolfram Sang, Michał Mirosław, Svyatoslav Ryhel Cc: linux-i2c, devicetree, linux-kernel Document device tree schema which describes hot-pluggable via GPIO i2c bus. Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com> --- .../bindings/i2c/i2c-hotplug-gpio.yaml | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-hotplug-gpio.yaml diff --git a/Documentation/devicetree/bindings/i2c/i2c-hotplug-gpio.yaml b/Documentation/devicetree/bindings/i2c/i2c-hotplug-gpio.yaml new file mode 100644 index 000000000000..74544687a2b8 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-hotplug-gpio.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/i2c/i2c-hotplug-gpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: GPIO detected hot-plugged I2C bus + +maintainers: + - Michał Mirosław <mirq-linux@rere.qmqm.pl> + +description: | + Driver for hot-plugged I2C busses, where some devices on a bus + are hot-pluggable and their presence is indicated by GPIO line. + +properties: + $nodename: + pattern: "^i2c-(.*)?" + + compatible: + items: + - const: i2c-hotplug-gpio + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + interrupts-extended: + minItems: 1 + + detect-gpios: + maxItems: 1 + + i2c-parent: + maxItems: 1 + +required: + - compatible + - "#address-cells" + - "#size-cells" + - interrupts-extended + - detect-gpios + - i2c-parent + +unevaluatedProperties: false + +examples: + - | + /* + * Asus Transformers use I2C hotplug for attachable dock keyboard + */ + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + + i2c-dock { + compatible = "i2c-hotplug-gpio"; + + #address-cells = <1>; + #size-cells = <0>; + + interrupts-extended = <&gpio 164 IRQ_TYPE_EDGE_BOTH>; + detect-gpios = <&gpio 164 1>; + + i2c-parent = <&{/i2c@7000c400}>; + }; +... -- 2.39.2 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v1 1/2] dt-bindings: i2c: add binding for i2c-hotplug-gpio 2023-06-19 14:36 ` [PATCH v1 1/2] dt-bindings: i2c: add binding for i2c-hotplug-gpio Svyatoslav Ryhel @ 2023-06-19 14:45 ` Krzysztof Kozlowski 2023-06-19 14:59 ` Svyatoslav Ryhel 2023-06-19 15:17 ` Rob Herring 1 sibling, 1 reply; 6+ messages in thread From: Krzysztof Kozlowski @ 2023-06-19 14:45 UTC (permalink / raw) To: Svyatoslav Ryhel, Andi Shyti, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Wolfram Sang, Michał Mirosław Cc: linux-i2c, devicetree, linux-kernel On 19/06/2023 16:36, Svyatoslav Ryhel wrote: > Document device tree schema which describes hot-pluggable via GPIO > i2c bus. > > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com> > --- > .../bindings/i2c/i2c-hotplug-gpio.yaml | 68 +++++++++++++++++++ > 1 file changed, 68 insertions(+) > create mode 100644 Documentation/devicetree/bindings/i2c/i2c-hotplug-gpio.yaml > > diff --git a/Documentation/devicetree/bindings/i2c/i2c-hotplug-gpio.yaml b/Documentation/devicetree/bindings/i2c/i2c-hotplug-gpio.yaml > new file mode 100644 > index 000000000000..74544687a2b8 > --- /dev/null > +++ b/Documentation/devicetree/bindings/i2c/i2c-hotplug-gpio.yaml > @@ -0,0 +1,68 @@ > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) > +%YAML 1.2 > +--- > +$id: http://devicetree.org/schemas/i2c/i2c-hotplug-gpio.yaml# > +$schema: http://devicetree.org/meta-schemas/core.yaml# > + > +title: GPIO detected hot-plugged I2C bus > + > +maintainers: > + - Michał Mirosław <mirq-linux@rere.qmqm.pl> > + > +description: | Do not need '|' unless you need to preserve formatting. > + Driver for hot-plugged I2C busses, where some devices on a bus > + are hot-pluggable and their presence is indicated by GPIO line. > + > +properties: > + $nodename: > + pattern: "^i2c-(.*)?" Drop > + > + compatible: > + items: > + - const: i2c-hotplug-gpio > + > + '#address-cells': > + const: 1 > + > + '#size-cells': > + const: 0 > + > + interrupts-extended: > + minItems: 1 > + > + detect-gpios: > + maxItems: 1 > + > + i2c-parent: > + maxItems: 1 I don't understand this part. You built it as a complimentary device to the I2C controller, but there is no such device as "hotplug I2C", right? The GPIO is part of the controller and this is imaginary (virtual) device? Otherwise, where does the "detect-gpios" go? To the SoC? Then it is not a real device... > + > +required: > + - compatible > + - "#address-cells" > + - "#size-cells" Use consistent quotes (' or "). > + - interrupts-extended > + - detect-gpios > + - i2c-parent > + > +unevaluatedProperties: false > + > +examples: > + - | > + /* > + * Asus Transformers use I2C hotplug for attachable dock keyboard > + */ > + #include <dt-bindings/gpio/gpio.h> > + #include <dt-bindings/interrupt-controller/irq.h> > + > + i2c-dock { > + compatible = "i2c-hotplug-gpio"; > + > + #address-cells = <1>; > + #size-cells = <0>; > + > + interrupts-extended = <&gpio 164 IRQ_TYPE_EDGE_BOTH>; > + detect-gpios = <&gpio 164 1>; You forgot define. > + > + i2c-parent = <&{/i2c@7000c400}>; Use normal phandles/labels like entire DTS, not full paths or node names. > + }; > +... Best regards, Krzysztof ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v1 1/2] dt-bindings: i2c: add binding for i2c-hotplug-gpio 2023-06-19 14:45 ` Krzysztof Kozlowski @ 2023-06-19 14:59 ` Svyatoslav Ryhel 0 siblings, 0 replies; 6+ messages in thread From: Svyatoslav Ryhel @ 2023-06-19 14:59 UTC (permalink / raw) To: Krzysztof Kozlowski Cc: Andi Shyti, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Wolfram Sang, Michał Mirosław, linux-i2c, devicetree, linux-kernel пн, 19 черв. 2023 р. о 17:45 Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> пише: > > On 19/06/2023 16:36, Svyatoslav Ryhel wrote: > > Document device tree schema which describes hot-pluggable via GPIO > > i2c bus. > > > > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com> > > --- > > .../bindings/i2c/i2c-hotplug-gpio.yaml | 68 +++++++++++++++++++ > > 1 file changed, 68 insertions(+) > > create mode 100644 Documentation/devicetree/bindings/i2c/i2c-hotplug-gpio.yaml > > > > diff --git a/Documentation/devicetree/bindings/i2c/i2c-hotplug-gpio.yaml b/Documentation/devicetree/bindings/i2c/i2c-hotplug-gpio.yaml > > new file mode 100644 > > index 000000000000..74544687a2b8 > > --- /dev/null > > +++ b/Documentation/devicetree/bindings/i2c/i2c-hotplug-gpio.yaml > > @@ -0,0 +1,68 @@ > > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) > > +%YAML 1.2 > > +--- > > +$id: http://devicetree.org/schemas/i2c/i2c-hotplug-gpio.yaml# > > +$schema: http://devicetree.org/meta-schemas/core.yaml# > > + > > +title: GPIO detected hot-plugged I2C bus > > + > > +maintainers: > > + - Michał Mirosław <mirq-linux@rere.qmqm.pl> > > + > > +description: | > > Do not need '|' unless you need to preserve formatting. > > > + Driver for hot-plugged I2C buses, where some devices on a bus > > + are hot-pluggable and their presence is indicated by GPIO line. > > + > > +properties: > > + $nodename: > > + pattern: "^i2c-(.*)?" > > Drop > > > + > > + compatible: > > + items: > > + - const: i2c-hotplug-gpio > > + > > + '#address-cells': > > + const: 1 > > + > > + '#size-cells': > > + const: 0 > > + > > + interrupts-extended: > > + minItems: 1 > > + > > + detect-gpios: > > + maxItems: 1 > > + > > + i2c-parent: > > + maxItems: 1 > > I don't understand this part. You built it as a complimentary device to > the I2C controller, but there is no such device as "hotplug I2C", right? > The GPIO is part of the controller and this is imaginary (virtual) device? > > Otherwise, where does the "detect-gpios" go? To the SoC? Then it is not > a real device... > This is basically GPIO controlled i2c bus duplication. Transformer has 2 ECs, one for pad and one for dock. They both are present on the i2c bus, but the dock is not always present. Its presence is determined by a GPIO. Once a dock is present, GPIO triggers bus duplication and all devices described on that bus are probed, same when detaching the dock. Detecting GPIO and interrupt GPIO is the same GPIO. > > + > > +required: > > + - compatible > > + - "#address-cells" > > + - "#size-cells" > > Use consistent quotes (' or "). > > > + - interrupts-extended > > + - detect-gpios > > + - i2c-parent > > + > > +unevaluatedProperties: false > > + > > +examples: > > + - | > > + /* > > + * Asus Transformers use I2C hotplug for attachable dock keyboard > > + */ > > + #include <dt-bindings/gpio/gpio.h> > > + #include <dt-bindings/interrupt-controller/irq.h> > > + > > + i2c-dock { > > + compatible = "i2c-hotplug-gpio"; > > + > > + #address-cells = <1>; > > + #size-cells = <0>; > > + > > + interrupts-extended = <&gpio 164 IRQ_TYPE_EDGE_BOTH>; > > + detect-gpios = <&gpio 164 1>; > > You forgot define. > Define GPIO name or high/low? May you specify? Best regards, Svyatoslav R. > > + > > + i2c-parent = <&{/i2c@7000c400}>; > > Use normal phandles/labels like entire DTS, not full paths or node names. > > > + }; > > +... > > Best regards, > Krzysztof > ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v1 1/2] dt-bindings: i2c: add binding for i2c-hotplug-gpio 2023-06-19 14:36 ` [PATCH v1 1/2] dt-bindings: i2c: add binding for i2c-hotplug-gpio Svyatoslav Ryhel 2023-06-19 14:45 ` Krzysztof Kozlowski @ 2023-06-19 15:17 ` Rob Herring 1 sibling, 0 replies; 6+ messages in thread From: Rob Herring @ 2023-06-19 15:17 UTC (permalink / raw) To: Svyatoslav Ryhel Cc: Wolfram Sang, linux-kernel, Krzysztof Kozlowski, Michał Mirosław, devicetree, Andi Shyti, Conor Dooley, Rob Herring, linux-i2c On Mon, 19 Jun 2023 17:36:10 +0300, Svyatoslav Ryhel wrote: > Document device tree schema which describes hot-pluggable via GPIO > i2c bus. > > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com> > --- > .../bindings/i2c/i2c-hotplug-gpio.yaml | 68 +++++++++++++++++++ > 1 file changed, 68 insertions(+) > create mode 100644 Documentation/devicetree/bindings/i2c/i2c-hotplug-gpio.yaml > My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check' on your patch (DT_CHECKER_FLAGS is new in v5.13): yamllint warnings/errors: dtschema/dtc warnings/errors: FATAL ERROR: Can't generate fixup for reference to path &{/i2c@7000c400} make[1]: *** [scripts/Makefile.lib:419: Documentation/devicetree/bindings/i2c/i2c-hotplug-gpio.example.dtb] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [Makefile:1512: dt_binding_check] Error 2 doc reference errors (make refcheckdocs): See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20230619143611.24482-2-clamor95@gmail.com The base for the series is generally the latest rc1. A different dependency should be noted in *this* patch. If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date: pip3 install dtschema --upgrade Please check and re-submit after running the above command yourself. Note that DT_SCHEMA_FILES can be set to your schema file to speed up checking your schema. However, it must be unset to test all examples with your schema. ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v1 2/2] i2c: Add GPIO-based hotplug gate 2023-06-19 14:36 [PATCH v1 0/2] GPIO-based hotplug i2c bus Svyatoslav Ryhel 2023-06-19 14:36 ` [PATCH v1 1/2] dt-bindings: i2c: add binding for i2c-hotplug-gpio Svyatoslav Ryhel @ 2023-06-19 14:36 ` Svyatoslav Ryhel 1 sibling, 0 replies; 6+ messages in thread From: Svyatoslav Ryhel @ 2023-06-19 14:36 UTC (permalink / raw) To: Andi Shyti, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Wolfram Sang, Michał Mirosław, Svyatoslav Ryhel Cc: linux-i2c, devicetree, linux-kernel From: Michał Mirosław <mirq-linux@rere.qmqm.pl> Implement driver for hot-plugged I2C busses, where some devices on a bus are hot-pluggable and their presence is indicated by GPIO line. Co-developed-by: Ion Agorria <ion@agorria.com> Signed-off-by: Ion Agorria <ion@agorria.com> Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com> --- drivers/i2c/Kconfig | 11 ++ drivers/i2c/Makefile | 1 + drivers/i2c/i2c-hotplug-gpio.c | 266 +++++++++++++++++++++++++++++++++ 3 files changed, 278 insertions(+) create mode 100644 drivers/i2c/i2c-hotplug-gpio.c diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 438905e2a1d0..3e3f7675ea4a 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -98,6 +98,17 @@ config I2C_SMBUS source "drivers/i2c/algos/Kconfig" source "drivers/i2c/busses/Kconfig" +config I2C_HOTPLUG_GPIO + tristate "Hot-plugged I2C bus detected by GPIO" + depends on GPIOLIB + depends on OF + help + If you say yes to this option, support will be included for + hot-plugging I2C devices with presence detected by GPIO pin value. + + This driver can also be built as a module. If so, the module + will be called i2c-hotplug-gpio. + config I2C_STUB tristate "I2C/SMBus Test Stub" depends on m diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index c1d493dc9bac..9fd44310835a 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o obj-$(CONFIG_I2C_MUX) += i2c-mux.o obj-y += algos/ busses/ muxes/ +obj-$(CONFIG_I2C_HOTPLUG_GPIO) += i2c-hotplug-gpio.o obj-$(CONFIG_I2C_STUB) += i2c-stub.o obj-$(CONFIG_I2C_SLAVE_EEPROM) += i2c-slave-eeprom.o obj-$(CONFIG_I2C_SLAVE_TESTUNIT) += i2c-slave-testunit.o diff --git a/drivers/i2c/i2c-hotplug-gpio.c b/drivers/i2c/i2c-hotplug-gpio.c new file mode 100644 index 000000000000..18c2d7f44d29 --- /dev/null +++ b/drivers/i2c/i2c-hotplug-gpio.c @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * I2C hotplug gate controlled by GPIO + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +struct i2c_hotplug_priv { + struct i2c_adapter adap; + struct i2c_adapter *parent; + struct device *dev; + struct gpio_desc *gpio; + int irq; +}; + +static inline struct i2c_adapter *i2c_hotplug_parent(struct i2c_adapter *adap) +{ + struct i2c_hotplug_priv *priv = container_of(adap, struct i2c_hotplug_priv, adap); + + return priv->parent; +} + +static int i2c_hotplug_master_xfer(struct i2c_adapter *adap, + struct i2c_msg msgs[], int num) +{ + struct i2c_adapter *parent = i2c_hotplug_parent(adap); + + return parent->algo->master_xfer(parent, msgs, num); +} + +static int i2c_hotplug_smbus_xfer(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int protocol, + union i2c_smbus_data *data) +{ + struct i2c_adapter *parent = i2c_hotplug_parent(adap); + + return parent->algo->smbus_xfer(parent, addr, flags, read_write, + command, protocol, data); +} + +static u32 i2c_hotplug_functionality(struct i2c_adapter *adap) +{ + u32 parent_func = i2c_get_functionality(i2c_hotplug_parent(adap)); + + return parent_func & ~I2C_FUNC_SLAVE; +} + +static const struct i2c_algorithm i2c_hotplug_algo_i2c = { + .master_xfer = i2c_hotplug_master_xfer, + .functionality = i2c_hotplug_functionality, +}; + +static const struct i2c_algorithm i2c_hotplug_algo_smbus = { + .smbus_xfer = i2c_hotplug_smbus_xfer, + .functionality = i2c_hotplug_functionality, +}; + +static const struct i2c_algorithm i2c_hotplug_algo_both = { + .master_xfer = i2c_hotplug_master_xfer, + .smbus_xfer = i2c_hotplug_smbus_xfer, + .functionality = i2c_hotplug_functionality, +}; + +static const struct i2c_algorithm *const i2c_hotplug_algo[2][2] = { + /* non-I2C */ + { NULL, &i2c_hotplug_algo_smbus }, + /* I2C */ + { &i2c_hotplug_algo_i2c, &i2c_hotplug_algo_both } +}; + +static void i2c_hotplug_lock_bus(struct i2c_adapter *adap, unsigned int flags) +{ + i2c_lock_bus(i2c_hotplug_parent(adap), flags); +} + +static int i2c_hotplug_trylock_bus(struct i2c_adapter *adap, + unsigned int flags) +{ + return i2c_trylock_bus(i2c_hotplug_parent(adap), flags); +} + +static void i2c_hotplug_unlock_bus(struct i2c_adapter *adap, + unsigned int flags) +{ + i2c_unlock_bus(i2c_hotplug_parent(adap), flags); +} + +static const struct i2c_lock_operations i2c_hotplug_lock_ops = { + .lock_bus = i2c_hotplug_lock_bus, + .trylock_bus = i2c_hotplug_trylock_bus, + .unlock_bus = i2c_hotplug_unlock_bus, +}; + +static int i2c_hotplug_recover_bus(struct i2c_adapter *adap) +{ + return i2c_recover_bus(i2c_hotplug_parent(adap)); +} + +static struct i2c_bus_recovery_info i2c_hotplug_recovery_info = { + .recover_bus = i2c_hotplug_recover_bus, +}; + +static int i2c_hotplug_activate(struct i2c_hotplug_priv *priv) +{ + int ret; + + if (priv->adap.algo_data) + return 0; + + /* + * Store the dev data in adapter dev, since + * previous i2c_del_adapter might have wiped it. + */ + priv->adap.dev.parent = priv->dev; + priv->adap.dev.of_node = priv->dev->of_node; + + dev_dbg(priv->adap.dev.parent, "connection detected"); + + ret = i2c_add_adapter(&priv->adap); + if (!ret) + priv->adap.algo_data = (void *)1; + + return ret; +} + +static void i2c_hotplug_deactivate(struct i2c_hotplug_priv *priv) +{ + if (!priv->adap.algo_data) + return; + + dev_dbg(priv->adap.dev.parent, "disconnection detected"); + + i2c_del_adapter(&priv->adap); + priv->adap.algo_data = NULL; +} + +static irqreturn_t i2c_hotplug_interrupt(int irq, void *dev_id) +{ + struct i2c_hotplug_priv *priv = dev_id; + + /* debounce */ + msleep(20); + + if (gpiod_get_value_cansleep(priv->gpio)) + i2c_hotplug_activate(priv); + else + i2c_hotplug_deactivate(priv); + + return IRQ_HANDLED; +} + +static void devm_i2c_put_adapter(void *adapter) +{ + i2c_put_adapter(adapter); +} + +static int i2c_hotplug_gpio_probe(struct platform_device *pdev) +{ + struct device_node *parent_np; + struct i2c_adapter *parent; + struct i2c_hotplug_priv *priv; + bool is_i2c, is_smbus; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + priv->dev = &pdev->dev; + + parent_np = of_parse_phandle(pdev->dev.of_node, "i2c-parent", 0); + if (IS_ERR(parent_np)) + return dev_err_probe(&pdev->dev, PTR_ERR(parent_np), + "cannot parse i2c-parent\n"); + + parent = of_find_i2c_adapter_by_node(parent_np); + of_node_put(parent_np); + if (IS_ERR(parent)) + return dev_err_probe(&pdev->dev, PTR_ERR(parent), + "failed to get parent I2C adapter\n"); + priv->parent = parent; + + ret = devm_add_action_or_reset(&pdev->dev, devm_i2c_put_adapter, + parent); + if (ret) + return ret; + + priv->gpio = devm_gpiod_get(&pdev->dev, "detect", GPIOD_IN); + if (IS_ERR(priv->gpio)) + return dev_err_probe(&pdev->dev, PTR_ERR(priv->gpio), + "failed to get detect GPIO\n"); + + is_i2c = parent->algo->master_xfer; + is_smbus = parent->algo->smbus_xfer; + + snprintf(priv->adap.name, sizeof(priv->adap.name), + "i2c-hotplug (master i2c-%d)", i2c_adapter_id(parent)); + priv->adap.owner = THIS_MODULE; + priv->adap.algo = i2c_hotplug_algo[is_i2c][is_smbus]; + priv->adap.algo_data = NULL; + priv->adap.lock_ops = &i2c_hotplug_lock_ops; + priv->adap.class = parent->class; + priv->adap.retries = parent->retries; + priv->adap.timeout = parent->timeout; + priv->adap.quirks = parent->quirks; + if (parent->bus_recovery_info) + priv->adap.bus_recovery_info = &i2c_hotplug_recovery_info; + + if (!priv->adap.algo) + return -EINVAL; + + priv->irq = platform_get_irq(pdev, 0); + if (priv->irq < 0) + return dev_err_probe(&pdev->dev, priv->irq, + "failed to get IRQ %d\n", priv->irq); + + ret = devm_request_threaded_irq(&pdev->dev, priv->irq, NULL, + i2c_hotplug_interrupt, + IRQF_ONESHOT | IRQF_SHARED, + "i2c-hotplug", priv); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "failed to register IRQ %d\n", priv->irq); + + irq_wake_thread(priv->irq, priv); + + return 0; +} + +static int i2c_hotplug_gpio_remove(struct platform_device *pdev) +{ + struct i2c_hotplug_priv *priv = platform_get_drvdata(pdev); + + i2c_hotplug_deactivate(priv); + + return 0; +} + +static const struct of_device_id i2c_hotplug_gpio_of_match[] = { + { .compatible = "i2c-hotplug-gpio" }, + {}, +}; +MODULE_DEVICE_TABLE(of, i2c_hotplug_gpio_of_match); + +static struct platform_driver i2c_hotplug_gpio_driver = { + .probe = i2c_hotplug_gpio_probe, + .remove = i2c_hotplug_gpio_remove, + .driver = { + .name = "i2c-hotplug-gpio", + .of_match_table = i2c_hotplug_gpio_of_match, + }, +}; + +module_platform_driver(i2c_hotplug_gpio_driver); + +MODULE_DESCRIPTION("Hot-plugged I2C bus detected by GPIO"); +MODULE_AUTHOR("Michał Mirosław <mirq-linux@rere.qmqm.pl>"); +MODULE_LICENSE("GPL"); -- 2.39.2 ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2023-06-19 15:17 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-06-19 14:36 [PATCH v1 0/2] GPIO-based hotplug i2c bus Svyatoslav Ryhel 2023-06-19 14:36 ` [PATCH v1 1/2] dt-bindings: i2c: add binding for i2c-hotplug-gpio Svyatoslav Ryhel 2023-06-19 14:45 ` Krzysztof Kozlowski 2023-06-19 14:59 ` Svyatoslav Ryhel 2023-06-19 15:17 ` Rob Herring 2023-06-19 14:36 ` [PATCH v1 2/2] i2c: Add GPIO-based hotplug gate Svyatoslav Ryhel
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox