aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorStephen Warren <swarren@wwwdotorg.org>2013-02-11 21:47:56 -0500
committerWolfram Sang <wolfram@the-dreams.de>2013-02-12 05:33:59 -0500
commitf3b54b9a066edeac5c06e1cdcd82e1cb1224aaef (patch)
treea98bbfac8ccd16ac6535107a066bb78a226adc7d /drivers/i2c
parentcb7f07a4c58659d971a60ebbb8547f6611278622 (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/Kconfig12
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-bcm2835.c342
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
333config 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
333config I2C_BLACKFIN_TWI 345config 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
32obj-$(CONFIG_I2C_AT91) += i2c-at91.o 32obj-$(CONFIG_I2C_AT91) += i2c-at91.o
33obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o 33obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
34obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o
34obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o 35obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
35obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o 36obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
36obj-$(CONFIG_I2C_CPM) += i2c-cpm.o 37obj-$(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
55struct 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
67static 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
73static inline u32 bcm2835_i2c_readl(struct bcm2835_i2c_dev *i2c_dev, u32 reg)
74{
75 return readl(i2c_dev->regs + reg);
76}
77
78static 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
93static 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
108static 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
146static 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
193static 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
209static u32 bcm2835_i2c_func(struct i2c_adapter *adap)
210{
211 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
212}
213
214static const struct i2c_algorithm bcm2835_i2c_algo = {
215 .master_xfer = bcm2835_i2c_xfer,
216 .functionality = bcm2835_i2c_func,
217};
218
219static 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
312static 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
322static const struct of_device_id bcm2835_i2c_of_match[] = {
323 { .compatible = "brcm,bcm2835-i2c" },
324 {},
325};
326MODULE_DEVICE_TABLE(of, bcm2835_i2c_of_match);
327
328static 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};
337module_platform_driver(bcm2835_i2c_driver);
338
339MODULE_AUTHOR("Stephen Warren <swarren@wwwdotorg.org>");
340MODULE_DESCRIPTION("BCM2835 I2C bus adapter");
341MODULE_LICENSE("GPL v2");
342MODULE_ALIAS("platform:i2c-bcm2835");