diff options
| -rw-r--r-- | Documentation/devicetree/bindings/i2c/pnx.txt | 36 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-pnx.c | 63 | ||||
| -rw-r--r-- | include/linux/i2c-pnx.h | 1 |
3 files changed, 84 insertions, 16 deletions
diff --git a/Documentation/devicetree/bindings/i2c/pnx.txt b/Documentation/devicetree/bindings/i2c/pnx.txt new file mode 100644 index 000000000000..fe98ada33ee4 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/pnx.txt | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | * NXP PNX I2C Controller | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | |||
| 5 | - reg: Offset and length of the register set for the device | ||
| 6 | - compatible: should be "nxp,pnx-i2c" | ||
| 7 | - interrupts: configure one interrupt line | ||
| 8 | - #address-cells: always 1 (for i2c addresses) | ||
| 9 | - #size-cells: always 0 | ||
| 10 | - interrupt-parent: the phandle for the interrupt controller that | ||
| 11 | services interrupts for this device. | ||
| 12 | |||
| 13 | Optional properties: | ||
| 14 | |||
| 15 | - clock-frequency: desired I2C bus clock frequency in Hz, Default: 100000 Hz | ||
| 16 | |||
| 17 | Examples: | ||
| 18 | |||
| 19 | i2c1: i2c@400a0000 { | ||
| 20 | compatible = "nxp,pnx-i2c"; | ||
| 21 | reg = <0x400a0000 0x100>; | ||
| 22 | interrupt-parent = <&mic>; | ||
| 23 | interrupts = <51 0>; | ||
| 24 | #address-cells = <1>; | ||
| 25 | #size-cells = <0>; | ||
| 26 | }; | ||
| 27 | |||
| 28 | i2c2: i2c@400a8000 { | ||
| 29 | compatible = "nxp,pnx-i2c"; | ||
| 30 | reg = <0x400a8000 0x100>; | ||
| 31 | interrupt-parent = <&mic>; | ||
| 32 | interrupts = <50 0>; | ||
| 33 | #address-cells = <1>; | ||
| 34 | #size-cells = <0>; | ||
| 35 | clock-frequency = <100000>; | ||
| 36 | }; | ||
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), |
diff --git a/include/linux/i2c-pnx.h b/include/linux/i2c-pnx.h index 6e8efb7afd7c..1bc74afe7a35 100644 --- a/include/linux/i2c-pnx.h +++ b/include/linux/i2c-pnx.h | |||
| @@ -32,6 +32,7 @@ struct i2c_pnx_algo_data { | |||
| 32 | struct i2c_adapter adapter; | 32 | struct i2c_adapter adapter; |
| 33 | phys_addr_t base; | 33 | phys_addr_t base; |
| 34 | int irq; | 34 | int irq; |
| 35 | u32 timeout; | ||
| 35 | }; | 36 | }; |
| 36 | 37 | ||
| 37 | #endif /* __I2C_PNX_H__ */ | 38 | #endif /* __I2C_PNX_H__ */ |
