* [PATCHv5 0/2] ARM: I2C: Add device tree bindings to i2c-mux-gpio @ 2012-10-22 12:53 Maxime Ripard [not found] ` <1350910413-23925-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 0 siblings, 1 reply; 14+ messages in thread From: Maxime Ripard @ 2012-10-22 12:53 UTC (permalink / raw) To: peter.korsgaard-ob4gmnvZ1/cAvxtiuMwx3w, shawn.guo-QSEj5FYQhm4dnm+yROfE0A, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, brian-ZKiFAVwZFM2FeswfMrDH8w Hi everyone, This patchset adds the device tree entry to the CFA-10049 board of its i2c muxer. This muxer controls sub-buses that contains three Nuvoton NAU7802 ADCs and a NXP PCA955 GPIO expander. Support for these will be added eventually. Thanks, Maxime Changes from v4: - Fixed a wrong sentence in the bindings documentation, stating a false behavoiour Maxime Ripard (2): i2c: mux: Add dt support to i2c-mux-gpio driver ARM: dts: cfa10049: Add the i2c muxer buses to the CFA-10049 .../devicetree/bindings/i2c/i2c-mux-gpio.txt | 81 ++++++++++ arch/arm/boot/dts/imx28-cfa10049.dts | 24 +++ drivers/i2c/muxes/i2c-mux-gpio.c | 169 +++++++++++++++----- 3 files changed, 235 insertions(+), 39 deletions(-) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt -- 1.7.9.5 ^ permalink raw reply [flat|nested] 14+ messages in thread
[parent not found: <1350910413-23925-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>]
* [PATCH 1/2] i2c: mux: Add dt support to i2c-mux-gpio driver [not found] ` <1350910413-23925-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> @ 2012-10-22 12:53 ` Maxime Ripard [not found] ` <1350910413-23925-2-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 2012-10-22 12:53 ` [PATCH 2/2] ARM: dts: cfa10049: Add the i2c muxer buses to the CFA-10049 Maxime Ripard 1 sibling, 1 reply; 14+ messages in thread From: Maxime Ripard @ 2012-10-22 12:53 UTC (permalink / raw) To: peter.korsgaard-ob4gmnvZ1/cAvxtiuMwx3w, shawn.guo-QSEj5FYQhm4dnm+yROfE0A, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, brian-ZKiFAVwZFM2FeswfMrDH8w Allow the i2c-mux-gpio to be used by a device tree enabled device. The bindings are inspired by the one found in the i2c-mux-pinctrl driver. Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> --- .../devicetree/bindings/i2c/i2c-mux-gpio.txt | 81 ++++++++++ drivers/i2c/muxes/i2c-mux-gpio.c | 169 +++++++++++++++----- 2 files changed, 211 insertions(+), 39 deletions(-) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt new file mode 100644 index 0000000..335fc4e --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt @@ -0,0 +1,81 @@ +GPIO-based I2C Bus Mux + +This binding describes an I2C bus multiplexer that uses GPIOs to +route the I2C signals. + + +-----+ +-----+ + | dev | | dev | + +------------+ +-----+ +-----+ + | SoC | | | + | | /--------+--------+ + | +------+ | +------+ child bus A, on GPIO value set to 0 + | | I2C |-|--| Mux | + | +------+ | +--+---+ child bus B, on GPIO value set to 1 + | | | \----------+--------+--------+ + | +------+ | | | | | + | | GPIO |-|-----+ +-----+ +-----+ +-----+ + | +------+ | | dev | | dev | | dev | + +------------+ +-----+ +-----+ +-----+ + +Required properties: +- compatible: i2c-mux-gpio +- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side + port is connected to. +- mux-gpios: list of gpios to use to control the muxer +* Standard I2C mux properties. See mux.txt in this directory. +* I2C child bus nodes. See mux.txt in this directory. + +Optional properties: +- idle-state: value to set to the muxer when idle. When no value is + given, it defaults to the last value used. + +For each i2c child node, an I2C child bus will be created. They will +be numbered based on the reg property of each node. + +Whenever an access is made to a device on a child bus, the value set +in the revelant node's reg property will be output using the list of +GPIOs, the first in the list holding the most-significant value. + +If an idle state is defined, using the idle-state (optional) property, +whenever an access is not being made to a device on a child bus, the +idle value will be programmed into the GPIOs. + +If an idle state is not defined, the most recently used value will be +left programmed into hardware whenever no access is being made of a +device on a child bus. + +Example: + i2cmux { + compatible = "i2c-mux-gpio"; + #address-cells = <1>; + #size-cells = <0>; + mux-gpios = <&gpio1 22 0 &gpio1 23 0>; + i2c-parent = <&i2c1>; + + i2c@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + ssd1307: oled@3c { + compatible = "solomon,ssd1307fb-i2c"; + reg = <0x3c>; + pwms = <&pwm 4 3000>; + reset-gpios = <&gpio2 7 1>; + reset-active-low; + }; + }; + + i2c@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + + pca9555: pca9555@20 { + compatible = "nxp,pca9555"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x20>; + }; + }; + }; diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 566a675..7ebef01 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -16,11 +16,13 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/gpio.h> +#include <linux/of_i2c.h> +#include <linux/of_gpio.h> struct gpiomux { struct i2c_adapter *parent; struct i2c_adapter **adap; /* child busses */ - struct i2c_mux_gpio_platform_data data; + struct i2c_mux_gpio_platform_data *data; unsigned gpio_base; }; @@ -28,8 +30,8 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val) { int i; - for (i = 0; i < mux->data.n_gpios; i++) - gpio_set_value(mux->gpio_base + mux->data.gpios[i], + for (i = 0; i < mux->data->n_gpios; i++) + gpio_set_value(mux->gpio_base + mux->data->gpios[i], val & (1 << i)); } @@ -37,7 +39,7 @@ static int i2c_mux_gpio_select(struct i2c_adapter *adap, void *data, u32 chan) { struct gpiomux *mux = data; - i2c_mux_gpio_set(mux, mux->data.values[chan]); + i2c_mux_gpio_set(mux, mux->data->values[chan]); return 0; } @@ -46,7 +48,7 @@ static int i2c_mux_gpio_deselect(struct i2c_adapter *adap, void *data, u32 chan) { struct gpiomux *mux = data; - i2c_mux_gpio_set(mux, mux->data.idle); + i2c_mux_gpio_set(mux, mux->data->idle); return 0; } @@ -57,29 +59,118 @@ static int __devinit match_gpio_chip_by_label(struct gpio_chip *chip, return !strcmp(chip->label, data); } +#ifdef CONFIG_OF +static int __devinit i2c_mux_gpio_probe_dt(struct gpiomux *mux, + struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *adapter_np, *child; + struct i2c_adapter *adapter; + unsigned *values, *gpios; + int i = 0; + + if (!np) + return 0; + + mux->data = devm_kzalloc(&pdev->dev, sizeof(*mux->data), + GFP_KERNEL); + if (!mux->data) { + dev_err(&pdev->dev, "Cannot allocate platform_data"); + return -ENOMEM; + } + + adapter_np = of_parse_phandle(np, "i2c-parent", 0); + if (!adapter_np) { + dev_err(&pdev->dev, "Cannot parse i2c-parent\n"); + return -ENODEV; + } + adapter = of_find_i2c_adapter_by_node(adapter_np); + if (!adapter) { + dev_err(&pdev->dev, "Cannot find parent bus\n"); + return -ENODEV; + } + mux->data->parent = i2c_adapter_id(adapter); + put_device(&adapter->dev); + + mux->data->n_values = of_get_child_count(np); + + values = devm_kzalloc(&pdev->dev, + sizeof(*mux->data->values) * mux->data->n_values, + GFP_KERNEL); + if (!values) { + dev_err(&pdev->dev, "Cannot allocate values array"); + return -ENOMEM; + } + + for_each_child_of_node(np, child) { + of_property_read_u32(child, "reg", values + i); + i++; + } + mux->data->values = values; + + if (of_property_read_u32(np, "idle-state", &mux->data->idle)) + mux->data->idle = I2C_MUX_GPIO_NO_IDLE; + + mux->data->n_gpios = of_gpio_named_count(np, "mux-gpios"); + if (mux->data->n_gpios < 0) { + dev_err(&pdev->dev, "Missing mux-gpios property in the DT.\n"); + return -EINVAL; + } + + gpios = devm_kzalloc(&pdev->dev, + sizeof(*mux->data->gpios) * mux->data->n_gpios, + GFP_KERNEL); + if (!gpios) { + dev_err(&pdev->dev, "Cannot allocate gpios array"); + return -ENOMEM; + } + + for (i = 0; i < mux->data->n_gpios; i++) + gpios[i] = of_get_named_gpio(np, "mux-gpios", i); + + mux->data->gpios = gpios; + + return 0; +} +#else +static int __devinit i2c_mux_gpio_probe_dt(struct gpiomux *mux, + struct platform_device *pdev) +{ + return 0; +} +#endif + static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) { struct gpiomux *mux; - struct i2c_mux_gpio_platform_data *pdata; struct i2c_adapter *parent; int (*deselect) (struct i2c_adapter *, void *, u32); unsigned initial_state, gpio_base; int i, ret; - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "Missing platform data\n"); - return -ENODEV; + mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); + if (!mux) { + dev_err(&pdev->dev, "Cannot allocate gpiomux structure"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, mux); + + mux->data = pdev->dev.platform_data; + if (!mux->data) { + ret = i2c_mux_gpio_probe_dt(mux, pdev); + if (ret < 0) + return ret; } /* * If a GPIO chip name is provided, the GPIO pin numbers provided are * relative to its base GPIO number. Otherwise they are absolute. */ - if (pdata->gpio_chip) { + if (mux->data->gpio_chip) { struct gpio_chip *gpio; - gpio = gpiochip_find(pdata->gpio_chip, + gpio = gpiochip_find(mux->data->gpio_chip, match_gpio_chip_by_label); if (!gpio) return -EPROBE_DEFER; @@ -89,49 +180,44 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) gpio_base = 0; } - parent = i2c_get_adapter(pdata->parent); + parent = i2c_get_adapter(mux->data->parent); if (!parent) { dev_err(&pdev->dev, "Parent adapter (%d) not found\n", - pdata->parent); + mux->data->parent); return -ENODEV; } - mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); - if (!mux) { - ret = -ENOMEM; - goto alloc_failed; - } - mux->parent = parent; - mux->data = *pdata; mux->gpio_base = gpio_base; + mux->adap = devm_kzalloc(&pdev->dev, - sizeof(*mux->adap) * pdata->n_values, + sizeof(*mux->adap) * mux->data->n_values, GFP_KERNEL); if (!mux->adap) { + dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure"); ret = -ENOMEM; goto alloc_failed; } - if (pdata->idle != I2C_MUX_GPIO_NO_IDLE) { - initial_state = pdata->idle; + if (mux->data->idle != I2C_MUX_GPIO_NO_IDLE) { + initial_state = mux->data->idle; deselect = i2c_mux_gpio_deselect; } else { - initial_state = pdata->values[0]; + initial_state = mux->data->values[0]; deselect = NULL; } - for (i = 0; i < pdata->n_gpios; i++) { - ret = gpio_request(gpio_base + pdata->gpios[i], "i2c-mux-gpio"); + for (i = 0; i < mux->data->n_gpios; i++) { + ret = gpio_request(gpio_base + mux->data->gpios[i], "i2c-mux-gpio"); if (ret) goto err_request_gpio; - gpio_direction_output(gpio_base + pdata->gpios[i], + gpio_direction_output(gpio_base + mux->data->gpios[i], initial_state & (1 << i)); } - for (i = 0; i < pdata->n_values; i++) { - u32 nr = pdata->base_nr ? (pdata->base_nr + i) : 0; - unsigned int class = pdata->classes ? pdata->classes[i] : 0; + for (i = 0; i < mux->data->n_values; i++) { + u32 nr = mux->data->base_nr ? (mux->data->base_nr + i) : 0; + unsigned int class = mux->data->classes ? mux->data->classes[i] : 0; mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr, i, class, @@ -144,19 +230,17 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) } dev_info(&pdev->dev, "%d port mux on %s adapter\n", - pdata->n_values, parent->name); - - platform_set_drvdata(pdev, mux); + mux->data->n_values, parent->name); return 0; add_adapter_failed: for (; i > 0; i--) i2c_del_mux_adapter(mux->adap[i - 1]); - i = pdata->n_gpios; + i = mux->data->n_gpios; err_request_gpio: for (; i > 0; i--) - gpio_free(gpio_base + pdata->gpios[i - 1]); + gpio_free(gpio_base + mux->data->gpios[i - 1]); alloc_failed: i2c_put_adapter(parent); @@ -168,11 +252,11 @@ static int __devexit i2c_mux_gpio_remove(struct platform_device *pdev) struct gpiomux *mux = platform_get_drvdata(pdev); int i; - for (i = 0; i < mux->data.n_values; i++) + for (i = 0; i < mux->data->n_values; i++) i2c_del_mux_adapter(mux->adap[i]); - for (i = 0; i < mux->data.n_gpios; i++) - gpio_free(mux->gpio_base + mux->data.gpios[i]); + for (i = 0; i < mux->data->n_gpios; i++) + gpio_free(mux->gpio_base + mux->data->gpios[i]); platform_set_drvdata(pdev, NULL); i2c_put_adapter(mux->parent); @@ -180,12 +264,19 @@ static int __devexit i2c_mux_gpio_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id i2c_mux_gpio_of_match[] __devinitconst = { + { .compatible = "i2c-mux-gpio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, i2c_mux_gpio_of_match); + static struct platform_driver i2c_mux_gpio_driver = { .probe = i2c_mux_gpio_probe, .remove = __devexit_p(i2c_mux_gpio_remove), .driver = { .owner = THIS_MODULE, .name = "i2c-mux-gpio", + .of_match_table = of_match_ptr(i2c_mux_gpio_of_match), }, }; -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 14+ messages in thread
[parent not found: <1350910413-23925-2-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>]
* Re: [PATCH 1/2] i2c: mux: Add dt support to i2c-mux-gpio driver [not found] ` <1350910413-23925-2-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> @ 2012-10-22 20:16 ` Stephen Warren 2012-10-23 19:51 ` Peter Korsgaard 1 sibling, 0 replies; 14+ messages in thread From: Stephen Warren @ 2012-10-22 20:16 UTC (permalink / raw) To: Maxime Ripard Cc: peter.korsgaard-ob4gmnvZ1/cAvxtiuMwx3w, shawn.guo-QSEj5FYQhm4dnm+yROfE0A, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ, brian-ZKiFAVwZFM2FeswfMrDH8w, linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r On 10/22/2012 06:53 AM, Maxime Ripard wrote: > Allow the i2c-mux-gpio to be used by a device tree enabled device. The > bindings are inspired by the one found in the i2c-mux-pinctrl driver. Reviewed-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org> ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] i2c: mux: Add dt support to i2c-mux-gpio driver [not found] ` <1350910413-23925-2-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 2012-10-22 20:16 ` Stephen Warren @ 2012-10-23 19:51 ` Peter Korsgaard [not found] ` <87liexrmoz.fsf-1Ae4nN3xCbAluPl5bxqUMw@public.gmane.org> 1 sibling, 1 reply; 14+ messages in thread From: Peter Korsgaard @ 2012-10-23 19:51 UTC (permalink / raw) To: Maxime Ripard Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ, linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, brian-ZKiFAVwZFM2FeswfMrDH8w >>>>> "MR" == Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> writes: Hi Maxime, I'm fine with the idea, but a few comments: MR> Allow the i2c-mux-gpio to be used by a device tree enabled device. The MR> bindings are inspired by the one found in the i2c-mux-pinctrl driver. MR> Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> MR> --- MR> .../devicetree/bindings/i2c/i2c-mux-gpio.txt | 81 ++++++++++ MR> drivers/i2c/muxes/i2c-mux-gpio.c | 169 +++++++++++++++----- MR> 2 files changed, 211 insertions(+), 39 deletions(-) MR> create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt MR> diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt MR> new file mode 100644 MR> index 0000000..335fc4e MR> --- /dev/null MR> +++ b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt MR> @@ -0,0 +1,81 @@ MR> +GPIO-based I2C Bus Mux MR> + MR> +This binding describes an I2C bus multiplexer that uses GPIOs to MR> +route the I2C signals. MR> + MR> + +-----+ +-----+ MR> + | dev | | dev | MR> + +------------+ +-----+ +-----+ MR> + | SoC | | | MR> + | | /--------+--------+ MR> + | +------+ | +------+ child bus A, on GPIO value set to 0 MR> + | | I2C |-|--| Mux | MR> + | +------+ | +--+---+ child bus B, on GPIO value set to 1 MR> + | | | \----------+--------+--------+ MR> + | +------+ | | | | | MR> + | | GPIO |-|-----+ +-----+ +-----+ +-----+ MR> + | +------+ | | dev | | dev | | dev | MR> + +------------+ +-----+ +-----+ +-----+ MR> + MR> +Required properties: MR> +- compatible: i2c-mux-gpio MR> +- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side MR> + port is connected to. MR> +- mux-gpios: list of gpios to use to control the muxer s/to use to/used to/ MR> +* Standard I2C mux properties. See mux.txt in this directory. MR> +* I2C child bus nodes. See mux.txt in this directory. MR> + MR> +Optional properties: MR> +- idle-state: value to set to the muxer when idle. When no value is How about 'bitmask defining mux state when idle' instead? MR> + given, it defaults to the last value used. MR> + MR> +For each i2c child node, an I2C child bus will be created. They will MR> +be numbered based on the reg property of each node. As far as I can see they are dynamically assigned numbers in the order they are listed in the dt. MR> + MR> +Whenever an access is made to a device on a child bus, the value set MR> +in the revelant node's reg property will be output using the list of MR> +GPIOs, the first in the list holding the most-significant value. Isn't it the other way around, E.G. first gpio in mux-gpios controlled by LSB of reg property, next gpio by lsb+1, ..? MR> + MR> +If an idle state is defined, using the idle-state (optional) property, MR> +whenever an access is not being made to a device on a child bus, the MR> +idle value will be programmed into the GPIOs. s/idle value will be programmed into the GPIOS/GPIOS set according to the idle value bitmask/ MR> + MR> +If an idle state is not defined, the most recently used value will be MR> +left programmed into hardware whenever no access is being made of a s/of a/to a/ MR> +device on a child bus. MR> + MR> +Example: MR> + i2cmux { MR> + compatible = "i2c-mux-gpio"; MR> + #address-cells = <1>; MR> + #size-cells = <0>; MR> + mux-gpios = <&gpio1 22 0 &gpio1 23 0>; MR> + i2c-parent = <&i2c1>; MR> + MR> + i2c@1 { MR> + reg = <1>; MR> + #address-cells = <1>; MR> + #size-cells = <0>; MR> + MR> + ssd1307: oled@3c { MR> + compatible = "solomon,ssd1307fb-i2c"; MR> + reg = <0x3c>; MR> + pwms = <&pwm 4 3000>; MR> + reset-gpios = <&gpio2 7 1>; MR> + reset-active-low; MR> + }; MR> + }; MR> + MR> + i2c@3 { MR> + reg = <3>; MR> + #address-cells = <1>; MR> + #size-cells = <0>; MR> + MR> + pca9555: pca9555@20 { MR> + compatible = "nxp,pca9555"; MR> + gpio-controller; MR> + #gpio-cells = <2>; MR> + reg = <0x20>; MR> + }; MR> + }; MR> + }; MR> diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c MR> index 566a675..7ebef01 100644 MR> --- a/drivers/i2c/muxes/i2c-mux-gpio.c MR> +++ b/drivers/i2c/muxes/i2c-mux-gpio.c MR> @@ -16,11 +16,13 @@ MR> #include <linux/module.h> MR> #include <linux/slab.h> MR> #include <linux/gpio.h> MR> +#include <linux/of_i2c.h> MR> +#include <linux/of_gpio.h> MR> struct gpiomux { MR> struct i2c_adapter *parent; MR> struct i2c_adapter **adap; /* child busses */ MR> - struct i2c_mux_gpio_platform_data data; MR> + struct i2c_mux_gpio_platform_data *data; Why this change? I don't see why it is needed and the patch would be a lot easier to review without all the s/.data/->data/ noise. MR> unsigned gpio_base; MR> }; MR> @@ -28,8 +30,8 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val) MR> { MR> int i; MR> - for (i = 0; i < mux->data.n_gpios; i++) MR> - gpio_set_value(mux->gpio_base + mux->data.gpios[i], MR> + for (i = 0; i < mux->data->n_gpios; i++) MR> + gpio_set_value(mux->gpio_base + mux->data->gpios[i], MR> val & (1 << i)); MR> } MR> @@ -37,7 +39,7 @@ static int i2c_mux_gpio_select(struct i2c_adapter *adap, void *data, u32 chan) MR> { MR> struct gpiomux *mux = data; MR> - i2c_mux_gpio_set(mux, mux->data.values[chan]); MR> + i2c_mux_gpio_set(mux, mux->data->values[chan]); MR> return 0; MR> } MR> @@ -46,7 +48,7 @@ static int i2c_mux_gpio_deselect(struct i2c_adapter *adap, void *data, u32 chan) MR> { MR> struct gpiomux *mux = data; MR> - i2c_mux_gpio_set(mux, mux->data.idle); MR> + i2c_mux_gpio_set(mux, mux->data->idle); MR> return 0; MR> } MR> @@ -57,29 +59,118 @@ static int __devinit match_gpio_chip_by_label(struct gpio_chip *chip, MR> return !strcmp(chip->label, data); MR> } MR> +#ifdef CONFIG_OF MR> +static int __devinit i2c_mux_gpio_probe_dt(struct gpiomux *mux, MR> + struct platform_device *pdev) MR> +{ MR> + struct device_node *np = pdev->dev.of_node; MR> + struct device_node *adapter_np, *child; MR> + struct i2c_adapter *adapter; MR> + unsigned *values, *gpios; MR> + int i = 0; MR> + MR> + if (!np) MR> + return 0; MR> + MR> + mux->data = devm_kzalloc(&pdev->dev, sizeof(*mux->data), MR> + GFP_KERNEL); MR> + if (!mux->data) { MR> + dev_err(&pdev->dev, "Cannot allocate platform_data"); MR> + return -ENOMEM; MR> + } MR> + MR> + adapter_np = of_parse_phandle(np, "i2c-parent", 0); MR> + if (!adapter_np) { MR> + dev_err(&pdev->dev, "Cannot parse i2c-parent\n"); MR> + return -ENODEV; MR> + } MR> + adapter = of_find_i2c_adapter_by_node(adapter_np); MR> + if (!adapter) { MR> + dev_err(&pdev->dev, "Cannot find parent bus\n"); MR> + return -ENODEV; MR> + } MR> + mux->data->parent = i2c_adapter_id(adapter); MR> + put_device(&adapter->dev); MR> + MR> + mux->data->n_values = of_get_child_count(np); MR> + MR> + values = devm_kzalloc(&pdev->dev, MR> + sizeof(*mux->data->values) * mux->data->n_values, MR> + GFP_KERNEL); MR> + if (!values) { MR> + dev_err(&pdev->dev, "Cannot allocate values array"); MR> + return -ENOMEM; MR> + } MR> + MR> + for_each_child_of_node(np, child) { MR> + of_property_read_u32(child, "reg", values + i); MR> + i++; MR> + } MR> + mux->data->values = values; MR> + MR> + if (of_property_read_u32(np, "idle-state", &mux->data->idle)) MR> + mux->data->idle = I2C_MUX_GPIO_NO_IDLE; MR> + MR> + mux->data->n_gpios = of_gpio_named_count(np, "mux-gpios"); MR> + if (mux->data->n_gpios < 0) { MR> + dev_err(&pdev->dev, "Missing mux-gpios property in the DT.\n"); MR> + return -EINVAL; MR> + } MR> + MR> + gpios = devm_kzalloc(&pdev->dev, MR> + sizeof(*mux->data->gpios) * mux->data->n_gpios, MR> + GFP_KERNEL); MR> + if (!gpios) { MR> + dev_err(&pdev->dev, "Cannot allocate gpios array"); MR> + return -ENOMEM; MR> + } MR> + MR> + for (i = 0; i < mux->data->n_gpios; i++) MR> + gpios[i] = of_get_named_gpio(np, "mux-gpios", i); MR> + MR> + mux->data->gpios = gpios; MR> + MR> + return 0; MR> +} MR> +#else MR> +static int __devinit i2c_mux_gpio_probe_dt(struct gpiomux *mux, MR> + struct platform_device *pdev) MR> +{ MR> + return 0; MR> +} MR> +#endif MR> + MR> static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) MR> { MR> struct gpiomux *mux; MR> - struct i2c_mux_gpio_platform_data *pdata; MR> struct i2c_adapter *parent; MR> int (*deselect) (struct i2c_adapter *, void *, u32); MR> unsigned initial_state, gpio_base; MR> int i, ret; MR> - pdata = pdev->dev.platform_data; MR> - if (!pdata) { MR> - dev_err(&pdev->dev, "Missing platform data\n"); MR> - return -ENODEV; MR> + mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); MR> + if (!mux) { MR> + dev_err(&pdev->dev, "Cannot allocate gpiomux structure"); MR> + return -ENOMEM; MR> + } MR> + MR> + platform_set_drvdata(pdev, mux); MR> + MR> + mux->data = pdev->dev.platform_data; MR> + if (!mux->data) { MR> + ret = i2c_mux_gpio_probe_dt(mux, pdev); MR> + if (ret < 0) MR> + return ret; MR> } MR> /* MR> * If a GPIO chip name is provided, the GPIO pin numbers provided are MR> * relative to its base GPIO number. Otherwise they are absolute. MR> */ MR> - if (pdata->gpio_chip) { MR> + if (mux->data->gpio_chip) { MR> struct gpio_chip *gpio; MR> - gpio = gpiochip_find(pdata->gpio_chip, MR> + gpio = gpiochip_find(mux->data->gpio_chip, MR> match_gpio_chip_by_label); MR> if (!gpio) MR> return -EPROBE_DEFER; MR> @@ -89,49 +180,44 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) MR> gpio_base = 0; MR> } MR> - parent = i2c_get_adapter(pdata->parent); MR> + parent = i2c_get_adapter(mux->data->parent); MR> if (!parent) { MR> dev_err(&pdev->dev, "Parent adapter (%d) not found\n", MR> - pdata->parent); MR> + mux->data->parent); MR> return -ENODEV; MR> } MR> - mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); MR> - if (!mux) { MR> - ret = -ENOMEM; MR> - goto alloc_failed; MR> - } MR> - mux-> parent = parent; MR> - mux->data = *pdata; mux-> gpio_base = gpio_base; MR> + mux-> adap = devm_kzalloc(&pdev->dev, MR> - sizeof(*mux->adap) * pdata->n_values, MR> + sizeof(*mux->adap) * mux->data->n_values, MR> GFP_KERNEL); MR> if (!mux->adap) { MR> + dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure"); MR> ret = -ENOMEM; MR> goto alloc_failed; MR> } MR> - if (pdata->idle != I2C_MUX_GPIO_NO_IDLE) { MR> - initial_state = pdata->idle; MR> + if (mux->data->idle != I2C_MUX_GPIO_NO_IDLE) { MR> + initial_state = mux->data->idle; MR> deselect = i2c_mux_gpio_deselect; MR> } else { MR> - initial_state = pdata->values[0]; MR> + initial_state = mux->data->values[0]; MR> deselect = NULL; MR> } MR> - for (i = 0; i < pdata->n_gpios; i++) { MR> - ret = gpio_request(gpio_base + pdata->gpios[i], "i2c-mux-gpio"); MR> + for (i = 0; i < mux->data->n_gpios; i++) { MR> + ret = gpio_request(gpio_base + mux->data->gpios[i], "i2c-mux-gpio"); MR> if (ret) MR> goto err_request_gpio; MR> - gpio_direction_output(gpio_base + pdata->gpios[i], MR> + gpio_direction_output(gpio_base + mux->data->gpios[i], MR> initial_state & (1 << i)); MR> } MR> - for (i = 0; i < pdata->n_values; i++) { MR> - u32 nr = pdata->base_nr ? (pdata->base_nr + i) : 0; MR> - unsigned int class = pdata->classes ? pdata->classes[i] : 0; MR> + for (i = 0; i < mux->data->n_values; i++) { MR> + u32 nr = mux->data->base_nr ? (mux->data->base_nr + i) : 0; MR> + unsigned int class = mux->data->classes ? mux->data->classes[i] : 0; mux-> adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr, MR> i, class, MR> @@ -144,19 +230,17 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) MR> } MR> dev_info(&pdev->dev, "%d port mux on %s adapter\n", MR> - pdata->n_values, parent->name); MR> - MR> - platform_set_drvdata(pdev, mux); MR> + mux->data->n_values, parent->name); MR> return 0; MR> add_adapter_failed: MR> for (; i > 0; i--) MR> i2c_del_mux_adapter(mux->adap[i - 1]); MR> - i = pdata->n_gpios; MR> + i = mux->data->n_gpios; MR> err_request_gpio: MR> for (; i > 0; i--) MR> - gpio_free(gpio_base + pdata->gpios[i - 1]); MR> + gpio_free(gpio_base + mux->data->gpios[i - 1]); MR> alloc_failed: MR> i2c_put_adapter(parent); MR> @@ -168,11 +252,11 @@ static int __devexit i2c_mux_gpio_remove(struct platform_device *pdev) MR> struct gpiomux *mux = platform_get_drvdata(pdev); MR> int i; MR> - for (i = 0; i < mux->data.n_values; i++) MR> + for (i = 0; i < mux->data->n_values; i++) MR> i2c_del_mux_adapter(mux->adap[i]); MR> - for (i = 0; i < mux->data.n_gpios; i++) MR> - gpio_free(mux->gpio_base + mux->data.gpios[i]); MR> + for (i = 0; i < mux->data->n_gpios; i++) MR> + gpio_free(mux->gpio_base + mux->data->gpios[i]); MR> platform_set_drvdata(pdev, NULL); MR> i2c_put_adapter(mux->parent); MR> @@ -180,12 +264,19 @@ static int __devexit i2c_mux_gpio_remove(struct platform_device *pdev) MR> return 0; MR> } MR> +static const struct of_device_id i2c_mux_gpio_of_match[] __devinitconst = { MR> + { .compatible = "i2c-mux-gpio", }, MR> + {}, MR> +}; MR> +MODULE_DEVICE_TABLE(of, i2c_mux_gpio_of_match); MR> + MR> static struct platform_driver i2c_mux_gpio_driver = { MR> .probe = i2c_mux_gpio_probe, MR> .remove = __devexit_p(i2c_mux_gpio_remove), MR> .driver = { MR> .owner = THIS_MODULE, MR> .name = "i2c-mux-gpio", MR> + .of_match_table = of_match_ptr(i2c_mux_gpio_of_match), MR> }, MR> }; MR> -- MR> 1.7.9.5 -- Sorry about disclaimer - It's out of my control. Bye, Peter Korsgaard DISCLAIMER: Unless indicated otherwise, the information contained in this message is privileged and confidential, and is intended only for the use of the addressee(s) named above and others who have been specifically authorized to receive it. If you are not the intended recipient, you are hereby notified that any dissemination, distribution or copying of this message and/or attachments is strictly prohibited. The company accepts no liability for any damage caused by any virus transmitted by this email. Furthermore, the company does not warrant a proper and complete transmission of this information, nor does it accept liability for any delays. If you have received this message in error, please contact the sender and delete the message. Thank you. ^ permalink raw reply [flat|nested] 14+ messages in thread
[parent not found: <87liexrmoz.fsf-1Ae4nN3xCbAluPl5bxqUMw@public.gmane.org>]
* Re: [PATCH 1/2] i2c: mux: Add dt support to i2c-mux-gpio driver [not found] ` <87liexrmoz.fsf-1Ae4nN3xCbAluPl5bxqUMw@public.gmane.org> @ 2012-10-24 8:37 ` Maxime Ripard [not found] ` <5087A8E5.8050103-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 0 siblings, 1 reply; 14+ messages in thread From: Maxime Ripard @ 2012-10-24 8:37 UTC (permalink / raw) To: Peter Korsgaard Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ, linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, brian-ZKiFAVwZFM2FeswfMrDH8w Hi Peter, Le 23/10/2012 21:51, Peter Korsgaard a écrit : >>>>>> "MR" == Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> writes: > > Hi Maxime, > > I'm fine with the idea, but a few comments: > > > MR> Allow the i2c-mux-gpio to be used by a device tree enabled device. The > MR> bindings are inspired by the one found in the i2c-mux-pinctrl driver. > > MR> Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> > MR> --- > MR> .../devicetree/bindings/i2c/i2c-mux-gpio.txt | 81 ++++++++++ > MR> drivers/i2c/muxes/i2c-mux-gpio.c | 169 +++++++++++++++----- > MR> 2 files changed, 211 insertions(+), 39 deletions(-) > MR> create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt > > MR> diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt > MR> new file mode 100644 > MR> index 0000000..335fc4e > MR> --- /dev/null > MR> +++ b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt > MR> @@ -0,0 +1,81 @@ > MR> +GPIO-based I2C Bus Mux > MR> + > MR> +This binding describes an I2C bus multiplexer that uses GPIOs to > MR> +route the I2C signals. > MR> + > MR> + +-----+ +-----+ > MR> + | dev | | dev | > MR> + +------------+ +-----+ +-----+ > MR> + | SoC | | | > MR> + | | /--------+--------+ > MR> + | +------+ | +------+ child bus A, on GPIO value set to 0 > MR> + | | I2C |-|--| Mux | > MR> + | +------+ | +--+---+ child bus B, on GPIO value set to 1 > MR> + | | | \----------+--------+--------+ > MR> + | +------+ | | | | | > MR> + | | GPIO |-|-----+ +-----+ +-----+ +-----+ > MR> + | +------+ | | dev | | dev | | dev | > MR> + +------------+ +-----+ +-----+ +-----+ > MR> + > MR> +Required properties: > MR> +- compatible: i2c-mux-gpio > MR> +- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side > MR> + port is connected to. > MR> +- mux-gpios: list of gpios to use to control the muxer > > s/to use to/used to/ > > > MR> +* Standard I2C mux properties. See mux.txt in this directory. > MR> +* I2C child bus nodes. See mux.txt in this directory. > MR> + > MR> +Optional properties: > MR> +- idle-state: value to set to the muxer when idle. When no value is > > How about 'bitmask defining mux state when idle' instead? Since the array documented as using the bitmasks in the platform_data and described as an array of bitmasks is called "values", and the file mux.txt talks about "numbers" to put into reg, won't this be confusing to have three names for the exact same thing? > MR> + given, it defaults to the last value used. > MR> + > MR> +For each i2c child node, an I2C child bus will be created. They will > MR> +be numbered based on the reg property of each node. > > As far as I can see they are dynamically assigned numbers in the order > they are listed in the dt. Ah, yes. > MR> + > MR> +Whenever an access is made to a device on a child bus, the value set > MR> +in the revelant node's reg property will be output using the list of > MR> +GPIOs, the first in the list holding the most-significant value. > > Isn't it the other way around, E.G. first gpio in mux-gpios controlled > by LSB of reg property, next gpio by lsb+1, ..? True indeed. > MR> + > MR> +If an idle state is defined, using the idle-state (optional) property, > MR> +whenever an access is not being made to a device on a child bus, the > MR> +idle value will be programmed into the GPIOs. > > s/idle value will be programmed into the GPIOS/GPIOS set according to > the idle value bitmask/ Once again, I'm really not fond of the term "bitmask". [..] > MR> diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c > MR> index 566a675..7ebef01 100644 > MR> --- a/drivers/i2c/muxes/i2c-mux-gpio.c > MR> +++ b/drivers/i2c/muxes/i2c-mux-gpio.c > MR> @@ -16,11 +16,13 @@ > MR> #include <linux/module.h> > MR> #include <linux/slab.h> > MR> #include <linux/gpio.h> > MR> +#include <linux/of_i2c.h> > MR> +#include <linux/of_gpio.h> > > MR> struct gpiomux { > MR> struct i2c_adapter *parent; > MR> struct i2c_adapter **adap; /* child busses */ > MR> - struct i2c_mux_gpio_platform_data data; > MR> + struct i2c_mux_gpio_platform_data *data; > > > Why this change? I don't see why it is needed and the patch would be a > lot easier to review without all the s/.data/->data/ noise. Ah yes, since mux is already allocated using kcalloc, we don't need to do it for data as well. I will remove it. Thanks, Maxime -- Maxime Ripard, Free Electrons Kernel, drivers, real-time and embedded Linux development, consulting, training and support. http://free-electrons.com ^ permalink raw reply [flat|nested] 14+ messages in thread
[parent not found: <5087A8E5.8050103-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>]
* Re: [PATCH 1/2] i2c: mux: Add dt support to i2c-mux-gpio driver [not found] ` <5087A8E5.8050103-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> @ 2012-10-24 11:45 ` Peter Korsgaard 0 siblings, 0 replies; 14+ messages in thread From: Peter Korsgaard @ 2012-10-24 11:45 UTC (permalink / raw) To: Maxime Ripard Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ, linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, brian-ZKiFAVwZFM2FeswfMrDH8w >>>>> "MR" == Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> writes: Hi, MR> +* Standard I2C mux properties. See mux.txt in this directory. MR> +* I2C child bus nodes. See mux.txt in this directory. MR> + MR> +Optional properties: MR> +- idle-state: value to set to the muxer when idle. When no value is >> >> How about 'bitmask defining mux state when idle' instead? MR> Since the array documented as using the bitmasks in the platform_data MR> and described as an array of bitmasks is called "values", and the file MR> mux.txt talks about "numbers" to put into reg, won't this be confusing MR> to have three names for the exact same thing? Yeah, the mess is less than perfect. To my defense I did use bitmask in the platform data documentation: @values: Array of bitmasks of GPIO settings (low/high) for each position @idle: Bitmask to write to MUX when idle or GPIO_I2CMUX_NO_IDLE if not used But ok, I don't feel strongly about it. >> Why this change? I don't see why it is needed and the patch would be a >> lot easier to review without all the s/.data/->data/ noise. MR> Ah yes, since mux is already allocated using kcalloc, we don't need to MR> do it for data as well. I will remove it. Ok, great. -- Sorry about disclaimer - It's out of my control. Bye, Peter Korsgaard DISCLAIMER: Unless indicated otherwise, the information contained in this message is privileged and confidential, and is intended only for the use of the addressee(s) named above and others who have been specifically authorized to receive it. If you are not the intended recipient, you are hereby notified that any dissemination, distribution or copying of this message and/or attachments is strictly prohibited. The company accepts no liability for any damage caused by any virus transmitted by this email. Furthermore, the company does not warrant a proper and complete transmission of this information, nor does it accept liability for any delays. If you have received this message in error, please contact the sender and delete the message. Thank you. ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 2/2] ARM: dts: cfa10049: Add the i2c muxer buses to the CFA-10049 [not found] ` <1350910413-23925-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 2012-10-22 12:53 ` [PATCH 1/2] i2c: mux: Add dt support to i2c-mux-gpio driver Maxime Ripard @ 2012-10-22 12:53 ` Maxime Ripard 1 sibling, 0 replies; 14+ messages in thread From: Maxime Ripard @ 2012-10-22 12:53 UTC (permalink / raw) To: peter.korsgaard-ob4gmnvZ1/cAvxtiuMwx3w, shawn.guo-QSEj5FYQhm4dnm+yROfE0A, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, brian-ZKiFAVwZFM2FeswfMrDH8w This will allow to add the 3 Nuvoton NAU7802 ADCs and the NXP PCA9555 GPIO expander eventually. Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> --- arch/arm/boot/dts/imx28-cfa10049.dts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm/boot/dts/imx28-cfa10049.dts b/arch/arm/boot/dts/imx28-cfa10049.dts index 97ee098..2cda823 100644 --- a/arch/arm/boot/dts/imx28-cfa10049.dts +++ b/arch/arm/boot/dts/imx28-cfa10049.dts @@ -76,6 +76,30 @@ status = "okay"; }; + i2cmux { + compatible = "i2c-mux-gpio"; + #address-cells = <1>; + #size-cells = <0>; + mux-gpios = <&gpio1 22 0 &gpio1 23 0>; + i2c-parent = <&i2c1>; + + i2c@0 { + reg = <0>; + }; + + i2c@1 { + reg = <1>; + }; + + i2c@2 { + reg = <2>; + }; + + i2c@3 { + reg = <3>; + }; + }; + usbphy1: usbphy@8007e000 { status = "okay"; }; -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCHv7 0/2] ARM: I2C: Add device tree bindings to i2c-mux-gpio @ 2012-10-25 16:23 Maxime Ripard [not found] ` <1351182234-22971-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 0 siblings, 1 reply; 14+ messages in thread From: Maxime Ripard @ 2012-10-25 16:23 UTC (permalink / raw) To: peter.korsgaard-ob4gmnvZ1/cAvxtiuMwx3w, shawn.guo-QSEj5FYQhm4dnm+yROfE0A, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, brian-ZKiFAVwZFM2FeswfMrDH8w Hi everyone, This patchset adds the device tree entry to the CFA-10049 board of its i2c muxer. This muxer controls sub-buses that contains three Nuvoton NAU7802 ADCs and a NXP PCA955 GPIO expander. Support for these will be added eventually. Thanks, Maxime Changes from v6: - Changed the return value when neither platform data nor dt was available - Fix a sentence in the documentation Maxime Ripard (2): i2c: mux: Add dt support to i2c-mux-gpio driver ARM: dts: cfa10049: Add the i2c muxer buses to the CFA-10049 .../devicetree/bindings/i2c/i2c-mux-gpio.txt | 81 +++++++++++ arch/arm/boot/dts/imx28-cfa10049.dts | 24 ++++ drivers/i2c/muxes/i2c-mux-gpio.c | 146 +++++++++++++++----- 3 files changed, 220 insertions(+), 31 deletions(-) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt -- 1.7.9.5 ^ permalink raw reply [flat|nested] 14+ messages in thread
[parent not found: <1351182234-22971-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>]
* [PATCH 1/2] i2c: mux: Add dt support to i2c-mux-gpio driver [not found] ` <1351182234-22971-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> @ 2012-10-25 16:23 ` Maxime Ripard [not found] ` <1351182234-22971-2-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 0 siblings, 1 reply; 14+ messages in thread From: Maxime Ripard @ 2012-10-25 16:23 UTC (permalink / raw) To: peter.korsgaard-ob4gmnvZ1/cAvxtiuMwx3w, shawn.guo-QSEj5FYQhm4dnm+yROfE0A, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, brian-ZKiFAVwZFM2FeswfMrDH8w Allow the i2c-mux-gpio to be used by a device tree enabled device. The bindings are inspired by the one found in the i2c-mux-pinctrl driver. Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> Reviewed-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org> Acked-by: Peter Korsgaard <peter.korsgaard-ob4gmnvZ1/cAvxtiuMwx3w@public.gmane.org> --- .../devicetree/bindings/i2c/i2c-mux-gpio.txt | 81 +++++++++++ drivers/i2c/muxes/i2c-mux-gpio.c | 146 +++++++++++++++----- 2 files changed, 196 insertions(+), 31 deletions(-) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt new file mode 100644 index 0000000..66709a8 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt @@ -0,0 +1,81 @@ +GPIO-based I2C Bus Mux + +This binding describes an I2C bus multiplexer that uses GPIOs to +route the I2C signals. + + +-----+ +-----+ + | dev | | dev | + +------------+ +-----+ +-----+ + | SoC | | | + | | /--------+--------+ + | +------+ | +------+ child bus A, on GPIO value set to 0 + | | I2C |-|--| Mux | + | +------+ | +--+---+ child bus B, on GPIO value set to 1 + | | | \----------+--------+--------+ + | +------+ | | | | | + | | GPIO |-|-----+ +-----+ +-----+ +-----+ + | +------+ | | dev | | dev | | dev | + +------------+ +-----+ +-----+ +-----+ + +Required properties: +- compatible: i2c-mux-gpio +- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side + port is connected to. +- mux-gpios: list of gpios used to control the muxer +* Standard I2C mux properties. See mux.txt in this directory. +* I2C child bus nodes. See mux.txt in this directory. + +Optional properties: +- idle-state: value to set the muxer to when idle. When no value is + given, it defaults to the last value used. + +For each i2c child node, an I2C child bus will be created. They will +be numbered based on their order in the device tree. + +Whenever an access is made to a device on a child bus, the value set +in the revelant node's reg property will be output using the list of +GPIOs, the first in the list holding the least-significant value. + +If an idle state is defined, using the idle-state (optional) property, +whenever an access is not being made to a device on a child bus, the +GPIOs will be set according to the idle value. + +If an idle state is not defined, the most recently used value will be +left programmed into hardware whenever no access is being made to a +device on a child bus. + +Example: + i2cmux { + compatible = "i2c-mux-gpio"; + #address-cells = <1>; + #size-cells = <0>; + mux-gpios = <&gpio1 22 0 &gpio1 23 0>; + i2c-parent = <&i2c1>; + + i2c@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + ssd1307: oled@3c { + compatible = "solomon,ssd1307fb-i2c"; + reg = <0x3c>; + pwms = <&pwm 4 3000>; + reset-gpios = <&gpio2 7 1>; + reset-active-low; + }; + }; + + i2c@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + + pca9555: pca9555@20 { + compatible = "nxp,pca9555"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x20>; + }; + }; + }; diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 566a675..e446f05 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -16,6 +16,8 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/gpio.h> +#include <linux/of_i2c.h> +#include <linux/of_gpio.h> struct gpiomux { struct i2c_adapter *parent; @@ -57,29 +59,111 @@ static int __devinit match_gpio_chip_by_label(struct gpio_chip *chip, return !strcmp(chip->label, data); } +#ifdef CONFIG_OF +static int __devinit i2c_mux_gpio_probe_dt(struct gpiomux *mux, + struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *adapter_np, *child; + struct i2c_adapter *adapter; + unsigned *values, *gpios; + int i = 0; + + if (!np) + return -ENODEV; + + adapter_np = of_parse_phandle(np, "i2c-parent", 0); + if (!adapter_np) { + dev_err(&pdev->dev, "Cannot parse i2c-parent\n"); + return -ENODEV; + } + adapter = of_find_i2c_adapter_by_node(adapter_np); + if (!adapter) { + dev_err(&pdev->dev, "Cannot find parent bus\n"); + return -ENODEV; + } + mux->data.parent = i2c_adapter_id(adapter); + put_device(&adapter->dev); + + mux->data.n_values = of_get_child_count(np); + + values = devm_kzalloc(&pdev->dev, + sizeof(*mux->data.values) * mux->data.n_values, + GFP_KERNEL); + if (!values) { + dev_err(&pdev->dev, "Cannot allocate values array"); + return -ENOMEM; + } + + for_each_child_of_node(np, child) { + of_property_read_u32(child, "reg", values + i); + i++; + } + mux->data.values = values; + + if (of_property_read_u32(np, "idle-state", &mux->data.idle)) + mux->data.idle = I2C_MUX_GPIO_NO_IDLE; + + mux->data.n_gpios = of_gpio_named_count(np, "mux-gpios"); + if (mux->data.n_gpios < 0) { + dev_err(&pdev->dev, "Missing mux-gpios property in the DT.\n"); + return -EINVAL; + } + + gpios = devm_kzalloc(&pdev->dev, + sizeof(*mux->data.gpios) * mux->data.n_gpios, + GFP_KERNEL); + if (!gpios) { + dev_err(&pdev->dev, "Cannot allocate gpios array"); + return -ENOMEM; + } + + for (i = 0; i < mux->data.n_gpios; i++) + gpios[i] = of_get_named_gpio(np, "mux-gpios", i); + + mux->data.gpios = gpios; + + return 0; +} +#else +static int __devinit i2c_mux_gpio_probe_dt(struct gpiomux *mux, + struct platform_device *pdev) +{ + return 0; +} +#endif + static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) { struct gpiomux *mux; - struct i2c_mux_gpio_platform_data *pdata; struct i2c_adapter *parent; int (*deselect) (struct i2c_adapter *, void *, u32); unsigned initial_state, gpio_base; int i, ret; - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "Missing platform data\n"); - return -ENODEV; + mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); + if (!mux) { + dev_err(&pdev->dev, "Cannot allocate gpiomux structure"); + return -ENOMEM; } + platform_set_drvdata(pdev, mux); + + if (!pdev->dev.platform_data) { + ret = i2c_mux_gpio_probe_dt(mux, pdev); + if (ret < 0) + return ret; + } else + memcpy(&mux->data, pdev->dev.platform_data, sizeof(mux->data)); + /* * If a GPIO chip name is provided, the GPIO pin numbers provided are * relative to its base GPIO number. Otherwise they are absolute. */ - if (pdata->gpio_chip) { + if (mux->data.gpio_chip) { struct gpio_chip *gpio; - gpio = gpiochip_find(pdata->gpio_chip, + gpio = gpiochip_find(mux->data.gpio_chip, match_gpio_chip_by_label); if (!gpio) return -EPROBE_DEFER; @@ -89,49 +173,44 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) gpio_base = 0; } - parent = i2c_get_adapter(pdata->parent); + parent = i2c_get_adapter(mux->data.parent); if (!parent) { dev_err(&pdev->dev, "Parent adapter (%d) not found\n", - pdata->parent); + mux->data.parent); return -ENODEV; } - mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); - if (!mux) { - ret = -ENOMEM; - goto alloc_failed; - } - mux->parent = parent; - mux->data = *pdata; mux->gpio_base = gpio_base; + mux->adap = devm_kzalloc(&pdev->dev, - sizeof(*mux->adap) * pdata->n_values, + sizeof(*mux->adap) * mux->data.n_values, GFP_KERNEL); if (!mux->adap) { + dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure"); ret = -ENOMEM; goto alloc_failed; } - if (pdata->idle != I2C_MUX_GPIO_NO_IDLE) { - initial_state = pdata->idle; + if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) { + initial_state = mux->data.idle; deselect = i2c_mux_gpio_deselect; } else { - initial_state = pdata->values[0]; + initial_state = mux->data.values[0]; deselect = NULL; } - for (i = 0; i < pdata->n_gpios; i++) { - ret = gpio_request(gpio_base + pdata->gpios[i], "i2c-mux-gpio"); + for (i = 0; i < mux->data.n_gpios; i++) { + ret = gpio_request(gpio_base + mux->data.gpios[i], "i2c-mux-gpio"); if (ret) goto err_request_gpio; - gpio_direction_output(gpio_base + pdata->gpios[i], + gpio_direction_output(gpio_base + mux->data.gpios[i], initial_state & (1 << i)); } - for (i = 0; i < pdata->n_values; i++) { - u32 nr = pdata->base_nr ? (pdata->base_nr + i) : 0; - unsigned int class = pdata->classes ? pdata->classes[i] : 0; + for (i = 0; i < mux->data.n_values; i++) { + u32 nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0; + unsigned int class = mux->data.classes ? mux->data.classes[i] : 0; mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr, i, class, @@ -144,19 +223,17 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) } dev_info(&pdev->dev, "%d port mux on %s adapter\n", - pdata->n_values, parent->name); - - platform_set_drvdata(pdev, mux); + mux->data.n_values, parent->name); return 0; add_adapter_failed: for (; i > 0; i--) i2c_del_mux_adapter(mux->adap[i - 1]); - i = pdata->n_gpios; + i = mux->data.n_gpios; err_request_gpio: for (; i > 0; i--) - gpio_free(gpio_base + pdata->gpios[i - 1]); + gpio_free(gpio_base + mux->data.gpios[i - 1]); alloc_failed: i2c_put_adapter(parent); @@ -180,12 +257,19 @@ static int __devexit i2c_mux_gpio_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id i2c_mux_gpio_of_match[] __devinitconst = { + { .compatible = "i2c-mux-gpio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, i2c_mux_gpio_of_match); + static struct platform_driver i2c_mux_gpio_driver = { .probe = i2c_mux_gpio_probe, .remove = __devexit_p(i2c_mux_gpio_remove), .driver = { .owner = THIS_MODULE, .name = "i2c-mux-gpio", + .of_match_table = of_match_ptr(i2c_mux_gpio_of_match), }, }; -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 14+ messages in thread
[parent not found: <1351182234-22971-2-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>]
* Re: [PATCH 1/2] i2c: mux: Add dt support to i2c-mux-gpio driver [not found] ` <1351182234-22971-2-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> @ 2012-11-16 8:30 ` Wolfram Sang 0 siblings, 0 replies; 14+ messages in thread From: Wolfram Sang @ 2012-11-16 8:30 UTC (permalink / raw) To: Maxime Ripard Cc: peter.korsgaard-ob4gmnvZ1/cAvxtiuMwx3w, shawn.guo-QSEj5FYQhm4dnm+yROfE0A, linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, brian-ZKiFAVwZFM2FeswfMrDH8w [-- Attachment #1: Type: text/plain, Size: 769 bytes --] On Thu, Oct 25, 2012 at 06:23:53PM +0200, Maxime Ripard wrote: > Allow the i2c-mux-gpio to be used by a device tree enabled device. The > bindings are inspired by the one found in the i2c-mux-pinctrl driver. > > Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> > Reviewed-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org> > Acked-by: Peter Korsgaard <peter.korsgaard-ob4gmnvZ1/cAvxtiuMwx3w@public.gmane.org> checkpatch found a whitespace error in line 115, please run it before submitting. Fixed that and pushed to for-next. Thanks. -- Pengutronix e.K. | Wolfram Sang | Industrial Linux Solutions | http://www.pengutronix.de/ | [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 198 bytes --] ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCHv6 0/2] ARM: I2C: Add device tree bindings to i2c-mux-gpio @ 2012-10-24 14:40 Maxime Ripard [not found] ` <1351089624-20794-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 0 siblings, 1 reply; 14+ messages in thread From: Maxime Ripard @ 2012-10-24 14:40 UTC (permalink / raw) To: peter.korsgaard-ob4gmnvZ1/cAvxtiuMwx3w, shawn.guo-QSEj5FYQhm4dnm+yROfE0A, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, brian-ZKiFAVwZFM2FeswfMrDH8w Hi everyone, This patchset adds the device tree entry to the CFA-10049 board of its i2c muxer. This muxer controls sub-buses that contains three Nuvoton NAU7802 ADCs and a NXP PCA955 GPIO expander. Support for these will be added eventually. Thanks, Maxime Changes from v5: - Fix few errors in the dt bindings documentation - Removed the change of the data variable to a pointer in the gpiomux structure Maxime Ripard (2): i2c: mux: Add dt support to i2c-mux-gpio driver ARM: dts: cfa10049: Add the i2c muxer buses to the CFA-10049 .../devicetree/bindings/i2c/i2c-mux-gpio.txt | 81 +++++++++++ arch/arm/boot/dts/imx28-cfa10049.dts | 24 ++++ drivers/i2c/muxes/i2c-mux-gpio.c | 146 +++++++++++++++----- 3 files changed, 220 insertions(+), 31 deletions(-) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt -- 1.7.9.5 ^ permalink raw reply [flat|nested] 14+ messages in thread
[parent not found: <1351089624-20794-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>]
* [PATCH 1/2] i2c: mux: Add dt support to i2c-mux-gpio driver [not found] ` <1351089624-20794-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> @ 2012-10-24 14:40 ` Maxime Ripard [not found] ` <1351089624-20794-2-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 0 siblings, 1 reply; 14+ messages in thread From: Maxime Ripard @ 2012-10-24 14:40 UTC (permalink / raw) To: peter.korsgaard-ob4gmnvZ1/cAvxtiuMwx3w, shawn.guo-QSEj5FYQhm4dnm+yROfE0A, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, brian-ZKiFAVwZFM2FeswfMrDH8w Allow the i2c-mux-gpio to be used by a device tree enabled device. The bindings are inspired by the one found in the i2c-mux-pinctrl driver. Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> Reviewed-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org> --- .../devicetree/bindings/i2c/i2c-mux-gpio.txt | 81 +++++++++++ drivers/i2c/muxes/i2c-mux-gpio.c | 146 +++++++++++++++----- 2 files changed, 196 insertions(+), 31 deletions(-) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt new file mode 100644 index 0000000..d61726f --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt @@ -0,0 +1,81 @@ +GPIO-based I2C Bus Mux + +This binding describes an I2C bus multiplexer that uses GPIOs to +route the I2C signals. + + +-----+ +-----+ + | dev | | dev | + +------------+ +-----+ +-----+ + | SoC | | | + | | /--------+--------+ + | +------+ | +------+ child bus A, on GPIO value set to 0 + | | I2C |-|--| Mux | + | +------+ | +--+---+ child bus B, on GPIO value set to 1 + | | | \----------+--------+--------+ + | +------+ | | | | | + | | GPIO |-|-----+ +-----+ +-----+ +-----+ + | +------+ | | dev | | dev | | dev | + +------------+ +-----+ +-----+ +-----+ + +Required properties: +- compatible: i2c-mux-gpio +- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side + port is connected to. +- mux-gpios: list of gpios used to control the muxer +* Standard I2C mux properties. See mux.txt in this directory. +* I2C child bus nodes. See mux.txt in this directory. + +Optional properties: +- idle-state: value to set to the muxer when idle. When no value is + given, it defaults to the last value used. + +For each i2c child node, an I2C child bus will be created. They will +be numbered based on their order in the device tree. + +Whenever an access is made to a device on a child bus, the value set +in the revelant node's reg property will be output using the list of +GPIOs, the first in the list holding the least-significant value. + +If an idle state is defined, using the idle-state (optional) property, +whenever an access is not being made to a device on a child bus, the +GPIOs will be set according to the idle value. + +If an idle state is not defined, the most recently used value will be +left programmed into hardware whenever no access is being made to a +device on a child bus. + +Example: + i2cmux { + compatible = "i2c-mux-gpio"; + #address-cells = <1>; + #size-cells = <0>; + mux-gpios = <&gpio1 22 0 &gpio1 23 0>; + i2c-parent = <&i2c1>; + + i2c@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + ssd1307: oled@3c { + compatible = "solomon,ssd1307fb-i2c"; + reg = <0x3c>; + pwms = <&pwm 4 3000>; + reset-gpios = <&gpio2 7 1>; + reset-active-low; + }; + }; + + i2c@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + + pca9555: pca9555@20 { + compatible = "nxp,pca9555"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x20>; + }; + }; + }; diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 566a675..5f20f54 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -16,6 +16,8 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/gpio.h> +#include <linux/of_i2c.h> +#include <linux/of_gpio.h> struct gpiomux { struct i2c_adapter *parent; @@ -57,29 +59,111 @@ static int __devinit match_gpio_chip_by_label(struct gpio_chip *chip, return !strcmp(chip->label, data); } +#ifdef CONFIG_OF +static int __devinit i2c_mux_gpio_probe_dt(struct gpiomux *mux, + struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *adapter_np, *child; + struct i2c_adapter *adapter; + unsigned *values, *gpios; + int i = 0; + + if (!np) + return 0; + + adapter_np = of_parse_phandle(np, "i2c-parent", 0); + if (!adapter_np) { + dev_err(&pdev->dev, "Cannot parse i2c-parent\n"); + return -ENODEV; + } + adapter = of_find_i2c_adapter_by_node(adapter_np); + if (!adapter) { + dev_err(&pdev->dev, "Cannot find parent bus\n"); + return -ENODEV; + } + mux->data.parent = i2c_adapter_id(adapter); + put_device(&adapter->dev); + + mux->data.n_values = of_get_child_count(np); + + values = devm_kzalloc(&pdev->dev, + sizeof(*mux->data.values) * mux->data.n_values, + GFP_KERNEL); + if (!values) { + dev_err(&pdev->dev, "Cannot allocate values array"); + return -ENOMEM; + } + + for_each_child_of_node(np, child) { + of_property_read_u32(child, "reg", values + i); + i++; + } + mux->data.values = values; + + if (of_property_read_u32(np, "idle-state", &mux->data.idle)) + mux->data.idle = I2C_MUX_GPIO_NO_IDLE; + + mux->data.n_gpios = of_gpio_named_count(np, "mux-gpios"); + if (mux->data.n_gpios < 0) { + dev_err(&pdev->dev, "Missing mux-gpios property in the DT.\n"); + return -EINVAL; + } + + gpios = devm_kzalloc(&pdev->dev, + sizeof(*mux->data.gpios) * mux->data.n_gpios, + GFP_KERNEL); + if (!gpios) { + dev_err(&pdev->dev, "Cannot allocate gpios array"); + return -ENOMEM; + } + + for (i = 0; i < mux->data.n_gpios; i++) + gpios[i] = of_get_named_gpio(np, "mux-gpios", i); + + mux->data.gpios = gpios; + + return 0; +} +#else +static int __devinit i2c_mux_gpio_probe_dt(struct gpiomux *mux, + struct platform_device *pdev) +{ + return 0; +} +#endif + static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) { struct gpiomux *mux; - struct i2c_mux_gpio_platform_data *pdata; struct i2c_adapter *parent; int (*deselect) (struct i2c_adapter *, void *, u32); unsigned initial_state, gpio_base; int i, ret; - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "Missing platform data\n"); - return -ENODEV; + mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); + if (!mux) { + dev_err(&pdev->dev, "Cannot allocate gpiomux structure"); + return -ENOMEM; } + platform_set_drvdata(pdev, mux); + + if (!pdev->dev.platform_data) { + ret = i2c_mux_gpio_probe_dt(mux, pdev); + if (ret < 0) + return ret; + } else + memcpy(&mux->data, pdev->dev.platform_data, sizeof(mux->data)); + /* * If a GPIO chip name is provided, the GPIO pin numbers provided are * relative to its base GPIO number. Otherwise they are absolute. */ - if (pdata->gpio_chip) { + if (mux->data.gpio_chip) { struct gpio_chip *gpio; - gpio = gpiochip_find(pdata->gpio_chip, + gpio = gpiochip_find(mux->data.gpio_chip, match_gpio_chip_by_label); if (!gpio) return -EPROBE_DEFER; @@ -89,49 +173,44 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) gpio_base = 0; } - parent = i2c_get_adapter(pdata->parent); + parent = i2c_get_adapter(mux->data.parent); if (!parent) { dev_err(&pdev->dev, "Parent adapter (%d) not found\n", - pdata->parent); + mux->data.parent); return -ENODEV; } - mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); - if (!mux) { - ret = -ENOMEM; - goto alloc_failed; - } - mux->parent = parent; - mux->data = *pdata; mux->gpio_base = gpio_base; + mux->adap = devm_kzalloc(&pdev->dev, - sizeof(*mux->adap) * pdata->n_values, + sizeof(*mux->adap) * mux->data.n_values, GFP_KERNEL); if (!mux->adap) { + dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure"); ret = -ENOMEM; goto alloc_failed; } - if (pdata->idle != I2C_MUX_GPIO_NO_IDLE) { - initial_state = pdata->idle; + if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) { + initial_state = mux->data.idle; deselect = i2c_mux_gpio_deselect; } else { - initial_state = pdata->values[0]; + initial_state = mux->data.values[0]; deselect = NULL; } - for (i = 0; i < pdata->n_gpios; i++) { - ret = gpio_request(gpio_base + pdata->gpios[i], "i2c-mux-gpio"); + for (i = 0; i < mux->data.n_gpios; i++) { + ret = gpio_request(gpio_base + mux->data.gpios[i], "i2c-mux-gpio"); if (ret) goto err_request_gpio; - gpio_direction_output(gpio_base + pdata->gpios[i], + gpio_direction_output(gpio_base + mux->data.gpios[i], initial_state & (1 << i)); } - for (i = 0; i < pdata->n_values; i++) { - u32 nr = pdata->base_nr ? (pdata->base_nr + i) : 0; - unsigned int class = pdata->classes ? pdata->classes[i] : 0; + for (i = 0; i < mux->data.n_values; i++) { + u32 nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0; + unsigned int class = mux->data.classes ? mux->data.classes[i] : 0; mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr, i, class, @@ -144,19 +223,17 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) } dev_info(&pdev->dev, "%d port mux on %s adapter\n", - pdata->n_values, parent->name); - - platform_set_drvdata(pdev, mux); + mux->data.n_values, parent->name); return 0; add_adapter_failed: for (; i > 0; i--) i2c_del_mux_adapter(mux->adap[i - 1]); - i = pdata->n_gpios; + i = mux->data.n_gpios; err_request_gpio: for (; i > 0; i--) - gpio_free(gpio_base + pdata->gpios[i - 1]); + gpio_free(gpio_base + mux->data.gpios[i - 1]); alloc_failed: i2c_put_adapter(parent); @@ -180,12 +257,19 @@ static int __devexit i2c_mux_gpio_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id i2c_mux_gpio_of_match[] __devinitconst = { + { .compatible = "i2c-mux-gpio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, i2c_mux_gpio_of_match); + static struct platform_driver i2c_mux_gpio_driver = { .probe = i2c_mux_gpio_probe, .remove = __devexit_p(i2c_mux_gpio_remove), .driver = { .owner = THIS_MODULE, .name = "i2c-mux-gpio", + .of_match_table = of_match_ptr(i2c_mux_gpio_of_match), }, }; -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 14+ messages in thread
[parent not found: <1351089624-20794-2-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>]
* Re: [PATCH 1/2] i2c: mux: Add dt support to i2c-mux-gpio driver [not found] ` <1351089624-20794-2-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> @ 2012-10-24 14:56 ` Peter Korsgaard 0 siblings, 0 replies; 14+ messages in thread From: Peter Korsgaard @ 2012-10-24 14:56 UTC (permalink / raw) To: Maxime Ripard Cc: shawn.guo-QSEj5FYQhm4dnm+yROfE0A, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ, linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, brian-ZKiFAVwZFM2FeswfMrDH8w >>>>> "MR" == Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> writes: Hi, MR> Allow the i2c-mux-gpio to be used by a device tree enabled device. The MR> bindings are inspired by the one found in the i2c-mux-pinctrl driver. MR> Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> MR> Reviewed-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org> MR> --- MR> .../devicetree/bindings/i2c/i2c-mux-gpio.txt | 81 +++++++++++ MR> drivers/i2c/muxes/i2c-mux-gpio.c | 146 +++++++++++++++----- MR> 2 files changed, 196 insertions(+), 31 deletions(-) MR> create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt MR> diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt MR> new file mode 100644 MR> index 0000000..d61726f MR> --- /dev/null MR> +++ b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt MR> @@ -0,0 +1,81 @@ MR> +GPIO-based I2C Bus Mux MR> + MR> +This binding describes an I2C bus multiplexer that uses GPIOs to MR> +route the I2C signals. MR> + MR> + +-----+ +-----+ MR> + | dev | | dev | MR> + +------------+ +-----+ +-----+ MR> + | SoC | | | MR> + | | /--------+--------+ MR> + | +------+ | +------+ child bus A, on GPIO value set to 0 MR> + | | I2C |-|--| Mux | MR> + | +------+ | +--+---+ child bus B, on GPIO value set to 1 MR> + | | | \----------+--------+--------+ MR> + | +------+ | | | | | MR> + | | GPIO |-|-----+ +-----+ +-----+ +-----+ MR> + | +------+ | | dev | | dev | | dev | MR> + +------------+ +-----+ +-----+ +-----+ MR> + MR> +Required properties: MR> +- compatible: i2c-mux-gpio MR> +- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side MR> + port is connected to. MR> +- mux-gpios: list of gpios used to control the muxer MR> +* Standard I2C mux properties. See mux.txt in this directory. MR> +* I2C child bus nodes. See mux.txt in this directory. MR> + MR> +Optional properties: MR> +- idle-state: value to set to the muxer when idle. When no value is s/to set to the muxer/to set the muxer to/ MR> +++ b/drivers/i2c/muxes/i2c-mux-gpio.c MR> @@ -16,6 +16,8 @@ MR> #include <linux/module.h> MR> #include <linux/slab.h> MR> #include <linux/gpio.h> MR> +#include <linux/of_i2c.h> MR> +#include <linux/of_gpio.h> MR> struct gpiomux { MR> struct i2c_adapter *parent; MR> @@ -57,29 +59,111 @@ static int __devinit match_gpio_chip_by_label(struct gpio_chip *chip, MR> return !strcmp(chip->label, data); MR> } MR> +#ifdef CONFIG_OF MR> +static int __devinit i2c_mux_gpio_probe_dt(struct gpiomux *mux, MR> + struct platform_device *pdev) MR> +{ MR> + struct device_node *np = pdev->dev.of_node; MR> + struct device_node *adapter_np, *child; MR> + struct i2c_adapter *adapter; MR> + unsigned *values, *gpios; MR> + int i = 0; MR> + MR> + if (!np) MR> + return 0; This should be -ENODEV, otherwise we end up using a zeroed out struct i2c_mux_gpio_platform_data in case i2c_mux_gpio is used with the platform bus but the platform forgets to pass the pdata. With those two minor fixes: Acked-by: Peter Korsgaard <peter.korsgaard-ob4gmnvZ1/cAvxtiuMwx3w@public.gmane.org> -- Sorry about disclaimer - It's out of my control. Bye, Peter Korsgaard DISCLAIMER: Unless indicated otherwise, the information contained in this message is privileged and confidential, and is intended only for the use of the addressee(s) named above and others who have been specifically authorized to receive it. If you are not the intended recipient, you are hereby notified that any dissemination, distribution or copying of this message and/or attachments is strictly prohibited. The company accepts no liability for any damage caused by any virus transmitted by this email. Furthermore, the company does not warrant a proper and complete transmission of this information, nor does it accept liability for any delays. If you have received this message in error, please contact the sender and delete the message. Thank you. ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCHv4 0/2] ARM: I2C: Add device tree bindings to i2c-mux-gpio @ 2012-10-18 14:13 Maxime Ripard [not found] ` <1350569623-4699-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 0 siblings, 1 reply; 14+ messages in thread From: Maxime Ripard @ 2012-10-18 14:13 UTC (permalink / raw) To: peter.korsgaard-ob4gmnvZ1/cAvxtiuMwx3w, shawn.guo-QSEj5FYQhm4dnm+yROfE0A, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, brian-ZKiFAVwZFM2FeswfMrDH8w Hi everyone, This patchset adds the device tree entry to the CFA-10049 board of its i2c muxer. This muxer controls sub-buses that contains three Nuvoton NAU7802 ADCs and a NXP PCA955 GPIO expander. Support for these will be added eventually. Thanks, Maxime Changes from v3: - Rebased on top of 3.7-rc1 Maxime Ripard (2): i2c: mux: Add dt support to i2c-mux-gpio driver ARM: dts: cfa10049: Add the i2c muxer buses to the CFA-10049 .../devicetree/bindings/i2c/i2c-mux-gpio.txt | 81 ++++++++++ arch/arm/boot/dts/imx28-cfa10049.dts | 24 +++ drivers/i2c/muxes/i2c-mux-gpio.c | 169 +++++++++++++++----- 3 files changed, 235 insertions(+), 39 deletions(-) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt -- 1.7.9.5 ^ permalink raw reply [flat|nested] 14+ messages in thread
[parent not found: <1350569623-4699-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>]
* [PATCH 1/2] i2c: mux: Add dt support to i2c-mux-gpio driver [not found] ` <1350569623-4699-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> @ 2012-10-18 14:13 ` Maxime Ripard [not found] ` <1350569623-4699-2-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 0 siblings, 1 reply; 14+ messages in thread From: Maxime Ripard @ 2012-10-18 14:13 UTC (permalink / raw) To: peter.korsgaard-ob4gmnvZ1/cAvxtiuMwx3w, shawn.guo-QSEj5FYQhm4dnm+yROfE0A, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, brian-ZKiFAVwZFM2FeswfMrDH8w Allow the i2c-mux-gpio to be used by a device tree enabled device. The bindings are inspired by the one found in the i2c-mux-pinctrl driver. Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> --- .../devicetree/bindings/i2c/i2c-mux-gpio.txt | 81 ++++++++++ drivers/i2c/muxes/i2c-mux-gpio.c | 169 +++++++++++++++----- 2 files changed, 211 insertions(+), 39 deletions(-) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt new file mode 100644 index 0000000..2cddc41 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt @@ -0,0 +1,81 @@ +GPIO-based I2C Bus Mux + +This binding describes an I2C bus multiplexer that uses GPIOs to +route the I2C signals. + + +-----+ +-----+ + | dev | | dev | + +------------+ +-----+ +-----+ + | SoC | | | + | | /--------+--------+ + | +------+ | +------+ child bus A, on GPIO value set to 0 + | | I2C |-|--| Mux | + | +------+ | +--+---+ child bus B, on GPIO value set to 1 + | | | \----------+--------+--------+ + | +------+ | | | | | + | | GPIO |-|-----+ +-----+ +-----+ +-----+ + | +------+ | | dev | | dev | | dev | + +------------+ +-----+ +-----+ +-----+ + +Required properties: +- compatible: i2c-mux-gpio +- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side + port is connected to. +- mux-gpios: list of gpios to use to control the muxer +* Standard I2C mux properties. See mux.txt in this directory. +* I2C child bus nodes. See mux.txt in this directory. + +Optional properties: +- idle-state: value to set to the muxer when idle. When no value is + given, it defaults to the first value in the array. + +For each i2c child node, an I2C child bus will be created. They will +be numbered based on the reg property of each node. + +Whenever an access is made to a device on a child bus, the value set +in the revelant node's reg property will be output using the list of +GPIOs, the first in the list holding the most-significant value. + +If an idle state is defined, using the idle-state (optional) property, +whenever an access is not being made to a device on a child bus, the +idle value will be programmed into the GPIOs. + +If an idle state is not defined, the most recently used value will be +left programmed into hardware whenever no access is being made of a +device on a child bus. + +Example: + i2cmux { + compatible = "i2c-mux-gpio"; + #address-cells = <1>; + #size-cells = <0>; + mux-gpios = <&gpio1 22 0 &gpio1 23 0>; + i2c-parent = <&i2c1>; + + i2c@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + ssd1307: oled@3c { + compatible = "solomon,ssd1307fb-i2c"; + reg = <0x3c>; + pwms = <&pwm 4 3000>; + reset-gpios = <&gpio2 7 1>; + reset-active-low; + }; + }; + + i2c@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + + pca9555: pca9555@20 { + compatible = "nxp,pca9555"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x20>; + }; + }; + }; diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 566a675..7ebef01 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -16,11 +16,13 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/gpio.h> +#include <linux/of_i2c.h> +#include <linux/of_gpio.h> struct gpiomux { struct i2c_adapter *parent; struct i2c_adapter **adap; /* child busses */ - struct i2c_mux_gpio_platform_data data; + struct i2c_mux_gpio_platform_data *data; unsigned gpio_base; }; @@ -28,8 +30,8 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val) { int i; - for (i = 0; i < mux->data.n_gpios; i++) - gpio_set_value(mux->gpio_base + mux->data.gpios[i], + for (i = 0; i < mux->data->n_gpios; i++) + gpio_set_value(mux->gpio_base + mux->data->gpios[i], val & (1 << i)); } @@ -37,7 +39,7 @@ static int i2c_mux_gpio_select(struct i2c_adapter *adap, void *data, u32 chan) { struct gpiomux *mux = data; - i2c_mux_gpio_set(mux, mux->data.values[chan]); + i2c_mux_gpio_set(mux, mux->data->values[chan]); return 0; } @@ -46,7 +48,7 @@ static int i2c_mux_gpio_deselect(struct i2c_adapter *adap, void *data, u32 chan) { struct gpiomux *mux = data; - i2c_mux_gpio_set(mux, mux->data.idle); + i2c_mux_gpio_set(mux, mux->data->idle); return 0; } @@ -57,29 +59,118 @@ static int __devinit match_gpio_chip_by_label(struct gpio_chip *chip, return !strcmp(chip->label, data); } +#ifdef CONFIG_OF +static int __devinit i2c_mux_gpio_probe_dt(struct gpiomux *mux, + struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *adapter_np, *child; + struct i2c_adapter *adapter; + unsigned *values, *gpios; + int i = 0; + + if (!np) + return 0; + + mux->data = devm_kzalloc(&pdev->dev, sizeof(*mux->data), + GFP_KERNEL); + if (!mux->data) { + dev_err(&pdev->dev, "Cannot allocate platform_data"); + return -ENOMEM; + } + + adapter_np = of_parse_phandle(np, "i2c-parent", 0); + if (!adapter_np) { + dev_err(&pdev->dev, "Cannot parse i2c-parent\n"); + return -ENODEV; + } + adapter = of_find_i2c_adapter_by_node(adapter_np); + if (!adapter) { + dev_err(&pdev->dev, "Cannot find parent bus\n"); + return -ENODEV; + } + mux->data->parent = i2c_adapter_id(adapter); + put_device(&adapter->dev); + + mux->data->n_values = of_get_child_count(np); + + values = devm_kzalloc(&pdev->dev, + sizeof(*mux->data->values) * mux->data->n_values, + GFP_KERNEL); + if (!values) { + dev_err(&pdev->dev, "Cannot allocate values array"); + return -ENOMEM; + } + + for_each_child_of_node(np, child) { + of_property_read_u32(child, "reg", values + i); + i++; + } + mux->data->values = values; + + if (of_property_read_u32(np, "idle-state", &mux->data->idle)) + mux->data->idle = I2C_MUX_GPIO_NO_IDLE; + + mux->data->n_gpios = of_gpio_named_count(np, "mux-gpios"); + if (mux->data->n_gpios < 0) { + dev_err(&pdev->dev, "Missing mux-gpios property in the DT.\n"); + return -EINVAL; + } + + gpios = devm_kzalloc(&pdev->dev, + sizeof(*mux->data->gpios) * mux->data->n_gpios, + GFP_KERNEL); + if (!gpios) { + dev_err(&pdev->dev, "Cannot allocate gpios array"); + return -ENOMEM; + } + + for (i = 0; i < mux->data->n_gpios; i++) + gpios[i] = of_get_named_gpio(np, "mux-gpios", i); + + mux->data->gpios = gpios; + + return 0; +} +#else +static int __devinit i2c_mux_gpio_probe_dt(struct gpiomux *mux, + struct platform_device *pdev) +{ + return 0; +} +#endif + static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) { struct gpiomux *mux; - struct i2c_mux_gpio_platform_data *pdata; struct i2c_adapter *parent; int (*deselect) (struct i2c_adapter *, void *, u32); unsigned initial_state, gpio_base; int i, ret; - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "Missing platform data\n"); - return -ENODEV; + mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); + if (!mux) { + dev_err(&pdev->dev, "Cannot allocate gpiomux structure"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, mux); + + mux->data = pdev->dev.platform_data; + if (!mux->data) { + ret = i2c_mux_gpio_probe_dt(mux, pdev); + if (ret < 0) + return ret; } /* * If a GPIO chip name is provided, the GPIO pin numbers provided are * relative to its base GPIO number. Otherwise they are absolute. */ - if (pdata->gpio_chip) { + if (mux->data->gpio_chip) { struct gpio_chip *gpio; - gpio = gpiochip_find(pdata->gpio_chip, + gpio = gpiochip_find(mux->data->gpio_chip, match_gpio_chip_by_label); if (!gpio) return -EPROBE_DEFER; @@ -89,49 +180,44 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) gpio_base = 0; } - parent = i2c_get_adapter(pdata->parent); + parent = i2c_get_adapter(mux->data->parent); if (!parent) { dev_err(&pdev->dev, "Parent adapter (%d) not found\n", - pdata->parent); + mux->data->parent); return -ENODEV; } - mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); - if (!mux) { - ret = -ENOMEM; - goto alloc_failed; - } - mux->parent = parent; - mux->data = *pdata; mux->gpio_base = gpio_base; + mux->adap = devm_kzalloc(&pdev->dev, - sizeof(*mux->adap) * pdata->n_values, + sizeof(*mux->adap) * mux->data->n_values, GFP_KERNEL); if (!mux->adap) { + dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure"); ret = -ENOMEM; goto alloc_failed; } - if (pdata->idle != I2C_MUX_GPIO_NO_IDLE) { - initial_state = pdata->idle; + if (mux->data->idle != I2C_MUX_GPIO_NO_IDLE) { + initial_state = mux->data->idle; deselect = i2c_mux_gpio_deselect; } else { - initial_state = pdata->values[0]; + initial_state = mux->data->values[0]; deselect = NULL; } - for (i = 0; i < pdata->n_gpios; i++) { - ret = gpio_request(gpio_base + pdata->gpios[i], "i2c-mux-gpio"); + for (i = 0; i < mux->data->n_gpios; i++) { + ret = gpio_request(gpio_base + mux->data->gpios[i], "i2c-mux-gpio"); if (ret) goto err_request_gpio; - gpio_direction_output(gpio_base + pdata->gpios[i], + gpio_direction_output(gpio_base + mux->data->gpios[i], initial_state & (1 << i)); } - for (i = 0; i < pdata->n_values; i++) { - u32 nr = pdata->base_nr ? (pdata->base_nr + i) : 0; - unsigned int class = pdata->classes ? pdata->classes[i] : 0; + for (i = 0; i < mux->data->n_values; i++) { + u32 nr = mux->data->base_nr ? (mux->data->base_nr + i) : 0; + unsigned int class = mux->data->classes ? mux->data->classes[i] : 0; mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr, i, class, @@ -144,19 +230,17 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev) } dev_info(&pdev->dev, "%d port mux on %s adapter\n", - pdata->n_values, parent->name); - - platform_set_drvdata(pdev, mux); + mux->data->n_values, parent->name); return 0; add_adapter_failed: for (; i > 0; i--) i2c_del_mux_adapter(mux->adap[i - 1]); - i = pdata->n_gpios; + i = mux->data->n_gpios; err_request_gpio: for (; i > 0; i--) - gpio_free(gpio_base + pdata->gpios[i - 1]); + gpio_free(gpio_base + mux->data->gpios[i - 1]); alloc_failed: i2c_put_adapter(parent); @@ -168,11 +252,11 @@ static int __devexit i2c_mux_gpio_remove(struct platform_device *pdev) struct gpiomux *mux = platform_get_drvdata(pdev); int i; - for (i = 0; i < mux->data.n_values; i++) + for (i = 0; i < mux->data->n_values; i++) i2c_del_mux_adapter(mux->adap[i]); - for (i = 0; i < mux->data.n_gpios; i++) - gpio_free(mux->gpio_base + mux->data.gpios[i]); + for (i = 0; i < mux->data->n_gpios; i++) + gpio_free(mux->gpio_base + mux->data->gpios[i]); platform_set_drvdata(pdev, NULL); i2c_put_adapter(mux->parent); @@ -180,12 +264,19 @@ static int __devexit i2c_mux_gpio_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id i2c_mux_gpio_of_match[] __devinitconst = { + { .compatible = "i2c-mux-gpio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, i2c_mux_gpio_of_match); + static struct platform_driver i2c_mux_gpio_driver = { .probe = i2c_mux_gpio_probe, .remove = __devexit_p(i2c_mux_gpio_remove), .driver = { .owner = THIS_MODULE, .name = "i2c-mux-gpio", + .of_match_table = of_match_ptr(i2c_mux_gpio_of_match), }, }; -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 14+ messages in thread
[parent not found: <1350569623-4699-2-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>]
* Re: [PATCH 1/2] i2c: mux: Add dt support to i2c-mux-gpio driver [not found] ` <1350569623-4699-2-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> @ 2012-10-18 22:36 ` Stephen Warren [not found] ` <50808481.6040501-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> 0 siblings, 1 reply; 14+ messages in thread From: Stephen Warren @ 2012-10-18 22:36 UTC (permalink / raw) To: Maxime Ripard Cc: peter.korsgaard-ob4gmnvZ1/cAvxtiuMwx3w, shawn.guo-QSEj5FYQhm4dnm+yROfE0A, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ, brian-ZKiFAVwZFM2FeswfMrDH8w, linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r On 10/18/2012 08:13 AM, Maxime Ripard wrote: > Allow the i2c-mux-gpio to be used by a device tree enabled device. The > bindings are inspired by the one found in the i2c-mux-pinctrl driver. > +++ b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt > +Optional properties: > +- idle-state: value to set to the muxer when idle. When no value is > + given, it defaults to the first value in the array. That's inconsistent with the following text that appears later (and describes what the driver actually does): > +If an idle state is defined, using the idle-state (optional) property, > +whenever an access is not being made to a device on a child bus, the > +idle value will be programmed into the GPIOs. > + > +If an idle state is not defined, the most recently used value will be > +left programmed into hardware whenever no access is being made of a > +device on a child bus. ^ permalink raw reply [flat|nested] 14+ messages in thread
[parent not found: <50808481.6040501-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>]
* Re: [PATCH 1/2] i2c: mux: Add dt support to i2c-mux-gpio driver [not found] ` <50808481.6040501-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> @ 2012-10-19 8:55 ` Maxime Ripard 0 siblings, 0 replies; 14+ messages in thread From: Maxime Ripard @ 2012-10-19 8:55 UTC (permalink / raw) To: Stephen Warren Cc: peter.korsgaard-ob4gmnvZ1/cAvxtiuMwx3w, shawn.guo-QSEj5FYQhm4dnm+yROfE0A, w.sang-bIcnvbaLZ9MEGnE8C9+IrQ, brian-ZKiFAVwZFM2FeswfMrDH8w, linux-i2c-u79uwXL29TY76Z2rM5mHXA, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r Le 19/10/2012 00:36, Stephen Warren a écrit : > On 10/18/2012 08:13 AM, Maxime Ripard wrote: >> Allow the i2c-mux-gpio to be used by a device tree enabled device. The >> bindings are inspired by the one found in the i2c-mux-pinctrl driver. > >> +++ b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt > >> +Optional properties: >> +- idle-state: value to set to the muxer when idle. When no value is >> + given, it defaults to the first value in the array. > > That's inconsistent with the following text that appears later (and > describes what the driver actually does): Ah, right, sorry Maxime -- Maxime Ripard, Free Electrons Kernel, drivers, real-time and embedded Linux development, consulting, training and support. http://free-electrons.com ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2012-11-16 8:30 UTC | newest] Thread overview: 14+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2012-10-22 12:53 [PATCHv5 0/2] ARM: I2C: Add device tree bindings to i2c-mux-gpio Maxime Ripard [not found] ` <1350910413-23925-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 2012-10-22 12:53 ` [PATCH 1/2] i2c: mux: Add dt support to i2c-mux-gpio driver Maxime Ripard [not found] ` <1350910413-23925-2-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 2012-10-22 20:16 ` Stephen Warren 2012-10-23 19:51 ` Peter Korsgaard [not found] ` <87liexrmoz.fsf-1Ae4nN3xCbAluPl5bxqUMw@public.gmane.org> 2012-10-24 8:37 ` Maxime Ripard [not found] ` <5087A8E5.8050103-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 2012-10-24 11:45 ` Peter Korsgaard 2012-10-22 12:53 ` [PATCH 2/2] ARM: dts: cfa10049: Add the i2c muxer buses to the CFA-10049 Maxime Ripard -- strict thread matches above, loose matches on Subject: below -- 2012-10-25 16:23 [PATCHv7 0/2] ARM: I2C: Add device tree bindings to i2c-mux-gpio Maxime Ripard [not found] ` <1351182234-22971-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 2012-10-25 16:23 ` [PATCH 1/2] i2c: mux: Add dt support to i2c-mux-gpio driver Maxime Ripard [not found] ` <1351182234-22971-2-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 2012-11-16 8:30 ` Wolfram Sang 2012-10-24 14:40 [PATCHv6 0/2] ARM: I2C: Add device tree bindings to i2c-mux-gpio Maxime Ripard [not found] ` <1351089624-20794-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 2012-10-24 14:40 ` [PATCH 1/2] i2c: mux: Add dt support to i2c-mux-gpio driver Maxime Ripard [not found] ` <1351089624-20794-2-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 2012-10-24 14:56 ` Peter Korsgaard 2012-10-18 14:13 [PATCHv4 0/2] ARM: I2C: Add device tree bindings to i2c-mux-gpio Maxime Ripard [not found] ` <1350569623-4699-1-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 2012-10-18 14:13 ` [PATCH 1/2] i2c: mux: Add dt support to i2c-mux-gpio driver Maxime Ripard [not found] ` <1350569623-4699-2-git-send-email-maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> 2012-10-18 22:36 ` Stephen Warren [not found] ` <50808481.6040501-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> 2012-10-19 8:55 ` Maxime Ripard
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).