diff options
author | Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> | 2012-02-05 05:22:34 -0500 |
---|---|---|
committer | Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> | 2012-03-15 11:29:22 -0400 |
commit | 8ffaa0f40db22564efc44588a9d861d78a1fae02 (patch) | |
tree | 4c255465cc79e8ec7cc36812add87b64ee06e07d /drivers/i2c | |
parent | 86a89f4ff665d385741a7831c612fc0b9aa22480 (diff) |
i2c/gpio: add DT support
To achieve DT support, we need to populate a custom platform_data in a
private struct from DT information. To simplify code, the adapter and
algorithm are also put into the private struct.
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Acked-by: Rob Herring <rob.herring@calxeda.com>
Acked-by: Wolfram Sang <w.sang@pengutronix.de>
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-gpio.c | 98 |
1 files changed, 76 insertions, 22 deletions
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index a651779d9ff7..c0330a41db03 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c | |||
@@ -14,8 +14,15 @@ | |||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
17 | 17 | #include <linux/gpio.h> | |
18 | #include <asm/gpio.h> | 18 | #include <linux/of_gpio.h> |
19 | #include <linux/of_i2c.h> | ||
20 | |||
21 | struct i2c_gpio_private_data { | ||
22 | struct i2c_adapter adap; | ||
23 | struct i2c_algo_bit_data bit_data; | ||
24 | struct i2c_gpio_platform_data pdata; | ||
25 | }; | ||
19 | 26 | ||
20 | /* Toggle SDA by changing the direction of the pin */ | 27 | /* Toggle SDA by changing the direction of the pin */ |
21 | static void i2c_gpio_setsda_dir(void *data, int state) | 28 | static void i2c_gpio_setsda_dir(void *data, int state) |
@@ -78,24 +85,62 @@ static int i2c_gpio_getscl(void *data) | |||
78 | return gpio_get_value(pdata->scl_pin); | 85 | return gpio_get_value(pdata->scl_pin); |
79 | } | 86 | } |
80 | 87 | ||
88 | static int __devinit of_i2c_gpio_probe(struct device_node *np, | ||
89 | struct i2c_gpio_platform_data *pdata) | ||
90 | { | ||
91 | u32 reg; | ||
92 | |||
93 | if (of_gpio_count(np) < 2) | ||
94 | return -ENODEV; | ||
95 | |||
96 | pdata->sda_pin = of_get_gpio(np, 0); | ||
97 | pdata->scl_pin = of_get_gpio(np, 1); | ||
98 | |||
99 | if (!gpio_is_valid(pdata->sda_pin) || !gpio_is_valid(pdata->scl_pin)) { | ||
100 | pr_err("%s: invalid GPIO pins, sda=%d/scl=%d\n", | ||
101 | np->full_name, pdata->sda_pin, pdata->scl_pin); | ||
102 | return -ENODEV; | ||
103 | } | ||
104 | |||
105 | of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay); | ||
106 | |||
107 | if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", ®)) | ||
108 | pdata->timeout = msecs_to_jiffies(reg); | ||
109 | |||
110 | pdata->sda_is_open_drain = | ||
111 | of_property_read_bool(np, "i2c-gpio,sda-open-drain"); | ||
112 | pdata->scl_is_open_drain = | ||
113 | of_property_read_bool(np, "i2c-gpio,scl-open-drain"); | ||
114 | pdata->scl_is_output_only = | ||
115 | of_property_read_bool(np, "i2c-gpio,scl-output-only"); | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
81 | static int __devinit i2c_gpio_probe(struct platform_device *pdev) | 120 | static int __devinit i2c_gpio_probe(struct platform_device *pdev) |
82 | { | 121 | { |
122 | struct i2c_gpio_private_data *priv; | ||
83 | struct i2c_gpio_platform_data *pdata; | 123 | struct i2c_gpio_platform_data *pdata; |
84 | struct i2c_algo_bit_data *bit_data; | 124 | struct i2c_algo_bit_data *bit_data; |
85 | struct i2c_adapter *adap; | 125 | struct i2c_adapter *adap; |
86 | int ret; | 126 | int ret; |
87 | 127 | ||
88 | pdata = pdev->dev.platform_data; | 128 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); |
89 | if (!pdata) | 129 | if (!priv) |
90 | return -ENXIO; | 130 | return -ENOMEM; |
91 | 131 | adap = &priv->adap; | |
92 | ret = -ENOMEM; | 132 | bit_data = &priv->bit_data; |
93 | adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); | 133 | pdata = &priv->pdata; |
94 | if (!adap) | 134 | |
95 | goto err_alloc_adap; | 135 | if (pdev->dev.of_node) { |
96 | bit_data = kzalloc(sizeof(struct i2c_algo_bit_data), GFP_KERNEL); | 136 | ret = of_i2c_gpio_probe(pdev->dev.of_node, pdata); |
97 | if (!bit_data) | 137 | if (ret) |
98 | goto err_alloc_bit_data; | 138 | return ret; |
139 | } else { | ||
140 | if (!pdev->dev.platform_data) | ||
141 | return -ENXIO; | ||
142 | memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata)); | ||
143 | } | ||
99 | 144 | ||
100 | ret = gpio_request(pdata->sda_pin, "sda"); | 145 | ret = gpio_request(pdata->sda_pin, "sda"); |
101 | if (ret) | 146 | if (ret) |
@@ -143,6 +188,7 @@ static int __devinit i2c_gpio_probe(struct platform_device *pdev) | |||
143 | adap->algo_data = bit_data; | 188 | adap->algo_data = bit_data; |
144 | adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; | 189 | adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; |
145 | adap->dev.parent = &pdev->dev; | 190 | adap->dev.parent = &pdev->dev; |
191 | adap->dev.of_node = pdev->dev.of_node; | ||
146 | 192 | ||
147 | /* | 193 | /* |
148 | * If "dev->id" is negative we consider it as zero. | 194 | * If "dev->id" is negative we consider it as zero. |
@@ -154,7 +200,9 @@ static int __devinit i2c_gpio_probe(struct platform_device *pdev) | |||
154 | if (ret) | 200 | if (ret) |
155 | goto err_add_bus; | 201 | goto err_add_bus; |
156 | 202 | ||
157 | platform_set_drvdata(pdev, adap); | 203 | of_i2c_register_devices(adap); |
204 | |||
205 | platform_set_drvdata(pdev, priv); | ||
158 | 206 | ||
159 | dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n", | 207 | dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n", |
160 | pdata->sda_pin, pdata->scl_pin, | 208 | pdata->sda_pin, pdata->scl_pin, |
@@ -168,34 +216,40 @@ err_add_bus: | |||
168 | err_request_scl: | 216 | err_request_scl: |
169 | gpio_free(pdata->sda_pin); | 217 | gpio_free(pdata->sda_pin); |
170 | err_request_sda: | 218 | err_request_sda: |
171 | kfree(bit_data); | ||
172 | err_alloc_bit_data: | ||
173 | kfree(adap); | ||
174 | err_alloc_adap: | ||
175 | return ret; | 219 | return ret; |
176 | } | 220 | } |
177 | 221 | ||
178 | static int __devexit i2c_gpio_remove(struct platform_device *pdev) | 222 | static int __devexit i2c_gpio_remove(struct platform_device *pdev) |
179 | { | 223 | { |
224 | struct i2c_gpio_private_data *priv; | ||
180 | struct i2c_gpio_platform_data *pdata; | 225 | struct i2c_gpio_platform_data *pdata; |
181 | struct i2c_adapter *adap; | 226 | struct i2c_adapter *adap; |
182 | 227 | ||
183 | adap = platform_get_drvdata(pdev); | 228 | priv = platform_get_drvdata(pdev); |
184 | pdata = pdev->dev.platform_data; | 229 | adap = &priv->adap; |
230 | pdata = &priv->pdata; | ||
185 | 231 | ||
186 | i2c_del_adapter(adap); | 232 | i2c_del_adapter(adap); |
187 | gpio_free(pdata->scl_pin); | 233 | gpio_free(pdata->scl_pin); |
188 | gpio_free(pdata->sda_pin); | 234 | gpio_free(pdata->sda_pin); |
189 | kfree(adap->algo_data); | ||
190 | kfree(adap); | ||
191 | 235 | ||
192 | return 0; | 236 | return 0; |
193 | } | 237 | } |
194 | 238 | ||
239 | #if defined(CONFIG_OF) | ||
240 | static const struct of_device_id i2c_gpio_dt_ids[] = { | ||
241 | { .compatible = "i2c-gpio", }, | ||
242 | { /* sentinel */ } | ||
243 | }; | ||
244 | |||
245 | MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids); | ||
246 | #endif | ||
247 | |||
195 | static struct platform_driver i2c_gpio_driver = { | 248 | static struct platform_driver i2c_gpio_driver = { |
196 | .driver = { | 249 | .driver = { |
197 | .name = "i2c-gpio", | 250 | .name = "i2c-gpio", |
198 | .owner = THIS_MODULE, | 251 | .owner = THIS_MODULE, |
252 | .of_match_table = of_match_ptr(i2c_gpio_dt_ids), | ||
199 | }, | 253 | }, |
200 | .probe = i2c_gpio_probe, | 254 | .probe = i2c_gpio_probe, |
201 | .remove = __devexit_p(i2c_gpio_remove), | 255 | .remove = __devexit_p(i2c_gpio_remove), |