diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/i2c/busses/i2c-omap.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/i2c/busses/i2c-omap.c')
-rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 118 |
1 files changed, 77 insertions, 41 deletions
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 827da0858136..389ac6032a7b 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/platform_device.h> | 37 | #include <linux/platform_device.h> |
38 | #include <linux/clk.h> | 38 | #include <linux/clk.h> |
39 | #include <linux/io.h> | 39 | #include <linux/io.h> |
40 | #include <linux/slab.h> | ||
40 | 41 | ||
41 | /* I2C controller revisions */ | 42 | /* I2C controller revisions */ |
42 | #define OMAP_I2C_REV_2 0x20 | 43 | #define OMAP_I2C_REV_2 0x20 |
@@ -49,24 +50,24 @@ | |||
49 | #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) | 50 | #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) |
50 | 51 | ||
51 | #define OMAP_I2C_REV_REG 0x00 | 52 | #define OMAP_I2C_REV_REG 0x00 |
52 | #define OMAP_I2C_IE_REG 0x04 | 53 | #define OMAP_I2C_IE_REG 0x01 |
53 | #define OMAP_I2C_STAT_REG 0x08 | 54 | #define OMAP_I2C_STAT_REG 0x02 |
54 | #define OMAP_I2C_IV_REG 0x0c | 55 | #define OMAP_I2C_IV_REG 0x03 |
55 | /* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */ | 56 | /* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */ |
56 | #define OMAP_I2C_WE_REG 0x0c | 57 | #define OMAP_I2C_WE_REG 0x03 |
57 | #define OMAP_I2C_SYSS_REG 0x10 | 58 | #define OMAP_I2C_SYSS_REG 0x04 |
58 | #define OMAP_I2C_BUF_REG 0x14 | 59 | #define OMAP_I2C_BUF_REG 0x05 |
59 | #define OMAP_I2C_CNT_REG 0x18 | 60 | #define OMAP_I2C_CNT_REG 0x06 |
60 | #define OMAP_I2C_DATA_REG 0x1c | 61 | #define OMAP_I2C_DATA_REG 0x07 |
61 | #define OMAP_I2C_SYSC_REG 0x20 | 62 | #define OMAP_I2C_SYSC_REG 0x08 |
62 | #define OMAP_I2C_CON_REG 0x24 | 63 | #define OMAP_I2C_CON_REG 0x09 |
63 | #define OMAP_I2C_OA_REG 0x28 | 64 | #define OMAP_I2C_OA_REG 0x0a |
64 | #define OMAP_I2C_SA_REG 0x2c | 65 | #define OMAP_I2C_SA_REG 0x0b |
65 | #define OMAP_I2C_PSC_REG 0x30 | 66 | #define OMAP_I2C_PSC_REG 0x0c |
66 | #define OMAP_I2C_SCLL_REG 0x34 | 67 | #define OMAP_I2C_SCLL_REG 0x0d |
67 | #define OMAP_I2C_SCLH_REG 0x38 | 68 | #define OMAP_I2C_SCLH_REG 0x0e |
68 | #define OMAP_I2C_SYSTEST_REG 0x3c | 69 | #define OMAP_I2C_SYSTEST_REG 0x0f |
69 | #define OMAP_I2C_BUFSTAT_REG 0x40 | 70 | #define OMAP_I2C_BUFSTAT_REG 0x10 |
70 | 71 | ||
71 | /* I2C Interrupt Enable Register (OMAP_I2C_IE): */ | 72 | /* I2C Interrupt Enable Register (OMAP_I2C_IE): */ |
72 | #define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer drain int enable */ | 73 | #define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer drain int enable */ |
@@ -161,6 +162,7 @@ struct omap_i2c_dev { | |||
161 | struct device *dev; | 162 | struct device *dev; |
162 | void __iomem *base; /* virtual */ | 163 | void __iomem *base; /* virtual */ |
163 | int irq; | 164 | int irq; |
165 | int reg_shift; /* bit shift for I2C register addresses */ | ||
164 | struct clk *iclk; /* Interface clock */ | 166 | struct clk *iclk; /* Interface clock */ |
165 | struct clk *fclk; /* Functional clock */ | 167 | struct clk *fclk; /* Functional clock */ |
166 | struct completion cmd_complete; | 168 | struct completion cmd_complete; |
@@ -178,17 +180,23 @@ struct omap_i2c_dev { | |||
178 | unsigned b_hw:1; /* bad h/w fixes */ | 180 | unsigned b_hw:1; /* bad h/w fixes */ |
179 | unsigned idle:1; | 181 | unsigned idle:1; |
180 | u16 iestate; /* Saved interrupt register */ | 182 | u16 iestate; /* Saved interrupt register */ |
183 | u16 pscstate; | ||
184 | u16 scllstate; | ||
185 | u16 sclhstate; | ||
186 | u16 bufstate; | ||
187 | u16 syscstate; | ||
188 | u16 westate; | ||
181 | }; | 189 | }; |
182 | 190 | ||
183 | static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev, | 191 | static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev, |
184 | int reg, u16 val) | 192 | int reg, u16 val) |
185 | { | 193 | { |
186 | __raw_writew(val, i2c_dev->base + reg); | 194 | __raw_writew(val, i2c_dev->base + (reg << i2c_dev->reg_shift)); |
187 | } | 195 | } |
188 | 196 | ||
189 | static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg) | 197 | static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg) |
190 | { | 198 | { |
191 | return __raw_readw(i2c_dev->base + reg); | 199 | return __raw_readw(i2c_dev->base + (reg << i2c_dev->reg_shift)); |
192 | } | 200 | } |
193 | 201 | ||
194 | static int __init omap_i2c_get_clocks(struct omap_i2c_dev *dev) | 202 | static int __init omap_i2c_get_clocks(struct omap_i2c_dev *dev) |
@@ -230,7 +238,22 @@ static void omap_i2c_unidle(struct omap_i2c_dev *dev) | |||
230 | 238 | ||
231 | clk_enable(dev->iclk); | 239 | clk_enable(dev->iclk); |
232 | clk_enable(dev->fclk); | 240 | clk_enable(dev->fclk); |
241 | if (cpu_is_omap34xx()) { | ||
242 | omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); | ||
243 | omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate); | ||
244 | omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate); | ||
245 | omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate); | ||
246 | omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, dev->bufstate); | ||
247 | omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, dev->syscstate); | ||
248 | omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate); | ||
249 | omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); | ||
250 | } | ||
233 | dev->idle = 0; | 251 | dev->idle = 0; |
252 | |||
253 | /* | ||
254 | * Don't write to this register if the IE state is 0 as it can | ||
255 | * cause deadlock. | ||
256 | */ | ||
234 | if (dev->iestate) | 257 | if (dev->iestate) |
235 | omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate); | 258 | omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate); |
236 | } | 259 | } |
@@ -258,13 +281,18 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev) | |||
258 | 281 | ||
259 | static int omap_i2c_init(struct omap_i2c_dev *dev) | 282 | static int omap_i2c_init(struct omap_i2c_dev *dev) |
260 | { | 283 | { |
261 | u16 psc = 0, scll = 0, sclh = 0; | 284 | u16 psc = 0, scll = 0, sclh = 0, buf = 0; |
262 | u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0; | 285 | u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0; |
263 | unsigned long fclk_rate = 12000000; | 286 | unsigned long fclk_rate = 12000000; |
264 | unsigned long timeout; | 287 | unsigned long timeout; |
265 | unsigned long internal_clk = 0; | 288 | unsigned long internal_clk = 0; |
266 | 289 | ||
267 | if (dev->rev >= OMAP_I2C_REV_2) { | 290 | if (dev->rev >= OMAP_I2C_REV_2) { |
291 | /* Disable I2C controller before soft reset */ | ||
292 | omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, | ||
293 | omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) & | ||
294 | ~(OMAP_I2C_CON_EN)); | ||
295 | |||
268 | omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, SYSC_SOFTRESET_MASK); | 296 | omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, SYSC_SOFTRESET_MASK); |
269 | /* For some reason we need to set the EN bit before the | 297 | /* For some reason we need to set the EN bit before the |
270 | * reset done bit gets set. */ | 298 | * reset done bit gets set. */ |
@@ -287,24 +315,22 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) | |||
287 | SYSC_AUTOIDLE_MASK); | 315 | SYSC_AUTOIDLE_MASK); |
288 | 316 | ||
289 | } else if (dev->rev >= OMAP_I2C_REV_ON_3430) { | 317 | } else if (dev->rev >= OMAP_I2C_REV_ON_3430) { |
290 | u32 v; | 318 | dev->syscstate = SYSC_AUTOIDLE_MASK; |
291 | 319 | dev->syscstate |= SYSC_ENAWAKEUP_MASK; | |
292 | v = SYSC_AUTOIDLE_MASK; | 320 | dev->syscstate |= (SYSC_IDLEMODE_SMART << |
293 | v |= SYSC_ENAWAKEUP_MASK; | ||
294 | v |= (SYSC_IDLEMODE_SMART << | ||
295 | __ffs(SYSC_SIDLEMODE_MASK)); | 321 | __ffs(SYSC_SIDLEMODE_MASK)); |
296 | v |= (SYSC_CLOCKACTIVITY_FCLK << | 322 | dev->syscstate |= (SYSC_CLOCKACTIVITY_FCLK << |
297 | __ffs(SYSC_CLOCKACTIVITY_MASK)); | 323 | __ffs(SYSC_CLOCKACTIVITY_MASK)); |
298 | 324 | ||
299 | omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, v); | 325 | omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, |
326 | dev->syscstate); | ||
300 | /* | 327 | /* |
301 | * Enabling all wakup sources to stop I2C freezing on | 328 | * Enabling all wakup sources to stop I2C freezing on |
302 | * WFI instruction. | 329 | * WFI instruction. |
303 | * REVISIT: Some wkup sources might not be needed. | 330 | * REVISIT: Some wkup sources might not be needed. |
304 | */ | 331 | */ |
305 | omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, | 332 | dev->westate = OMAP_I2C_WE_ALL; |
306 | OMAP_I2C_WE_ALL); | 333 | omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate); |
307 | |||
308 | } | 334 | } |
309 | } | 335 | } |
310 | omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); | 336 | omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); |
@@ -394,23 +420,28 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) | |||
394 | omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll); | 420 | omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll); |
395 | omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh); | 421 | omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh); |
396 | 422 | ||
397 | if (dev->fifo_size) | 423 | if (dev->fifo_size) { |
398 | /* Note: setup required fifo size - 1 */ | 424 | /* Note: setup required fifo size - 1. RTRSH and XTRSH */ |
399 | omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, | 425 | buf = (dev->fifo_size - 1) << 8 | OMAP_I2C_BUF_RXFIF_CLR | |
400 | (dev->fifo_size - 1) << 8 | /* RTRSH */ | 426 | (dev->fifo_size - 1) | OMAP_I2C_BUF_TXFIF_CLR; |
401 | OMAP_I2C_BUF_RXFIF_CLR | | 427 | omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf); |
402 | (dev->fifo_size - 1) | /* XTRSH */ | 428 | } |
403 | OMAP_I2C_BUF_TXFIF_CLR); | ||
404 | 429 | ||
405 | /* Take the I2C module out of reset: */ | 430 | /* Take the I2C module out of reset: */ |
406 | omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); | 431 | omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); |
407 | 432 | ||
408 | /* Enable interrupts */ | 433 | /* Enable interrupts */ |
409 | omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, | 434 | dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY | |
410 | (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY | | ||
411 | OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK | | 435 | OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK | |
412 | OMAP_I2C_IE_AL) | ((dev->fifo_size) ? | 436 | OMAP_I2C_IE_AL) | ((dev->fifo_size) ? |
413 | (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0)); | 437 | (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0); |
438 | omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate); | ||
439 | if (cpu_is_omap34xx()) { | ||
440 | dev->pscstate = psc; | ||
441 | dev->scllstate = scll; | ||
442 | dev->sclhstate = sclh; | ||
443 | dev->bufstate = buf; | ||
444 | } | ||
414 | return 0; | 445 | return 0; |
415 | } | 446 | } |
416 | 447 | ||
@@ -820,7 +851,7 @@ static const struct i2c_algorithm omap_i2c_algo = { | |||
820 | .functionality = omap_i2c_func, | 851 | .functionality = omap_i2c_func, |
821 | }; | 852 | }; |
822 | 853 | ||
823 | static int __init | 854 | static int __devinit |
824 | omap_i2c_probe(struct platform_device *pdev) | 855 | omap_i2c_probe(struct platform_device *pdev) |
825 | { | 856 | { |
826 | struct omap_i2c_dev *dev; | 857 | struct omap_i2c_dev *dev; |
@@ -872,6 +903,11 @@ omap_i2c_probe(struct platform_device *pdev) | |||
872 | 903 | ||
873 | platform_set_drvdata(pdev, dev); | 904 | platform_set_drvdata(pdev, dev); |
874 | 905 | ||
906 | if (cpu_is_omap7xx()) | ||
907 | dev->reg_shift = 1; | ||
908 | else | ||
909 | dev->reg_shift = 2; | ||
910 | |||
875 | if ((r = omap_i2c_get_clocks(dev)) != 0) | 911 | if ((r = omap_i2c_get_clocks(dev)) != 0) |
876 | goto err_iounmap; | 912 | goto err_iounmap; |
877 | 913 | ||