diff options
-rw-r--r-- | Documentation/devicetree/bindings/i2c/i2c-digicolor.txt | 25 | ||||
-rw-r--r-- | drivers/i2c/busses/Kconfig | 9 | ||||
-rw-r--r-- | drivers/i2c/busses/Makefile | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-digicolor.c | 385 |
4 files changed, 420 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/i2c/i2c-digicolor.txt b/Documentation/devicetree/bindings/i2c/i2c-digicolor.txt new file mode 100644 index 000000000000..457a098d4f7e --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-digicolor.txt | |||
@@ -0,0 +1,25 @@ | |||
1 | Conexant Digicolor I2C controller | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: must be "cnxt,cx92755-i2c" | ||
5 | - reg: physical address and length of the device registers | ||
6 | - interrupts: a single interrupt specifier | ||
7 | - clocks: clock for the device | ||
8 | - #address-cells: should be <1> | ||
9 | - #size-cells: should be <0> | ||
10 | |||
11 | Optional properties: | ||
12 | - clock-frequency: the desired I2C bus clock frequency in Hz; in | ||
13 | absence of this property the default value is used (100 kHz). | ||
14 | |||
15 | Example: | ||
16 | |||
17 | i2c: i2c@f0000120 { | ||
18 | compatible = "cnxt,cx92755-i2c"; | ||
19 | reg = <0xf0000120 0x10>; | ||
20 | interrupts = <28>; | ||
21 | clocks = <&main_clk>; | ||
22 | clock-frequency = <100000>; | ||
23 | #address-cells = <1>; | ||
24 | #size-cells = <0>; | ||
25 | }; | ||
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 22da9c2ffa22..db09881614b7 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
@@ -485,6 +485,15 @@ config I2C_DESIGNWARE_BAYTRAIL | |||
485 | the platform firmware controlling it. You should say Y if running on | 485 | the platform firmware controlling it. You should say Y if running on |
486 | a BayTrail system using the AXP288. | 486 | a BayTrail system using the AXP288. |
487 | 487 | ||
488 | config I2C_DIGICOLOR | ||
489 | tristate "Conexant Digicolor I2C driver" | ||
490 | depends on ARCH_DIGICOLOR | ||
491 | help | ||
492 | Support for Conexant Digicolor SoCs (CX92755) I2C controller driver. | ||
493 | |||
494 | This driver can also be built as a module. If so, the module | ||
495 | will be called i2c-digicolor. | ||
496 | |||
488 | config I2C_EFM32 | 497 | config I2C_EFM32 |
489 | tristate "EFM32 I2C controller" | 498 | tristate "EFM32 I2C controller" |
490 | depends on ARCH_EFM32 || COMPILE_TEST | 499 | depends on ARCH_EFM32 || COMPILE_TEST |
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 3638feb6677e..4413f09996cb 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile | |||
@@ -45,6 +45,7 @@ i2c-designware-platform-objs := i2c-designware-platdrv.o | |||
45 | i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o | 45 | i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o |
46 | obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o | 46 | obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o |
47 | i2c-designware-pci-objs := i2c-designware-pcidrv.o | 47 | i2c-designware-pci-objs := i2c-designware-pcidrv.o |
48 | obj-$(CONFIG_I2C_DIGICOLOR) += i2c-digicolor.o | ||
48 | obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o | 49 | obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o |
49 | obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o | 50 | obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o |
50 | obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o | 51 | obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o |
diff --git a/drivers/i2c/busses/i2c-digicolor.c b/drivers/i2c/busses/i2c-digicolor.c new file mode 100644 index 000000000000..03f1e5549896 --- /dev/null +++ b/drivers/i2c/busses/i2c-digicolor.c | |||
@@ -0,0 +1,385 @@ | |||
1 | /* | ||
2 | * I2C bus driver for Conexant Digicolor SoCs | ||
3 | * | ||
4 | * Author: Baruch Siach <baruch@tkos.co.il> | ||
5 | * | ||
6 | * Copyright (C) 2015 Paradox Innovation Ltd. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/clk.h> | ||
14 | #include <linux/completion.h> | ||
15 | #include <linux/i2c.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/clk.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/of.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | |||
25 | #define DEFAULT_FREQ 100000 | ||
26 | #define TIMEOUT_MS 100 | ||
27 | |||
28 | #define II_CONTROL 0x0 | ||
29 | #define II_CONTROL_LOCAL_RESET BIT(0) | ||
30 | |||
31 | #define II_CLOCKTIME 0x1 | ||
32 | |||
33 | #define II_COMMAND 0x2 | ||
34 | #define II_CMD_START 1 | ||
35 | #define II_CMD_RESTART 2 | ||
36 | #define II_CMD_SEND_ACK 3 | ||
37 | #define II_CMD_GET_ACK 6 | ||
38 | #define II_CMD_GET_NOACK 7 | ||
39 | #define II_CMD_STOP 10 | ||
40 | #define II_COMMAND_GO BIT(7) | ||
41 | #define II_COMMAND_COMPLETION_STATUS(r) (((r) >> 5) & 3) | ||
42 | #define II_CMD_STATUS_NORMAL 0 | ||
43 | #define II_CMD_STATUS_ACK_GOOD 1 | ||
44 | #define II_CMD_STATUS_ACK_BAD 2 | ||
45 | #define II_CMD_STATUS_ABORT 3 | ||
46 | |||
47 | #define II_DATA 0x3 | ||
48 | #define II_INTFLAG_CLEAR 0x8 | ||
49 | #define II_INTENABLE 0xa | ||
50 | |||
51 | struct dc_i2c { | ||
52 | struct i2c_adapter adap; | ||
53 | struct device *dev; | ||
54 | void __iomem *regs; | ||
55 | struct clk *clk; | ||
56 | unsigned int frequency; | ||
57 | |||
58 | struct i2c_msg *msg; | ||
59 | unsigned int msgbuf_ptr; | ||
60 | int last; | ||
61 | spinlock_t lock; | ||
62 | struct completion done; | ||
63 | int state; | ||
64 | int error; | ||
65 | }; | ||
66 | |||
67 | enum { | ||
68 | STATE_IDLE, | ||
69 | STATE_START, | ||
70 | STATE_ADDR, | ||
71 | STATE_WRITE, | ||
72 | STATE_READ, | ||
73 | STATE_STOP, | ||
74 | }; | ||
75 | |||
76 | static void dc_i2c_cmd(struct dc_i2c *i2c, u8 cmd) | ||
77 | { | ||
78 | writeb_relaxed(cmd | II_COMMAND_GO, i2c->regs + II_COMMAND); | ||
79 | } | ||
80 | |||
81 | static u8 dc_i2c_addr_cmd(struct i2c_msg *msg) | ||
82 | { | ||
83 | u8 addr = (msg->addr & 0x7f) << 1; | ||
84 | |||
85 | if (msg->flags & I2C_M_RD) | ||
86 | addr |= 1; | ||
87 | |||
88 | return addr; | ||
89 | } | ||
90 | |||
91 | static void dc_i2c_data(struct dc_i2c *i2c, u8 data) | ||
92 | { | ||
93 | writeb_relaxed(data, i2c->regs + II_DATA); | ||
94 | } | ||
95 | |||
96 | static void dc_i2c_write_byte(struct dc_i2c *i2c, u8 byte) | ||
97 | { | ||
98 | dc_i2c_data(i2c, byte); | ||
99 | dc_i2c_cmd(i2c, II_CMD_SEND_ACK); | ||
100 | } | ||
101 | |||
102 | static void dc_i2c_write_buf(struct dc_i2c *i2c) | ||
103 | { | ||
104 | dc_i2c_write_byte(i2c, i2c->msg->buf[i2c->msgbuf_ptr++]); | ||
105 | } | ||
106 | |||
107 | static void dc_i2c_next_read(struct dc_i2c *i2c) | ||
108 | { | ||
109 | bool last = (i2c->msgbuf_ptr + 1 == i2c->msg->len); | ||
110 | |||
111 | dc_i2c_cmd(i2c, last ? II_CMD_GET_NOACK : II_CMD_GET_ACK); | ||
112 | } | ||
113 | |||
114 | static void dc_i2c_stop(struct dc_i2c *i2c) | ||
115 | { | ||
116 | i2c->state = STATE_STOP; | ||
117 | if (i2c->last) | ||
118 | dc_i2c_cmd(i2c, II_CMD_STOP); | ||
119 | else | ||
120 | complete(&i2c->done); | ||
121 | } | ||
122 | |||
123 | static u8 dc_i2c_read_byte(struct dc_i2c *i2c) | ||
124 | { | ||
125 | return readb_relaxed(i2c->regs + II_DATA); | ||
126 | } | ||
127 | |||
128 | static void dc_i2c_read_buf(struct dc_i2c *i2c) | ||
129 | { | ||
130 | i2c->msg->buf[i2c->msgbuf_ptr++] = dc_i2c_read_byte(i2c); | ||
131 | dc_i2c_next_read(i2c); | ||
132 | } | ||
133 | |||
134 | static void dc_i2c_set_irq(struct dc_i2c *i2c, int enable) | ||
135 | { | ||
136 | if (enable) | ||
137 | writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR); | ||
138 | writeb_relaxed(!!enable, i2c->regs + II_INTENABLE); | ||
139 | } | ||
140 | |||
141 | static int dc_i2c_cmd_status(struct dc_i2c *i2c) | ||
142 | { | ||
143 | u8 cmd = readb_relaxed(i2c->regs + II_COMMAND); | ||
144 | |||
145 | return II_COMMAND_COMPLETION_STATUS(cmd); | ||
146 | } | ||
147 | |||
148 | static void dc_i2c_start_msg(struct dc_i2c *i2c, int first) | ||
149 | { | ||
150 | struct i2c_msg *msg = i2c->msg; | ||
151 | |||
152 | if (!(msg->flags & I2C_M_NOSTART)) { | ||
153 | i2c->state = STATE_START; | ||
154 | dc_i2c_cmd(i2c, first ? II_CMD_START : II_CMD_RESTART); | ||
155 | } else if (msg->flags & I2C_M_RD) { | ||
156 | i2c->state = STATE_READ; | ||
157 | dc_i2c_next_read(i2c); | ||
158 | } else { | ||
159 | i2c->state = STATE_WRITE; | ||
160 | dc_i2c_write_buf(i2c); | ||
161 | } | ||
162 | } | ||
163 | |||
164 | static irqreturn_t dc_i2c_irq(int irq, void *dev_id) | ||
165 | { | ||
166 | struct dc_i2c *i2c = dev_id; | ||
167 | int cmd_status = dc_i2c_cmd_status(i2c); | ||
168 | unsigned long flags; | ||
169 | u8 addr_cmd; | ||
170 | |||
171 | writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR); | ||
172 | |||
173 | spin_lock_irqsave(&i2c->lock, flags); | ||
174 | |||
175 | if (cmd_status == II_CMD_STATUS_ACK_BAD | ||
176 | || cmd_status == II_CMD_STATUS_ABORT) { | ||
177 | i2c->error = -EIO; | ||
178 | complete(&i2c->done); | ||
179 | goto out; | ||
180 | } | ||
181 | |||
182 | switch (i2c->state) { | ||
183 | case STATE_START: | ||
184 | addr_cmd = dc_i2c_addr_cmd(i2c->msg); | ||
185 | dc_i2c_write_byte(i2c, addr_cmd); | ||
186 | i2c->state = STATE_ADDR; | ||
187 | break; | ||
188 | case STATE_ADDR: | ||
189 | if (i2c->msg->flags & I2C_M_RD) { | ||
190 | dc_i2c_next_read(i2c); | ||
191 | i2c->state = STATE_READ; | ||
192 | break; | ||
193 | } | ||
194 | i2c->state = STATE_WRITE; | ||
195 | /* fall through */ | ||
196 | case STATE_WRITE: | ||
197 | if (i2c->msgbuf_ptr < i2c->msg->len) | ||
198 | dc_i2c_write_buf(i2c); | ||
199 | else | ||
200 | dc_i2c_stop(i2c); | ||
201 | break; | ||
202 | case STATE_READ: | ||
203 | if (i2c->msgbuf_ptr < i2c->msg->len) | ||
204 | dc_i2c_read_buf(i2c); | ||
205 | else | ||
206 | dc_i2c_stop(i2c); | ||
207 | break; | ||
208 | case STATE_STOP: | ||
209 | i2c->state = STATE_IDLE; | ||
210 | complete(&i2c->done); | ||
211 | break; | ||
212 | } | ||
213 | |||
214 | out: | ||
215 | spin_unlock_irqrestore(&i2c->lock, flags); | ||
216 | return IRQ_HANDLED; | ||
217 | } | ||
218 | |||
219 | static int dc_i2c_xfer_msg(struct dc_i2c *i2c, struct i2c_msg *msg, int first, | ||
220 | int last) | ||
221 | { | ||
222 | unsigned long timeout = msecs_to_jiffies(TIMEOUT_MS); | ||
223 | unsigned long flags; | ||
224 | |||
225 | spin_lock_irqsave(&i2c->lock, flags); | ||
226 | i2c->msg = msg; | ||
227 | i2c->msgbuf_ptr = 0; | ||
228 | i2c->last = last; | ||
229 | i2c->error = 0; | ||
230 | |||
231 | reinit_completion(&i2c->done); | ||
232 | dc_i2c_set_irq(i2c, 1); | ||
233 | dc_i2c_start_msg(i2c, first); | ||
234 | spin_unlock_irqrestore(&i2c->lock, flags); | ||
235 | |||
236 | timeout = wait_for_completion_timeout(&i2c->done, timeout); | ||
237 | dc_i2c_set_irq(i2c, 0); | ||
238 | if (timeout == 0) { | ||
239 | i2c->state = STATE_IDLE; | ||
240 | return -ETIMEDOUT; | ||
241 | } | ||
242 | |||
243 | if (i2c->error) | ||
244 | return i2c->error; | ||
245 | |||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static int dc_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | ||
250 | { | ||
251 | struct dc_i2c *i2c = adap->algo_data; | ||
252 | int i, ret; | ||
253 | |||
254 | for (i = 0; i < num; i++) { | ||
255 | ret = dc_i2c_xfer_msg(i2c, &msgs[i], i == 0, i == num - 1); | ||
256 | if (ret) | ||
257 | return ret; | ||
258 | } | ||
259 | |||
260 | return num; | ||
261 | } | ||
262 | |||
263 | static int dc_i2c_init_hw(struct dc_i2c *i2c) | ||
264 | { | ||
265 | unsigned long clk_rate = clk_get_rate(i2c->clk); | ||
266 | unsigned int clocktime; | ||
267 | |||
268 | writeb_relaxed(II_CONTROL_LOCAL_RESET, i2c->regs + II_CONTROL); | ||
269 | udelay(100); | ||
270 | writeb_relaxed(0, i2c->regs + II_CONTROL); | ||
271 | udelay(100); | ||
272 | |||
273 | clocktime = DIV_ROUND_UP(clk_rate, 64 * i2c->frequency); | ||
274 | if (clocktime < 1 || clocktime > 0xff) { | ||
275 | dev_err(i2c->dev, "can't set bus speed of %u Hz\n", | ||
276 | i2c->frequency); | ||
277 | return -EINVAL; | ||
278 | } | ||
279 | writeb_relaxed(clocktime - 1, i2c->regs + II_CLOCKTIME); | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static u32 dc_i2c_func(struct i2c_adapter *adap) | ||
285 | { | ||
286 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART; | ||
287 | } | ||
288 | |||
289 | static const struct i2c_algorithm dc_i2c_algorithm = { | ||
290 | .master_xfer = dc_i2c_xfer, | ||
291 | .functionality = dc_i2c_func, | ||
292 | }; | ||
293 | |||
294 | static int dc_i2c_probe(struct platform_device *pdev) | ||
295 | { | ||
296 | struct device_node *np = pdev->dev.of_node; | ||
297 | struct dc_i2c *i2c; | ||
298 | struct resource *r; | ||
299 | int ret = 0, irq; | ||
300 | |||
301 | i2c = devm_kzalloc(&pdev->dev, sizeof(struct dc_i2c), GFP_KERNEL); | ||
302 | if (!i2c) | ||
303 | return -ENOMEM; | ||
304 | |||
305 | if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", | ||
306 | &i2c->frequency)) | ||
307 | i2c->frequency = DEFAULT_FREQ; | ||
308 | |||
309 | i2c->dev = &pdev->dev; | ||
310 | platform_set_drvdata(pdev, i2c); | ||
311 | |||
312 | spin_lock_init(&i2c->lock); | ||
313 | init_completion(&i2c->done); | ||
314 | |||
315 | i2c->clk = devm_clk_get(&pdev->dev, NULL); | ||
316 | if (IS_ERR(i2c->clk)) | ||
317 | return PTR_ERR(i2c->clk); | ||
318 | |||
319 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
320 | i2c->regs = devm_ioremap_resource(&pdev->dev, r); | ||
321 | if (IS_ERR(i2c->regs)) | ||
322 | return PTR_ERR(i2c->regs); | ||
323 | |||
324 | irq = platform_get_irq(pdev, 0); | ||
325 | if (irq < 0) | ||
326 | return irq; | ||
327 | |||
328 | ret = devm_request_irq(&pdev->dev, irq, dc_i2c_irq, 0, | ||
329 | dev_name(&pdev->dev), i2c); | ||
330 | if (ret < 0) | ||
331 | return ret; | ||
332 | |||
333 | strlcpy(i2c->adap.name, "Conexant Digicolor I2C adapter", | ||
334 | sizeof(i2c->adap.name)); | ||
335 | i2c->adap.owner = THIS_MODULE; | ||
336 | i2c->adap.algo = &dc_i2c_algorithm; | ||
337 | i2c->adap.dev.parent = &pdev->dev; | ||
338 | i2c->adap.dev.of_node = np; | ||
339 | i2c->adap.algo_data = i2c; | ||
340 | |||
341 | ret = dc_i2c_init_hw(i2c); | ||
342 | if (ret) | ||
343 | return ret; | ||
344 | |||
345 | ret = clk_prepare_enable(i2c->clk); | ||
346 | if (ret < 0) | ||
347 | return ret; | ||
348 | |||
349 | ret = i2c_add_adapter(&i2c->adap); | ||
350 | if (ret < 0) { | ||
351 | clk_unprepare(i2c->clk); | ||
352 | return ret; | ||
353 | } | ||
354 | |||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | static int dc_i2c_remove(struct platform_device *pdev) | ||
359 | { | ||
360 | struct dc_i2c *i2c = platform_get_drvdata(pdev); | ||
361 | |||
362 | i2c_del_adapter(&i2c->adap); | ||
363 | clk_disable_unprepare(i2c->clk); | ||
364 | |||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | static const struct of_device_id dc_i2c_match[] = { | ||
369 | { .compatible = "cnxt,cx92755-i2c" }, | ||
370 | { }, | ||
371 | }; | ||
372 | |||
373 | static struct platform_driver dc_i2c_driver = { | ||
374 | .probe = dc_i2c_probe, | ||
375 | .remove = dc_i2c_remove, | ||
376 | .driver = { | ||
377 | .name = "digicolor-i2c", | ||
378 | .of_match_table = dc_i2c_match, | ||
379 | }, | ||
380 | }; | ||
381 | module_platform_driver(dc_i2c_driver); | ||
382 | |||
383 | MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); | ||
384 | MODULE_DESCRIPTION("Conexant Digicolor I2C master driver"); | ||
385 | MODULE_LICENSE("GPL v2"); | ||