diff options
author | Roland Stigge <stigge@antcom.de> | 2012-04-20 09:34:09 -0400 |
---|---|---|
committer | Wolfram Sang <w.sang@pengutronix.de> | 2012-05-12 08:28:14 -0400 |
commit | a092de11bb4a96ac43ede0352e09bdf7e06280e8 (patch) | |
tree | d00b69bb5214e6287005c28c5f9f7df51e8a0d3b /drivers/i2c | |
parent | 973c5ed45dbdf8fd90e300826507b5e6814916af (diff) |
i2c: pnx: add device tree support
This patch adds device tree support to the pnx-i2c driver by using platform
resources for memory region and irq and removing dependency on mach includes.
The following platforms are affected:
* PNX
* LPC31xx (WIP)
* LPC32xx
The patch is based on a patch by Jon Smirl, working on lpc31xx integration
Signed-off-by: Roland Stigge <stigge@antcom.de>
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-pnx.c | 63 |
1 files changed, 47 insertions, 16 deletions
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index f69d80b8d736..99389d2eae51 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c | |||
@@ -23,10 +23,11 @@ | |||
23 | #include <linux/err.h> | 23 | #include <linux/err.h> |
24 | #include <linux/clk.h> | 24 | #include <linux/clk.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/of_i2c.h> | ||
26 | 27 | ||
27 | #define I2C_PNX_TIMEOUT 10 /* msec */ | 28 | #define I2C_PNX_TIMEOUT_DEFAULT 10 /* msec */ |
28 | #define I2C_PNX_SPEED_KHZ 100 | 29 | #define I2C_PNX_SPEED_KHZ_DEFAULT 100 |
29 | #define I2C_PNX_REGION_SIZE 0x100 | 30 | #define I2C_PNX_REGION_SIZE 0x100 |
30 | 31 | ||
31 | enum { | 32 | enum { |
32 | mstatus_tdi = 0x00000001, | 33 | mstatus_tdi = 0x00000001, |
@@ -74,8 +75,9 @@ enum { | |||
74 | #define I2C_REG_TXS(a) ((a)->ioaddr + 0x28) /* Tx slave FIFO (RO) */ | 75 | #define I2C_REG_TXS(a) ((a)->ioaddr + 0x28) /* Tx slave FIFO (RO) */ |
75 | #define I2C_REG_STFL(a) ((a)->ioaddr + 0x2c) /* Tx slave FIFO level (RO) */ | 76 | #define I2C_REG_STFL(a) ((a)->ioaddr + 0x2c) /* Tx slave FIFO level (RO) */ |
76 | 77 | ||
77 | static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data) | 78 | static inline int wait_timeout(struct i2c_pnx_algo_data *data) |
78 | { | 79 | { |
80 | long timeout = data->timeout; | ||
79 | while (timeout > 0 && | 81 | while (timeout > 0 && |
80 | (ioread32(I2C_REG_STS(data)) & mstatus_active)) { | 82 | (ioread32(I2C_REG_STS(data)) & mstatus_active)) { |
81 | mdelay(1); | 83 | mdelay(1); |
@@ -84,8 +86,9 @@ static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data) | |||
84 | return (timeout <= 0); | 86 | return (timeout <= 0); |
85 | } | 87 | } |
86 | 88 | ||
87 | static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data) | 89 | static inline int wait_reset(struct i2c_pnx_algo_data *data) |
88 | { | 90 | { |
91 | long timeout = data->timeout; | ||
89 | while (timeout > 0 && | 92 | while (timeout > 0 && |
90 | (ioread32(I2C_REG_CTL(data)) & mcntrl_reset)) { | 93 | (ioread32(I2C_REG_CTL(data)) & mcntrl_reset)) { |
91 | mdelay(1); | 94 | mdelay(1); |
@@ -97,7 +100,7 @@ static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data) | |||
97 | static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data) | 100 | static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data) |
98 | { | 101 | { |
99 | struct timer_list *timer = &alg_data->mif.timer; | 102 | struct timer_list *timer = &alg_data->mif.timer; |
100 | unsigned long expires = msecs_to_jiffies(I2C_PNX_TIMEOUT); | 103 | unsigned long expires = msecs_to_jiffies(alg_data->timeout); |
101 | 104 | ||
102 | if (expires <= 1) | 105 | if (expires <= 1) |
103 | expires = 2; | 106 | expires = 2; |
@@ -135,7 +138,7 @@ static int i2c_pnx_start(unsigned char slave_addr, | |||
135 | } | 138 | } |
136 | 139 | ||
137 | /* First, make sure bus is idle */ | 140 | /* First, make sure bus is idle */ |
138 | if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) { | 141 | if (wait_timeout(alg_data)) { |
139 | /* Somebody else is monopolizing the bus */ | 142 | /* Somebody else is monopolizing the bus */ |
140 | dev_err(&alg_data->adapter.dev, | 143 | dev_err(&alg_data->adapter.dev, |
141 | "%s: Bus busy. Slave addr = %02x, cntrl = %x, stat = %x\n", | 144 | "%s: Bus busy. Slave addr = %02x, cntrl = %x, stat = %x\n", |
@@ -228,7 +231,7 @@ static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data) | |||
228 | if (alg_data->mif.len == 0) { | 231 | if (alg_data->mif.len == 0) { |
229 | if (alg_data->last) { | 232 | if (alg_data->last) { |
230 | /* Wait until the STOP is seen. */ | 233 | /* Wait until the STOP is seen. */ |
231 | if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) | 234 | if (wait_timeout(alg_data)) |
232 | dev_err(&alg_data->adapter.dev, | 235 | dev_err(&alg_data->adapter.dev, |
233 | "The bus is still active after timeout\n"); | 236 | "The bus is still active after timeout\n"); |
234 | } | 237 | } |
@@ -326,7 +329,7 @@ static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data) | |||
326 | if (alg_data->mif.len == 0) { | 329 | if (alg_data->mif.len == 0) { |
327 | if (alg_data->last) | 330 | if (alg_data->last) |
328 | /* Wait until the STOP is seen. */ | 331 | /* Wait until the STOP is seen. */ |
329 | if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) | 332 | if (wait_timeout(alg_data)) |
330 | dev_err(&alg_data->adapter.dev, | 333 | dev_err(&alg_data->adapter.dev, |
331 | "The bus is still active after timeout\n"); | 334 | "The bus is still active after timeout\n"); |
332 | 335 | ||
@@ -442,7 +445,7 @@ static void i2c_pnx_timeout(unsigned long data) | |||
442 | 445 | ||
443 | ctl |= mcntrl_reset; | 446 | ctl |= mcntrl_reset; |
444 | iowrite32(ctl, I2C_REG_CTL(alg_data)); | 447 | iowrite32(ctl, I2C_REG_CTL(alg_data)); |
445 | wait_reset(I2C_PNX_TIMEOUT, alg_data); | 448 | wait_reset(alg_data); |
446 | alg_data->mif.ret = -EIO; | 449 | alg_data->mif.ret = -EIO; |
447 | complete(&alg_data->mif.complete); | 450 | complete(&alg_data->mif.complete); |
448 | } | 451 | } |
@@ -457,18 +460,18 @@ static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data) | |||
457 | alg_data->adapter.name); | 460 | alg_data->adapter.name); |
458 | iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, | 461 | iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, |
459 | I2C_REG_CTL(alg_data)); | 462 | I2C_REG_CTL(alg_data)); |
460 | wait_reset(I2C_PNX_TIMEOUT, alg_data); | 463 | wait_reset(alg_data); |
461 | } else if (!(stat & mstatus_rfe) || !(stat & mstatus_tfe)) { | 464 | } else if (!(stat & mstatus_rfe) || !(stat & mstatus_tfe)) { |
462 | /* If there is data in the fifo's after transfer, | 465 | /* If there is data in the fifo's after transfer, |
463 | * flush fifo's by reset. | 466 | * flush fifo's by reset. |
464 | */ | 467 | */ |
465 | iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, | 468 | iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, |
466 | I2C_REG_CTL(alg_data)); | 469 | I2C_REG_CTL(alg_data)); |
467 | wait_reset(I2C_PNX_TIMEOUT, alg_data); | 470 | wait_reset(alg_data); |
468 | } else if (stat & mstatus_nai) { | 471 | } else if (stat & mstatus_nai) { |
469 | iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, | 472 | iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, |
470 | I2C_REG_CTL(alg_data)); | 473 | I2C_REG_CTL(alg_data)); |
471 | wait_reset(I2C_PNX_TIMEOUT, alg_data); | 474 | wait_reset(alg_data); |
472 | } | 475 | } |
473 | } | 476 | } |
474 | 477 | ||
@@ -612,6 +615,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) | |||
612 | struct i2c_pnx_algo_data *alg_data; | 615 | struct i2c_pnx_algo_data *alg_data; |
613 | unsigned long freq; | 616 | unsigned long freq; |
614 | struct resource *res; | 617 | struct resource *res; |
618 | u32 speed = I2C_PNX_SPEED_KHZ_DEFAULT * 1000; | ||
615 | 619 | ||
616 | alg_data = kzalloc(sizeof(*alg_data), GFP_KERNEL); | 620 | alg_data = kzalloc(sizeof(*alg_data), GFP_KERNEL); |
617 | if (!alg_data) { | 621 | if (!alg_data) { |
@@ -626,6 +630,22 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) | |||
626 | alg_data->adapter.algo_data = alg_data; | 630 | alg_data->adapter.algo_data = alg_data; |
627 | alg_data->adapter.nr = pdev->id; | 631 | alg_data->adapter.nr = pdev->id; |
628 | 632 | ||
633 | alg_data->timeout = I2C_PNX_TIMEOUT_DEFAULT; | ||
634 | #ifdef CONFIG_OF | ||
635 | alg_data->adapter.dev.of_node = of_node_get(pdev->dev.of_node); | ||
636 | if (pdev->dev.of_node) { | ||
637 | of_property_read_u32(pdev->dev.of_node, "clock-frequency", | ||
638 | &speed); | ||
639 | /* | ||
640 | * At this point, it is planned to add an OF timeout property. | ||
641 | * As soon as there is a consensus about how to call and handle | ||
642 | * this, sth. like the following can be put here: | ||
643 | * | ||
644 | * of_property_read_u32(pdev->dev.of_node, "timeout", | ||
645 | * &alg_data->timeout); | ||
646 | */ | ||
647 | } | ||
648 | #endif | ||
629 | alg_data->clk = clk_get(&pdev->dev, NULL); | 649 | alg_data->clk = clk_get(&pdev->dev, NULL); |
630 | if (IS_ERR(alg_data->clk)) { | 650 | if (IS_ERR(alg_data->clk)) { |
631 | ret = PTR_ERR(alg_data->clk); | 651 | ret = PTR_ERR(alg_data->clk); |
@@ -651,7 +671,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) | |||
651 | dev_err(&pdev->dev, | 671 | dev_err(&pdev->dev, |
652 | "I/O region 0x%08x for I2C already in use.\n", | 672 | "I/O region 0x%08x for I2C already in use.\n", |
653 | res->start); | 673 | res->start); |
654 | ret = -ENODEV; | 674 | ret = -ENOMEM; |
655 | goto out_clkget; | 675 | goto out_clkget; |
656 | } | 676 | } |
657 | 677 | ||
@@ -680,14 +700,14 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) | |||
680 | * the deglitching filter length. | 700 | * the deglitching filter length. |
681 | */ | 701 | */ |
682 | 702 | ||
683 | tmp = ((freq / 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2; | 703 | tmp = (freq / speed) / 2 - 2; |
684 | if (tmp > 0x3FF) | 704 | if (tmp > 0x3FF) |
685 | tmp = 0x3FF; | 705 | tmp = 0x3FF; |
686 | iowrite32(tmp, I2C_REG_CKH(alg_data)); | 706 | iowrite32(tmp, I2C_REG_CKH(alg_data)); |
687 | iowrite32(tmp, I2C_REG_CKL(alg_data)); | 707 | iowrite32(tmp, I2C_REG_CKL(alg_data)); |
688 | 708 | ||
689 | iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data)); | 709 | iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data)); |
690 | if (wait_reset(I2C_PNX_TIMEOUT, alg_data)) { | 710 | if (wait_reset(alg_data)) { |
691 | ret = -ENODEV; | 711 | ret = -ENODEV; |
692 | goto out_clock; | 712 | goto out_clock; |
693 | } | 713 | } |
@@ -710,6 +730,8 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) | |||
710 | goto out_irq; | 730 | goto out_irq; |
711 | } | 731 | } |
712 | 732 | ||
733 | of_i2c_register_devices(&alg_data->adapter); | ||
734 | |||
713 | dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n", | 735 | dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n", |
714 | alg_data->adapter.name, res->start, alg_data->irq); | 736 | alg_data->adapter.name, res->start, alg_data->irq); |
715 | 737 | ||
@@ -748,10 +770,19 @@ static int __devexit i2c_pnx_remove(struct platform_device *pdev) | |||
748 | return 0; | 770 | return 0; |
749 | } | 771 | } |
750 | 772 | ||
773 | #ifdef CONFIG_OF | ||
774 | static const struct of_device_id i2c_pnx_of_match[] = { | ||
775 | { .compatible = "nxp,pnx-i2c" }, | ||
776 | { }, | ||
777 | }; | ||
778 | MODULE_DEVICE_TABLE(of, i2c_pnx_of_match); | ||
779 | #endif | ||
780 | |||
751 | static struct platform_driver i2c_pnx_driver = { | 781 | static struct platform_driver i2c_pnx_driver = { |
752 | .driver = { | 782 | .driver = { |
753 | .name = "pnx-i2c", | 783 | .name = "pnx-i2c", |
754 | .owner = THIS_MODULE, | 784 | .owner = THIS_MODULE, |
785 | .of_match_table = of_match_ptr(i2c_pnx_of_match), | ||
755 | }, | 786 | }, |
756 | .probe = i2c_pnx_probe, | 787 | .probe = i2c_pnx_probe, |
757 | .remove = __devexit_p(i2c_pnx_remove), | 788 | .remove = __devexit_p(i2c_pnx_remove), |