diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-imx.c')
-rw-r--r-- | drivers/i2c/busses/i2c-imx.c | 77 |
1 files changed, 52 insertions, 25 deletions
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index dc9f2ec22a29..ce31196bb5e7 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c | |||
@@ -108,9 +108,6 @@ | |||
108 | #define I2CR_IEN_OPCODE_0 0x0 | 108 | #define I2CR_IEN_OPCODE_0 0x0 |
109 | #define I2CR_IEN_OPCODE_1 I2CR_IEN | 109 | #define I2CR_IEN_OPCODE_1 I2CR_IEN |
110 | 110 | ||
111 | #define IMX_I2SR_CLR_OPCODE I2SR_CLR_OPCODE_W0C | ||
112 | #define IMX_I2CR_IEN_OPCODE I2CR_IEN_OPCODE_1 | ||
113 | |||
114 | /** Variables ****************************************************************** | 111 | /** Variables ****************************************************************** |
115 | *******************************************************************************/ | 112 | *******************************************************************************/ |
116 | 113 | ||
@@ -127,7 +124,7 @@ struct imx_i2c_clk_pair { | |||
127 | u16 val; | 124 | u16 val; |
128 | }; | 125 | }; |
129 | 126 | ||
130 | static struct imx_i2c_clk_pair __initdata i2c_clk_div[] = { | 127 | static struct imx_i2c_clk_pair imx_i2c_clk_div[] = { |
131 | { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 }, | 128 | { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 }, |
132 | { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 }, | 129 | { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 }, |
133 | { 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 }, | 130 | { 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 }, |
@@ -148,6 +145,15 @@ enum imx_i2c_type { | |||
148 | IMX21_I2C, | 145 | IMX21_I2C, |
149 | }; | 146 | }; |
150 | 147 | ||
148 | struct imx_i2c_hwdata { | ||
149 | enum imx_i2c_type devtype; | ||
150 | unsigned regshift; | ||
151 | struct imx_i2c_clk_pair *clk_div; | ||
152 | unsigned ndivs; | ||
153 | unsigned i2sr_clr_opcode; | ||
154 | unsigned i2cr_ien_opcode; | ||
155 | }; | ||
156 | |||
151 | struct imx_i2c_struct { | 157 | struct imx_i2c_struct { |
152 | struct i2c_adapter adapter; | 158 | struct i2c_adapter adapter; |
153 | struct clk *clk; | 159 | struct clk *clk; |
@@ -157,16 +163,36 @@ struct imx_i2c_struct { | |||
157 | unsigned int disable_delay; | 163 | unsigned int disable_delay; |
158 | int stopped; | 164 | int stopped; |
159 | unsigned int ifdr; /* IMX_I2C_IFDR */ | 165 | unsigned int ifdr; /* IMX_I2C_IFDR */ |
160 | enum imx_i2c_type devtype; | 166 | const struct imx_i2c_hwdata *hwdata; |
167 | }; | ||
168 | |||
169 | static const struct imx_i2c_hwdata imx1_i2c_hwdata = { | ||
170 | .devtype = IMX1_I2C, | ||
171 | .regshift = IMX_I2C_REGSHIFT, | ||
172 | .clk_div = imx_i2c_clk_div, | ||
173 | .ndivs = ARRAY_SIZE(imx_i2c_clk_div), | ||
174 | .i2sr_clr_opcode = I2SR_CLR_OPCODE_W0C, | ||
175 | .i2cr_ien_opcode = I2CR_IEN_OPCODE_1, | ||
176 | |||
177 | }; | ||
178 | |||
179 | static const struct imx_i2c_hwdata imx21_i2c_hwdata = { | ||
180 | .devtype = IMX21_I2C, | ||
181 | .regshift = IMX_I2C_REGSHIFT, | ||
182 | .clk_div = imx_i2c_clk_div, | ||
183 | .ndivs = ARRAY_SIZE(imx_i2c_clk_div), | ||
184 | .i2sr_clr_opcode = I2SR_CLR_OPCODE_W0C, | ||
185 | .i2cr_ien_opcode = I2CR_IEN_OPCODE_1, | ||
186 | |||
161 | }; | 187 | }; |
162 | 188 | ||
163 | static struct platform_device_id imx_i2c_devtype[] = { | 189 | static struct platform_device_id imx_i2c_devtype[] = { |
164 | { | 190 | { |
165 | .name = "imx1-i2c", | 191 | .name = "imx1-i2c", |
166 | .driver_data = IMX1_I2C, | 192 | .driver_data = (kernel_ulong_t)&imx1_i2c_hwdata, |
167 | }, { | 193 | }, { |
168 | .name = "imx21-i2c", | 194 | .name = "imx21-i2c", |
169 | .driver_data = IMX21_I2C, | 195 | .driver_data = (kernel_ulong_t)&imx21_i2c_hwdata, |
170 | }, { | 196 | }, { |
171 | /* sentinel */ | 197 | /* sentinel */ |
172 | } | 198 | } |
@@ -174,27 +200,27 @@ static struct platform_device_id imx_i2c_devtype[] = { | |||
174 | MODULE_DEVICE_TABLE(platform, imx_i2c_devtype); | 200 | MODULE_DEVICE_TABLE(platform, imx_i2c_devtype); |
175 | 201 | ||
176 | static const struct of_device_id i2c_imx_dt_ids[] = { | 202 | static const struct of_device_id i2c_imx_dt_ids[] = { |
177 | { .compatible = "fsl,imx1-i2c", .data = &imx_i2c_devtype[IMX1_I2C], }, | 203 | { .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, }, |
178 | { .compatible = "fsl,imx21-i2c", .data = &imx_i2c_devtype[IMX21_I2C], }, | 204 | { .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, }, |
179 | { /* sentinel */ } | 205 | { /* sentinel */ } |
180 | }; | 206 | }; |
181 | MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids); | 207 | MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids); |
182 | 208 | ||
183 | static inline int is_imx1_i2c(struct imx_i2c_struct *i2c_imx) | 209 | static inline int is_imx1_i2c(struct imx_i2c_struct *i2c_imx) |
184 | { | 210 | { |
185 | return i2c_imx->devtype == IMX1_I2C; | 211 | return i2c_imx->hwdata->devtype == IMX1_I2C; |
186 | } | 212 | } |
187 | 213 | ||
188 | static inline void imx_i2c_write_reg(unsigned int val, | 214 | static inline void imx_i2c_write_reg(unsigned int val, |
189 | struct imx_i2c_struct *i2c_imx, unsigned int reg) | 215 | struct imx_i2c_struct *i2c_imx, unsigned int reg) |
190 | { | 216 | { |
191 | writeb(val, i2c_imx->base + (reg << IMX_I2C_REGSHIFT)); | 217 | writeb(val, i2c_imx->base + (reg << i2c_imx->hwdata->regshift)); |
192 | } | 218 | } |
193 | 219 | ||
194 | static inline unsigned char imx_i2c_read_reg(struct imx_i2c_struct *i2c_imx, | 220 | static inline unsigned char imx_i2c_read_reg(struct imx_i2c_struct *i2c_imx, |
195 | unsigned int reg) | 221 | unsigned int reg) |
196 | { | 222 | { |
197 | return readb(i2c_imx->base + (reg << IMX_I2C_REGSHIFT)); | 223 | return readb(i2c_imx->base + (reg << i2c_imx->hwdata->regshift)); |
198 | } | 224 | } |
199 | 225 | ||
200 | /** Functions for IMX I2C adapter driver *************************************** | 226 | /** Functions for IMX I2C adapter driver *************************************** |
@@ -258,8 +284,8 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) | |||
258 | clk_prepare_enable(i2c_imx->clk); | 284 | clk_prepare_enable(i2c_imx->clk); |
259 | imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR); | 285 | imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR); |
260 | /* Enable I2C controller */ | 286 | /* Enable I2C controller */ |
261 | imx_i2c_write_reg(IMX_I2SR_CLR_OPCODE, i2c_imx, IMX_I2C_I2SR); | 287 | imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR); |
262 | imx_i2c_write_reg(IMX_I2CR_IEN_OPCODE, i2c_imx, IMX_I2C_I2CR); | 288 | imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx, IMX_I2C_I2CR); |
263 | 289 | ||
264 | /* Wait controller to be stable */ | 290 | /* Wait controller to be stable */ |
265 | udelay(50); | 291 | udelay(50); |
@@ -303,13 +329,15 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx) | |||
303 | } | 329 | } |
304 | 330 | ||
305 | /* Disable I2C controller */ | 331 | /* Disable I2C controller */ |
306 | imx_i2c_write_reg(IMX_I2CR_IEN_OPCODE ^ I2CR_IEN, i2c_imx, IMX_I2C_I2CR); | 332 | temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, |
333 | imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); | ||
307 | clk_disable_unprepare(i2c_imx->clk); | 334 | clk_disable_unprepare(i2c_imx->clk); |
308 | } | 335 | } |
309 | 336 | ||
310 | static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, | 337 | static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, |
311 | unsigned int rate) | 338 | unsigned int rate) |
312 | { | 339 | { |
340 | struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div; | ||
313 | unsigned int i2c_clk_rate; | 341 | unsigned int i2c_clk_rate; |
314 | unsigned int div; | 342 | unsigned int div; |
315 | int i; | 343 | int i; |
@@ -319,8 +347,8 @@ static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, | |||
319 | div = (i2c_clk_rate + rate - 1) / rate; | 347 | div = (i2c_clk_rate + rate - 1) / rate; |
320 | if (div < i2c_clk_div[0].div) | 348 | if (div < i2c_clk_div[0].div) |
321 | i = 0; | 349 | i = 0; |
322 | else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1].div) | 350 | else if (div > i2c_clk_div[i2c_imx->hwdata->ndivs - 1].div) |
323 | i = ARRAY_SIZE(i2c_clk_div) - 1; | 351 | i = i2c_imx->hwdata->ndivs - 1; |
324 | else | 352 | else |
325 | for (i = 0; i2c_clk_div[i].div < div; i++); | 353 | for (i = 0; i2c_clk_div[i].div < div; i++); |
326 | 354 | ||
@@ -355,7 +383,7 @@ static irqreturn_t i2c_imx_isr(int irq, void *dev_id) | |||
355 | /* save status register */ | 383 | /* save status register */ |
356 | i2c_imx->i2csr = temp; | 384 | i2c_imx->i2csr = temp; |
357 | temp &= ~I2SR_IIF; | 385 | temp &= ~I2SR_IIF; |
358 | temp |= (IMX_I2SR_CLR_OPCODE & I2SR_IIF); | 386 | temp |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IIF); |
359 | imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR); | 387 | imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR); |
360 | wake_up(&i2c_imx->queue); | 388 | wake_up(&i2c_imx->queue); |
361 | return IRQ_HANDLED; | 389 | return IRQ_HANDLED; |
@@ -537,7 +565,6 @@ static int __init i2c_imx_probe(struct platform_device *pdev) | |||
537 | struct imx_i2c_struct *i2c_imx; | 565 | struct imx_i2c_struct *i2c_imx; |
538 | struct resource *res; | 566 | struct resource *res; |
539 | struct imxi2c_platform_data *pdata = pdev->dev.platform_data; | 567 | struct imxi2c_platform_data *pdata = pdev->dev.platform_data; |
540 | const struct platform_device_id *imx_id; | ||
541 | void __iomem *base; | 568 | void __iomem *base; |
542 | int irq, ret; | 569 | int irq, ret; |
543 | u32 bitrate; | 570 | u32 bitrate; |
@@ -563,11 +590,10 @@ static int __init i2c_imx_probe(struct platform_device *pdev) | |||
563 | } | 590 | } |
564 | 591 | ||
565 | if (of_id) | 592 | if (of_id) |
566 | imx_id = of_id->data; | 593 | i2c_imx->hwdata = of_id->data; |
567 | else | 594 | else |
568 | imx_id = platform_get_device_id(pdev); | 595 | i2c_imx->hwdata = (struct imx_i2c_hwdata *) |
569 | 596 | platform_get_device_id(pdev)->driver_data; | |
570 | i2c_imx->devtype = imx_id->driver_data; | ||
571 | 597 | ||
572 | /* Setup i2c_imx driver structure */ | 598 | /* Setup i2c_imx driver structure */ |
573 | strlcpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name)); | 599 | strlcpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name)); |
@@ -613,8 +639,9 @@ static int __init i2c_imx_probe(struct platform_device *pdev) | |||
613 | i2c_imx_set_clk(i2c_imx, bitrate); | 639 | i2c_imx_set_clk(i2c_imx, bitrate); |
614 | 640 | ||
615 | /* Set up chip registers to defaults */ | 641 | /* Set up chip registers to defaults */ |
616 | imx_i2c_write_reg(IMX_I2CR_IEN_OPCODE ^ I2CR_IEN, i2c_imx, IMX_I2C_I2CR); | 642 | imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, |
617 | imx_i2c_write_reg(IMX_I2SR_CLR_OPCODE, i2c_imx, IMX_I2C_I2SR); | 643 | i2c_imx, IMX_I2C_I2CR); |
644 | imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR); | ||
618 | 645 | ||
619 | /* Add I2C adapter */ | 646 | /* Add I2C adapter */ |
620 | ret = i2c_add_numbered_adapter(&i2c_imx->adapter); | 647 | ret = i2c_add_numbered_adapter(&i2c_imx->adapter); |