diff options
author | Stephen Warren <swarren@wwwdotorg.org> | 2013-02-11 21:47:56 -0500 |
---|---|---|
committer | Wolfram Sang <wolfram@the-dreams.de> | 2013-02-12 05:33:59 -0500 |
commit | f3b54b9a066edeac5c06e1cdcd82e1cb1224aaef (patch) | |
tree | a98bbfac8ccd16ac6535107a066bb78a226adc7d /drivers/i2c | |
parent | cb7f07a4c58659d971a60ebbb8547f6611278622 (diff) |
i2c: add bcm2835 driver
This implements a very basic I2C host driver for the BCM2835 SoC. Missing
features so far are:
* 10-bit addressing.
* DMA.
Reviewed-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Stephen Warren <swarren@wwwdotorg.org>
Signed-off-by: Wolfram Sang <wolfram@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/Kconfig | 12 | ||||
-rw-r--r-- | drivers/i2c/busses/Makefile | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-bcm2835.c | 342 |
3 files changed, 355 insertions, 0 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 74e18bc0bf62..8cbd9cd1e0fa 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
@@ -330,6 +330,18 @@ config I2C_AU1550 | |||
330 | This driver can also be built as a module. If so, the module | 330 | This driver can also be built as a module. If so, the module |
331 | will be called i2c-au1550. | 331 | will be called i2c-au1550. |
332 | 332 | ||
333 | config I2C_BCM2835 | ||
334 | tristate "Broadcom BCM2835 I2C controller" | ||
335 | depends on ARCH_BCM2835 | ||
336 | help | ||
337 | If you say yes to this option, support will be included for the | ||
338 | BCM2835 I2C controller. | ||
339 | |||
340 | If you don't know what to do here, say N. | ||
341 | |||
342 | This support is also available as a module. If so, the module | ||
343 | will be called i2c-bcm2835. | ||
344 | |||
333 | config I2C_BLACKFIN_TWI | 345 | config I2C_BLACKFIN_TWI |
334 | tristate "Blackfin TWI I2C support" | 346 | tristate "Blackfin TWI I2C support" |
335 | depends on BLACKFIN | 347 | depends on BLACKFIN |
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 23c9d55bc880..8f4fc23b85b1 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile | |||
@@ -31,6 +31,7 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o | |||
31 | # Embedded system I2C/SMBus host controller drivers | 31 | # Embedded system I2C/SMBus host controller drivers |
32 | obj-$(CONFIG_I2C_AT91) += i2c-at91.o | 32 | obj-$(CONFIG_I2C_AT91) += i2c-at91.o |
33 | obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o | 33 | obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o |
34 | obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o | ||
34 | obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o | 35 | obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o |
35 | obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o | 36 | obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o |
36 | obj-$(CONFIG_I2C_CPM) += i2c-cpm.o | 37 | obj-$(CONFIG_I2C_CPM) += i2c-cpm.o |
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c new file mode 100644 index 000000000000..ea4b08fc3353 --- /dev/null +++ b/drivers/i2c/busses/i2c-bcm2835.c | |||
@@ -0,0 +1,342 @@ | |||
1 | /* | ||
2 | * BCM2835 master mode driver | ||
3 | * | ||
4 | * This software is licensed under the terms of the GNU General Public | ||
5 | * License version 2, as published by the Free Software Foundation, and | ||
6 | * may be copied, distributed, and modified under those terms. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/clk.h> | ||
15 | #include <linux/completion.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/slab.h> | ||
23 | |||
24 | #define BCM2835_I2C_C 0x0 | ||
25 | #define BCM2835_I2C_S 0x4 | ||
26 | #define BCM2835_I2C_DLEN 0x8 | ||
27 | #define BCM2835_I2C_A 0xc | ||
28 | #define BCM2835_I2C_FIFO 0x10 | ||
29 | #define BCM2835_I2C_DIV 0x14 | ||
30 | #define BCM2835_I2C_DEL 0x18 | ||
31 | #define BCM2835_I2C_CLKT 0x1c | ||
32 | |||
33 | #define BCM2835_I2C_C_READ BIT(0) | ||
34 | #define BCM2835_I2C_C_CLEAR BIT(4) /* bits 4 and 5 both clear */ | ||
35 | #define BCM2835_I2C_C_ST BIT(7) | ||
36 | #define BCM2835_I2C_C_INTD BIT(8) | ||
37 | #define BCM2835_I2C_C_INTT BIT(9) | ||
38 | #define BCM2835_I2C_C_INTR BIT(10) | ||
39 | #define BCM2835_I2C_C_I2CEN BIT(15) | ||
40 | |||
41 | #define BCM2835_I2C_S_TA BIT(0) | ||
42 | #define BCM2835_I2C_S_DONE BIT(1) | ||
43 | #define BCM2835_I2C_S_TXW BIT(2) | ||
44 | #define BCM2835_I2C_S_RXR BIT(3) | ||
45 | #define BCM2835_I2C_S_TXD BIT(4) | ||
46 | #define BCM2835_I2C_S_RXD BIT(5) | ||
47 | #define BCM2835_I2C_S_TXE BIT(6) | ||
48 | #define BCM2835_I2C_S_RXF BIT(7) | ||
49 | #define BCM2835_I2C_S_ERR BIT(8) | ||
50 | #define BCM2835_I2C_S_CLKT BIT(9) | ||
51 | #define BCM2835_I2C_S_LEN BIT(10) /* Fake bit for SW error reporting */ | ||
52 | |||
53 | #define BCM2835_I2C_TIMEOUT (msecs_to_jiffies(1000)) | ||
54 | |||
55 | struct bcm2835_i2c_dev { | ||
56 | struct device *dev; | ||
57 | void __iomem *regs; | ||
58 | struct clk *clk; | ||
59 | int irq; | ||
60 | struct i2c_adapter adapter; | ||
61 | struct completion completion; | ||
62 | u32 msg_err; | ||
63 | u8 *msg_buf; | ||
64 | size_t msg_buf_remaining; | ||
65 | }; | ||
66 | |||
67 | static inline void bcm2835_i2c_writel(struct bcm2835_i2c_dev *i2c_dev, | ||
68 | u32 reg, u32 val) | ||
69 | { | ||
70 | writel(val, i2c_dev->regs + reg); | ||
71 | } | ||
72 | |||
73 | static inline u32 bcm2835_i2c_readl(struct bcm2835_i2c_dev *i2c_dev, u32 reg) | ||
74 | { | ||
75 | return readl(i2c_dev->regs + reg); | ||
76 | } | ||
77 | |||
78 | static void bcm2835_fill_txfifo(struct bcm2835_i2c_dev *i2c_dev) | ||
79 | { | ||
80 | u32 val; | ||
81 | |||
82 | while (i2c_dev->msg_buf_remaining) { | ||
83 | val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S); | ||
84 | if (!(val & BCM2835_I2C_S_TXD)) | ||
85 | break; | ||
86 | bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_FIFO, | ||
87 | *i2c_dev->msg_buf); | ||
88 | i2c_dev->msg_buf++; | ||
89 | i2c_dev->msg_buf_remaining--; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | static void bcm2835_drain_rxfifo(struct bcm2835_i2c_dev *i2c_dev) | ||
94 | { | ||
95 | u32 val; | ||
96 | |||
97 | while (i2c_dev->msg_buf_remaining) { | ||
98 | val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S); | ||
99 | if (!(val & BCM2835_I2C_S_RXD)) | ||
100 | break; | ||
101 | *i2c_dev->msg_buf = bcm2835_i2c_readl(i2c_dev, | ||
102 | BCM2835_I2C_FIFO); | ||
103 | i2c_dev->msg_buf++; | ||
104 | i2c_dev->msg_buf_remaining--; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) | ||
109 | { | ||
110 | struct bcm2835_i2c_dev *i2c_dev = data; | ||
111 | u32 val, err; | ||
112 | |||
113 | val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S); | ||
114 | bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_S, val); | ||
115 | |||
116 | err = val & (BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR); | ||
117 | if (err) { | ||
118 | i2c_dev->msg_err = err; | ||
119 | complete(&i2c_dev->completion); | ||
120 | return IRQ_HANDLED; | ||
121 | } | ||
122 | |||
123 | if (val & BCM2835_I2C_S_RXD) { | ||
124 | bcm2835_drain_rxfifo(i2c_dev); | ||
125 | if (!(val & BCM2835_I2C_S_DONE)) | ||
126 | return IRQ_HANDLED; | ||
127 | } | ||
128 | |||
129 | if (val & BCM2835_I2C_S_DONE) { | ||
130 | if (i2c_dev->msg_buf_remaining) | ||
131 | i2c_dev->msg_err = BCM2835_I2C_S_LEN; | ||
132 | else | ||
133 | i2c_dev->msg_err = 0; | ||
134 | complete(&i2c_dev->completion); | ||
135 | return IRQ_HANDLED; | ||
136 | } | ||
137 | |||
138 | if (val & BCM2835_I2C_S_TXD) { | ||
139 | bcm2835_fill_txfifo(i2c_dev); | ||
140 | return IRQ_HANDLED; | ||
141 | } | ||
142 | |||
143 | return IRQ_NONE; | ||
144 | } | ||
145 | |||
146 | static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev, | ||
147 | struct i2c_msg *msg) | ||
148 | { | ||
149 | u32 c; | ||
150 | int time_left; | ||
151 | |||
152 | i2c_dev->msg_buf = msg->buf; | ||
153 | i2c_dev->msg_buf_remaining = msg->len; | ||
154 | INIT_COMPLETION(i2c_dev->completion); | ||
155 | |||
156 | bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); | ||
157 | |||
158 | if (msg->flags & I2C_M_RD) { | ||
159 | c = BCM2835_I2C_C_READ | BCM2835_I2C_C_INTR; | ||
160 | } else { | ||
161 | c = BCM2835_I2C_C_INTT; | ||
162 | bcm2835_fill_txfifo(i2c_dev); | ||
163 | } | ||
164 | c |= BCM2835_I2C_C_ST | BCM2835_I2C_C_INTD | BCM2835_I2C_C_I2CEN; | ||
165 | |||
166 | bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_A, msg->addr); | ||
167 | bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DLEN, msg->len); | ||
168 | bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c); | ||
169 | |||
170 | time_left = wait_for_completion_timeout(&i2c_dev->completion, | ||
171 | BCM2835_I2C_TIMEOUT); | ||
172 | bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); | ||
173 | if (!time_left) { | ||
174 | dev_err(i2c_dev->dev, "i2c transfer timed out\n"); | ||
175 | return -ETIMEDOUT; | ||
176 | } | ||
177 | |||
178 | if (likely(!i2c_dev->msg_err)) | ||
179 | return 0; | ||
180 | |||
181 | if ((i2c_dev->msg_err & BCM2835_I2C_S_ERR) && | ||
182 | (msg->flags & I2C_M_IGNORE_NAK)) | ||
183 | return 0; | ||
184 | |||
185 | dev_err(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err); | ||
186 | |||
187 | if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) | ||
188 | return -EREMOTEIO; | ||
189 | else | ||
190 | return -EIO; | ||
191 | } | ||
192 | |||
193 | static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], | ||
194 | int num) | ||
195 | { | ||
196 | struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap); | ||
197 | int i; | ||
198 | int ret = 0; | ||
199 | |||
200 | for (i = 0; i < num; i++) { | ||
201 | ret = bcm2835_i2c_xfer_msg(i2c_dev, &msgs[i]); | ||
202 | if (ret) | ||
203 | break; | ||
204 | } | ||
205 | |||
206 | return ret ?: i; | ||
207 | } | ||
208 | |||
209 | static u32 bcm2835_i2c_func(struct i2c_adapter *adap) | ||
210 | { | ||
211 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | ||
212 | } | ||
213 | |||
214 | static const struct i2c_algorithm bcm2835_i2c_algo = { | ||
215 | .master_xfer = bcm2835_i2c_xfer, | ||
216 | .functionality = bcm2835_i2c_func, | ||
217 | }; | ||
218 | |||
219 | static int bcm2835_i2c_probe(struct platform_device *pdev) | ||
220 | { | ||
221 | struct bcm2835_i2c_dev *i2c_dev; | ||
222 | struct resource *mem, *requested, *irq; | ||
223 | u32 bus_clk_rate, divider; | ||
224 | int ret; | ||
225 | struct i2c_adapter *adap; | ||
226 | |||
227 | i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); | ||
228 | if (!i2c_dev) { | ||
229 | dev_err(&pdev->dev, "Cannot allocate i2c_dev\n"); | ||
230 | return -ENOMEM; | ||
231 | } | ||
232 | platform_set_drvdata(pdev, i2c_dev); | ||
233 | i2c_dev->dev = &pdev->dev; | ||
234 | init_completion(&i2c_dev->completion); | ||
235 | |||
236 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
237 | if (!mem) { | ||
238 | dev_err(&pdev->dev, "No mem resource\n"); | ||
239 | return -ENODEV; | ||
240 | } | ||
241 | |||
242 | requested = devm_request_mem_region(&pdev->dev, mem->start, | ||
243 | resource_size(mem), | ||
244 | dev_name(&pdev->dev)); | ||
245 | if (!requested) { | ||
246 | dev_err(&pdev->dev, "Could not claim register region\n"); | ||
247 | return -EBUSY; | ||
248 | } | ||
249 | |||
250 | i2c_dev->regs = devm_ioremap(&pdev->dev, mem->start, | ||
251 | resource_size(mem)); | ||
252 | if (!i2c_dev->regs) { | ||
253 | dev_err(&pdev->dev, "Could not map registers\n"); | ||
254 | return -ENOMEM; | ||
255 | } | ||
256 | |||
257 | i2c_dev->clk = devm_clk_get(&pdev->dev, NULL); | ||
258 | if (IS_ERR(i2c_dev->clk)) { | ||
259 | dev_err(&pdev->dev, "Could not get clock\n"); | ||
260 | return PTR_ERR(i2c_dev->clk); | ||
261 | } | ||
262 | |||
263 | ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency", | ||
264 | &bus_clk_rate); | ||
265 | if (ret < 0) { | ||
266 | dev_warn(&pdev->dev, | ||
267 | "Could not read clock-frequency property\n"); | ||
268 | bus_clk_rate = 100000; | ||
269 | } | ||
270 | |||
271 | divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk), bus_clk_rate); | ||
272 | /* | ||
273 | * Per the datasheet, the register is always interpreted as an even | ||
274 | * number, by rounding down. In other words, the LSB is ignored. So, | ||
275 | * if the LSB is set, increment the divider to avoid any issue. | ||
276 | */ | ||
277 | if (divider & 1) | ||
278 | divider++; | ||
279 | bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider); | ||
280 | |||
281 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
282 | if (!irq) { | ||
283 | dev_err(&pdev->dev, "No IRQ resource\n"); | ||
284 | return -ENODEV; | ||
285 | } | ||
286 | i2c_dev->irq = irq->start; | ||
287 | |||
288 | ret = request_irq(i2c_dev->irq, bcm2835_i2c_isr, IRQF_SHARED, | ||
289 | dev_name(&pdev->dev), i2c_dev); | ||
290 | if (ret) { | ||
291 | dev_err(&pdev->dev, "Could not request IRQ\n"); | ||
292 | return -ENODEV; | ||
293 | } | ||
294 | |||
295 | adap = &i2c_dev->adapter; | ||
296 | i2c_set_adapdata(adap, i2c_dev); | ||
297 | adap->owner = THIS_MODULE; | ||
298 | adap->class = I2C_CLASS_HWMON; | ||
299 | strlcpy(adap->name, "bcm2835 I2C adapter", sizeof(adap->name)); | ||
300 | adap->algo = &bcm2835_i2c_algo; | ||
301 | adap->dev.parent = &pdev->dev; | ||
302 | |||
303 | bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, 0); | ||
304 | |||
305 | ret = i2c_add_adapter(adap); | ||
306 | if (ret) | ||
307 | free_irq(i2c_dev->irq, i2c_dev); | ||
308 | |||
309 | return ret; | ||
310 | } | ||
311 | |||
312 | static int bcm2835_i2c_remove(struct platform_device *pdev) | ||
313 | { | ||
314 | struct bcm2835_i2c_dev *i2c_dev = platform_get_drvdata(pdev); | ||
315 | |||
316 | free_irq(i2c_dev->irq, i2c_dev); | ||
317 | i2c_del_adapter(&i2c_dev->adapter); | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | static const struct of_device_id bcm2835_i2c_of_match[] = { | ||
323 | { .compatible = "brcm,bcm2835-i2c" }, | ||
324 | {}, | ||
325 | }; | ||
326 | MODULE_DEVICE_TABLE(of, bcm2835_i2c_of_match); | ||
327 | |||
328 | static struct platform_driver bcm2835_i2c_driver = { | ||
329 | .probe = bcm2835_i2c_probe, | ||
330 | .remove = bcm2835_i2c_remove, | ||
331 | .driver = { | ||
332 | .name = "i2c-bcm2835", | ||
333 | .owner = THIS_MODULE, | ||
334 | .of_match_table = bcm2835_i2c_of_match, | ||
335 | }, | ||
336 | }; | ||
337 | module_platform_driver(bcm2835_i2c_driver); | ||
338 | |||
339 | MODULE_AUTHOR("Stephen Warren <swarren@wwwdotorg.org>"); | ||
340 | MODULE_DESCRIPTION("BCM2835 I2C bus adapter"); | ||
341 | MODULE_LICENSE("GPL v2"); | ||
342 | MODULE_ALIAS("platform:i2c-bcm2835"); | ||