2 * I2C multiplexer using GPIO API
4 * Peter Korsgaard <peter.korsgaard@barco.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
11 #include <linux/i2c.h>
12 #include <linux/i2c-mux.h>
13 #include <linux/i2c-mux-gpio.h>
14 #include <linux/platform_device.h>
15 #include <linux/init.h>
16 #include <linux/module.h>
17 #include <linux/slab.h>
18 #include <linux/gpio.h>
21 struct i2c_adapter
*parent
;
22 struct i2c_adapter
**adap
; /* child busses */
23 struct i2c_mux_gpio_platform_data data
;
27 static void i2c_mux_gpio_set(const struct gpiomux
*mux
, unsigned val
)
31 for (i
= 0; i
< mux
->data
.n_gpios
; i
++)
32 gpio_set_value(mux
->gpio_base
+ mux
->data
.gpios
[i
],
36 static int i2c_mux_gpio_select(struct i2c_adapter
*adap
, void *data
, u32 chan
)
38 struct gpiomux
*mux
= data
;
40 i2c_mux_gpio_set(mux
, mux
->data
.values
[chan
]);
45 static int i2c_mux_gpio_deselect(struct i2c_adapter
*adap
, void *data
, u32 chan
)
47 struct gpiomux
*mux
= data
;
49 i2c_mux_gpio_set(mux
, mux
->data
.idle
);
54 static int __devinit
match_gpio_chip_by_label(struct gpio_chip
*chip
,
57 return !strcmp(chip
->label
, data
);
60 static int __devinit
i2c_mux_gpio_probe(struct platform_device
*pdev
)
63 struct i2c_mux_gpio_platform_data
*pdata
;
64 struct i2c_adapter
*parent
;
65 int (*deselect
) (struct i2c_adapter
*, void *, u32
);
66 unsigned initial_state
, gpio_base
;
69 pdata
= pdev
->dev
.platform_data
;
71 dev_err(&pdev
->dev
, "Missing platform data\n");
76 * If a GPIO chip name is provided, the GPIO pin numbers provided are
77 * relative to its base GPIO number. Otherwise they are absolute.
79 if (pdata
->gpio_chip
) {
80 struct gpio_chip
*gpio
;
82 gpio
= gpiochip_find(pdata
->gpio_chip
,
83 match_gpio_chip_by_label
);
87 gpio_base
= gpio
->base
;
92 parent
= i2c_get_adapter(pdata
->parent
);
94 dev_err(&pdev
->dev
, "Parent adapter (%d) not found\n",
99 mux
= devm_kzalloc(&pdev
->dev
, sizeof(*mux
), GFP_KERNEL
);
105 mux
->parent
= parent
;
107 mux
->gpio_base
= gpio_base
;
108 mux
->adap
= devm_kzalloc(&pdev
->dev
,
109 sizeof(*mux
->adap
) * pdata
->n_values
,
116 if (pdata
->idle
!= I2C_MUX_GPIO_NO_IDLE
) {
117 initial_state
= pdata
->idle
;
118 deselect
= i2c_mux_gpio_deselect
;
120 initial_state
= pdata
->values
[0];
124 for (i
= 0; i
< pdata
->n_gpios
; i
++) {
125 ret
= gpio_request(gpio_base
+ pdata
->gpios
[i
], "i2c-mux-gpio");
127 goto err_request_gpio
;
128 gpio_direction_output(gpio_base
+ pdata
->gpios
[i
],
129 initial_state
& (1 << i
));
132 for (i
= 0; i
< pdata
->n_values
; i
++) {
133 u32 nr
= pdata
->base_nr
? (pdata
->base_nr
+ i
) : 0;
134 unsigned int class = pdata
->classes
? pdata
->classes
[i
] : 0;
136 mux
->adap
[i
] = i2c_add_mux_adapter(parent
, &pdev
->dev
, mux
, nr
,
138 i2c_mux_gpio_select
, deselect
);
141 dev_err(&pdev
->dev
, "Failed to add adapter %d\n", i
);
142 goto add_adapter_failed
;
146 dev_info(&pdev
->dev
, "%d port mux on %s adapter\n",
147 pdata
->n_values
, parent
->name
);
149 platform_set_drvdata(pdev
, mux
);
155 i2c_del_mux_adapter(mux
->adap
[i
- 1]);
159 gpio_free(gpio_base
+ pdata
->gpios
[i
- 1]);
161 i2c_put_adapter(parent
);
166 static int __devexit
i2c_mux_gpio_remove(struct platform_device
*pdev
)
168 struct gpiomux
*mux
= platform_get_drvdata(pdev
);
171 for (i
= 0; i
< mux
->data
.n_values
; i
++)
172 i2c_del_mux_adapter(mux
->adap
[i
]);
174 for (i
= 0; i
< mux
->data
.n_gpios
; i
++)
175 gpio_free(mux
->gpio_base
+ mux
->data
.gpios
[i
]);
177 platform_set_drvdata(pdev
, NULL
);
178 i2c_put_adapter(mux
->parent
);
183 static struct platform_driver i2c_mux_gpio_driver
= {
184 .probe
= i2c_mux_gpio_probe
,
185 .remove
= __devexit_p(i2c_mux_gpio_remove
),
187 .owner
= THIS_MODULE
,
188 .name
= "i2c-mux-gpio",
192 module_platform_driver(i2c_mux_gpio_driver
);
194 MODULE_DESCRIPTION("GPIO-based I2C multiplexer driver");
195 MODULE_AUTHOR("Peter Korsgaard <peter.korsgaard@barco.com>");
196 MODULE_LICENSE("GPL");
197 MODULE_ALIAS("platform:i2c-mux-gpio");