diff options
| -rw-r--r-- | arch/arm/mach-pnx4008/Makefile | 2 | ||||
| -rw-r--r-- | arch/arm/mach-pnx4008/i2c.c | 167 | ||||
| -rw-r--r-- | drivers/i2c/busses/Kconfig | 19 | ||||
| -rw-r--r-- | drivers/i2c/busses/Makefile | 1 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-pnx.c | 708 | ||||
| -rw-r--r-- | include/asm-arm/arch-pnx4008/i2c.h | 67 | ||||
| -rw-r--r-- | include/linux/i2c-pnx.h | 43 |
7 files changed, 1006 insertions, 1 deletions
diff --git a/arch/arm/mach-pnx4008/Makefile b/arch/arm/mach-pnx4008/Makefile index b457ca0a431a..777564c90a12 100644 --- a/arch/arm/mach-pnx4008/Makefile +++ b/arch/arm/mach-pnx4008/Makefile | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | # Makefile for the linux kernel. | 2 | # Makefile for the linux kernel. |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-y := core.o irq.o time.o clock.o gpio.o serial.o dma.o | 5 | obj-y := core.o irq.o time.o clock.o gpio.o serial.o dma.o i2c.o |
| 6 | obj-m := | 6 | obj-m := |
| 7 | obj-n := | 7 | obj-n := |
| 8 | obj- := | 8 | obj- := |
diff --git a/arch/arm/mach-pnx4008/i2c.c b/arch/arm/mach-pnx4008/i2c.c new file mode 100644 index 000000000000..6f308827c4fe --- /dev/null +++ b/arch/arm/mach-pnx4008/i2c.c | |||
| @@ -0,0 +1,167 @@ | |||
| 1 | /* | ||
| 2 | * I2C initialization for PNX4008. | ||
| 3 | * | ||
| 4 | * Author: Vitaly Wool <vitalywool@gmail.com> | ||
| 5 | * | ||
| 6 | * 2005-2006 (c) MontaVista Software, Inc. This file is licensed under | ||
| 7 | * the terms of the GNU General Public License version 2. This program | ||
| 8 | * is licensed "as is" without any warranty of any kind, whether express | ||
| 9 | * or implied. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/clk.h> | ||
| 13 | #include <linux/i2c.h> | ||
| 14 | #include <linux/i2c-pnx.h> | ||
| 15 | #include <linux/platform_device.h> | ||
| 16 | #include <linux/err.h> | ||
| 17 | #include <asm/arch/platform.h> | ||
| 18 | #include <asm/arch/i2c.h> | ||
| 19 | |||
| 20 | static int set_clock_run(struct platform_device *pdev) | ||
| 21 | { | ||
| 22 | struct clk *clk; | ||
| 23 | char name[10]; | ||
| 24 | int retval = 0; | ||
| 25 | |||
| 26 | snprintf(name, 10, "i2c%d_ck", pdev->id); | ||
| 27 | clk = clk_get(&pdev->dev, name); | ||
| 28 | if (!IS_ERR(clk)) { | ||
| 29 | clk_set_rate(clk, 1); | ||
| 30 | clk_put(clk); | ||
| 31 | } else | ||
| 32 | retval = -ENOENT; | ||
| 33 | |||
| 34 | return retval; | ||
| 35 | } | ||
| 36 | |||
| 37 | static int set_clock_stop(struct platform_device *pdev) | ||
| 38 | { | ||
| 39 | struct clk *clk; | ||
| 40 | char name[10]; | ||
| 41 | int retval = 0; | ||
| 42 | |||
| 43 | snprintf(name, 10, "i2c%d_ck", pdev->id); | ||
| 44 | clk = clk_get(&pdev->dev, name); | ||
| 45 | if (!IS_ERR(clk)) { | ||
| 46 | clk_set_rate(clk, 0); | ||
| 47 | clk_put(clk); | ||
| 48 | } else | ||
| 49 | retval = -ENOENT; | ||
| 50 | |||
| 51 | return retval; | ||
| 52 | } | ||
| 53 | |||
| 54 | static int i2c_pnx_suspend(struct platform_device *pdev, pm_message_t state) | ||
| 55 | { | ||
| 56 | int retval = 0; | ||
| 57 | #ifdef CONFIG_PM | ||
| 58 | retval = set_clock_run(pdev); | ||
| 59 | #endif | ||
| 60 | return retval; | ||
| 61 | } | ||
| 62 | |||
| 63 | static int i2c_pnx_resume(struct platform_device *pdev) | ||
| 64 | { | ||
| 65 | int retval = 0; | ||
| 66 | #ifdef CONFIG_PM | ||
| 67 | retval = set_clock_run(pdev); | ||
| 68 | #endif | ||
| 69 | return retval; | ||
| 70 | } | ||
| 71 | |||
| 72 | static u32 calculate_input_freq(struct platform_device *pdev) | ||
| 73 | { | ||
| 74 | return HCLK_MHZ; | ||
| 75 | } | ||
| 76 | |||
| 77 | |||
| 78 | static struct i2c_pnx_algo_data pnx_algo_data0 = { | ||
| 79 | .base = PNX4008_I2C1_BASE, | ||
| 80 | .irq = I2C_1_INT, | ||
| 81 | }; | ||
| 82 | |||
| 83 | static struct i2c_pnx_algo_data pnx_algo_data1 = { | ||
| 84 | .base = PNX4008_I2C2_BASE, | ||
| 85 | .irq = I2C_2_INT, | ||
| 86 | }; | ||
| 87 | |||
| 88 | static struct i2c_pnx_algo_data pnx_algo_data2 = { | ||
| 89 | .base = (PNX4008_USB_CONFIG_BASE + 0x300), | ||
| 90 | .irq = USB_I2C_INT, | ||
| 91 | }; | ||
| 92 | |||
| 93 | static struct i2c_adapter pnx_adapter0 = { | ||
| 94 | .name = I2C_CHIP_NAME "0", | ||
| 95 | .algo_data = &pnx_algo_data0, | ||
| 96 | }; | ||
| 97 | static struct i2c_adapter pnx_adapter1 = { | ||
| 98 | .name = I2C_CHIP_NAME "1", | ||
| 99 | .algo_data = &pnx_algo_data1, | ||
| 100 | }; | ||
| 101 | |||
| 102 | static struct i2c_adapter pnx_adapter2 = { | ||
| 103 | .name = "USB-I2C", | ||
| 104 | .algo_data = &pnx_algo_data2, | ||
| 105 | }; | ||
| 106 | |||
| 107 | static struct i2c_pnx_data i2c0_data = { | ||
| 108 | .suspend = i2c_pnx_suspend, | ||
| 109 | .resume = i2c_pnx_resume, | ||
| 110 | .calculate_input_freq = calculate_input_freq, | ||
| 111 | .set_clock_run = set_clock_run, | ||
| 112 | .set_clock_stop = set_clock_stop, | ||
| 113 | .adapter = &pnx_adapter0, | ||
| 114 | }; | ||
| 115 | |||
| 116 | static struct i2c_pnx_data i2c1_data = { | ||
| 117 | .suspend = i2c_pnx_suspend, | ||
| 118 | .resume = i2c_pnx_resume, | ||
| 119 | .calculate_input_freq = calculate_input_freq, | ||
| 120 | .set_clock_run = set_clock_run, | ||
| 121 | .set_clock_stop = set_clock_stop, | ||
| 122 | .adapter = &pnx_adapter1, | ||
| 123 | }; | ||
| 124 | |||
| 125 | static struct i2c_pnx_data i2c2_data = { | ||
| 126 | .suspend = i2c_pnx_suspend, | ||
| 127 | .resume = i2c_pnx_resume, | ||
| 128 | .calculate_input_freq = calculate_input_freq, | ||
| 129 | .set_clock_run = set_clock_run, | ||
| 130 | .set_clock_stop = set_clock_stop, | ||
| 131 | .adapter = &pnx_adapter2, | ||
| 132 | }; | ||
| 133 | |||
| 134 | static struct platform_device i2c0_device = { | ||
| 135 | .name = "pnx-i2c", | ||
| 136 | .id = 0, | ||
| 137 | .dev = { | ||
| 138 | .platform_data = &i2c0_data, | ||
| 139 | }, | ||
| 140 | }; | ||
| 141 | |||
| 142 | static struct platform_device i2c1_device = { | ||
| 143 | .name = "pnx-i2c", | ||
| 144 | .id = 1, | ||
| 145 | .dev = { | ||
| 146 | .platform_data = &i2c1_data, | ||
| 147 | }, | ||
| 148 | }; | ||
| 149 | |||
| 150 | static struct platform_device i2c2_device = { | ||
| 151 | .name = "pnx-i2c", | ||
| 152 | .id = 2, | ||
| 153 | .dev = { | ||
| 154 | .platform_data = &i2c2_data, | ||
| 155 | }, | ||
| 156 | }; | ||
| 157 | |||
| 158 | static struct platform_device *devices[] __initdata = { | ||
| 159 | &i2c0_device, | ||
| 160 | &i2c1_device, | ||
| 161 | &i2c2_device, | ||
| 162 | }; | ||
| 163 | |||
| 164 | void __init pnx4008_register_i2c_devices(void) | ||
| 165 | { | ||
| 166 | platform_add_devices(devices, ARRAY_SIZE(devices)); | ||
| 167 | } | ||
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 7c9ab337d180..291da25e84d1 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
| @@ -536,4 +536,23 @@ config I2C_MV64XXX | |||
| 536 | This driver can also be built as a module. If so, the module | 536 | This driver can also be built as a module. If so, the module |
| 537 | will be called i2c-mv64xxx. | 537 | will be called i2c-mv64xxx. |
| 538 | 538 | ||
| 539 | config I2C_PNX | ||
| 540 | tristate "I2C bus support for Philips PNX targets" | ||
| 541 | depends on ARCH_PNX4008 && I2C | ||
| 542 | help | ||
| 543 | This driver supports the Philips IP3204 I2C IP block master and/or | ||
| 544 | slave controller | ||
| 545 | |||
| 546 | This driver can also be built as a module. If so, the module | ||
| 547 | will be called i2c-pnx. | ||
| 548 | |||
| 549 | config I2C_PNX_EARLY | ||
| 550 | bool "Early initialization for I2C on PNXxxxx" | ||
| 551 | depends on I2C_PNX=y | ||
| 552 | help | ||
| 553 | Under certain circumstances one may need to make sure I2C on PNXxxxx | ||
| 554 | is initialized earlier than some other driver that depends on it | ||
| 555 | (for instance, that might be USB in case of PNX4008). With this | ||
| 556 | option turned on you can guarantee that. | ||
| 557 | |||
| 539 | endmenu | 558 | endmenu |
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index bf5fd078b292..626ac71af959 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile | |||
| @@ -28,6 +28,7 @@ obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o | |||
| 28 | obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o | 28 | obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o |
| 29 | obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o | 29 | obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o |
| 30 | obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o | 30 | obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o |
| 31 | obj-$(CONFIG_I2C_PNX) += i2c-pnx.o | ||
| 31 | obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o | 32 | obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o |
| 32 | obj-$(CONFIG_I2C_PXA) += i2c-pxa.o | 33 | obj-$(CONFIG_I2C_PXA) += i2c-pxa.o |
| 33 | obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o | 34 | obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o |
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c new file mode 100644 index 000000000000..de0bca77e926 --- /dev/null +++ b/drivers/i2c/busses/i2c-pnx.c | |||
| @@ -0,0 +1,708 @@ | |||
| 1 | /* | ||
| 2 | * Provides I2C support for Philips PNX010x/PNX4008 boards. | ||
| 3 | * | ||
| 4 | * Authors: Dennis Kovalev <dkovalev@ru.mvista.com> | ||
| 5 | * Vitaly Wool <vwool@ru.mvista.com> | ||
| 6 | * | ||
| 7 | * 2004-2006 (c) MontaVista Software, Inc. This file is licensed under | ||
| 8 | * the terms of the GNU General Public License version 2. This program | ||
| 9 | * is licensed "as is" without any warranty of any kind, whether express | ||
| 10 | * or implied. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/interrupt.h> | ||
| 15 | #include <linux/ioport.h> | ||
| 16 | #include <linux/delay.h> | ||
| 17 | #include <linux/i2c.h> | ||
| 18 | #include <linux/timer.h> | ||
| 19 | #include <linux/completion.h> | ||
| 20 | #include <linux/platform_device.h> | ||
| 21 | #include <linux/i2c-pnx.h> | ||
| 22 | #include <asm/hardware.h> | ||
| 23 | #include <asm/irq.h> | ||
| 24 | #include <asm/uaccess.h> | ||
| 25 | |||
| 26 | #define I2C_PNX_TIMEOUT 10 /* msec */ | ||
| 27 | #define I2C_PNX_SPEED_KHZ 100 | ||
| 28 | #define I2C_PNX_REGION_SIZE 0x100 | ||
| 29 | #define PNX_DEFAULT_FREQ 13 /* MHz */ | ||
| 30 | |||
| 31 | static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data) | ||
| 32 | { | ||
| 33 | while (timeout > 0 && | ||
| 34 | (ioread32(I2C_REG_STS(data)) & mstatus_active)) { | ||
| 35 | mdelay(1); | ||
| 36 | timeout--; | ||
| 37 | } | ||
| 38 | return (timeout <= 0); | ||
| 39 | } | ||
| 40 | |||
| 41 | static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data) | ||
| 42 | { | ||
| 43 | while (timeout > 0 && | ||
| 44 | (ioread32(I2C_REG_CTL(data)) & mcntrl_reset)) { | ||
| 45 | mdelay(1); | ||
| 46 | timeout--; | ||
| 47 | } | ||
| 48 | return (timeout <= 0); | ||
| 49 | } | ||
| 50 | |||
| 51 | static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap) | ||
| 52 | { | ||
| 53 | struct i2c_pnx_algo_data *data = adap->algo_data; | ||
| 54 | struct timer_list *timer = &data->mif.timer; | ||
| 55 | int expires = I2C_PNX_TIMEOUT / (1000 / HZ); | ||
| 56 | |||
| 57 | del_timer_sync(timer); | ||
| 58 | |||
| 59 | dev_dbg(&adap->dev, "Timer armed at %lu plus %u jiffies.\n", | ||
| 60 | jiffies, expires); | ||
| 61 | |||
| 62 | timer->expires = jiffies + expires; | ||
| 63 | timer->data = (unsigned long)adap; | ||
| 64 | |||
| 65 | add_timer(timer); | ||
| 66 | } | ||
| 67 | |||
| 68 | /** | ||
| 69 | * i2c_pnx_start - start a device | ||
| 70 | * @slave_addr: slave address | ||
| 71 | * @adap: pointer to adapter structure | ||
| 72 | * | ||
| 73 | * Generate a START signal in the desired mode. | ||
| 74 | */ | ||
| 75 | static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap) | ||
| 76 | { | ||
| 77 | struct i2c_pnx_algo_data *alg_data = adap->algo_data; | ||
| 78 | |||
| 79 | dev_dbg(&adap->dev, "%s(): addr 0x%x mode %d\n", __FUNCTION__, | ||
| 80 | slave_addr, alg_data->mif.mode); | ||
| 81 | |||
| 82 | /* Check for 7 bit slave addresses only */ | ||
| 83 | if (slave_addr & ~0x7f) { | ||
| 84 | dev_err(&adap->dev, "%s: Invalid slave address %x. " | ||
| 85 | "Only 7-bit addresses are supported\n", | ||
| 86 | adap->name, slave_addr); | ||
| 87 | return -EINVAL; | ||
| 88 | } | ||
| 89 | |||
| 90 | /* First, make sure bus is idle */ | ||
| 91 | if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) { | ||
| 92 | /* Somebody else is monopolizing the bus */ | ||
| 93 | dev_err(&adap->dev, "%s: Bus busy. Slave addr = %02x, " | ||
| 94 | "cntrl = %x, stat = %x\n", | ||
| 95 | adap->name, slave_addr, | ||
| 96 | ioread32(I2C_REG_CTL(alg_data)), | ||
| 97 | ioread32(I2C_REG_STS(alg_data))); | ||
| 98 | return -EBUSY; | ||
| 99 | } else if (ioread32(I2C_REG_STS(alg_data)) & mstatus_afi) { | ||
| 100 | /* Sorry, we lost the bus */ | ||
| 101 | dev_err(&adap->dev, "%s: Arbitration failure. " | ||
| 102 | "Slave addr = %02x\n", adap->name, slave_addr); | ||
| 103 | return -EIO; | ||
| 104 | } | ||
| 105 | |||
| 106 | /* | ||
| 107 | * OK, I2C is enabled and we have the bus. | ||
| 108 | * Clear the current TDI and AFI status flags. | ||
| 109 | */ | ||
| 110 | iowrite32(ioread32(I2C_REG_STS(alg_data)) | mstatus_tdi | mstatus_afi, | ||
| 111 | I2C_REG_STS(alg_data)); | ||
| 112 | |||
| 113 | dev_dbg(&adap->dev, "%s(): sending %#x\n", __FUNCTION__, | ||
| 114 | (slave_addr << 1) | start_bit | alg_data->mif.mode); | ||
| 115 | |||
| 116 | /* Write the slave address, START bit and R/W bit */ | ||
| 117 | iowrite32((slave_addr << 1) | start_bit | alg_data->mif.mode, | ||
| 118 | I2C_REG_TX(alg_data)); | ||
| 119 | |||
| 120 | dev_dbg(&adap->dev, "%s(): exit\n", __FUNCTION__); | ||
| 121 | |||
| 122 | return 0; | ||
| 123 | } | ||
| 124 | |||
| 125 | /** | ||
| 126 | * i2c_pnx_stop - stop a device | ||
| 127 | * @adap: pointer to I2C adapter structure | ||
| 128 | * | ||
| 129 | * Generate a STOP signal to terminate the master transaction. | ||
| 130 | */ | ||
| 131 | static void i2c_pnx_stop(struct i2c_adapter *adap) | ||
| 132 | { | ||
| 133 | struct i2c_pnx_algo_data *alg_data = adap->algo_data; | ||
| 134 | /* Only 1 msec max timeout due to interrupt context */ | ||
| 135 | long timeout = 1000; | ||
| 136 | |||
| 137 | dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n", | ||
| 138 | __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); | ||
| 139 | |||
| 140 | /* Write a STOP bit to TX FIFO */ | ||
| 141 | iowrite32(0xff | stop_bit, I2C_REG_TX(alg_data)); | ||
| 142 | |||
| 143 | /* Wait until the STOP is seen. */ | ||
| 144 | while (timeout > 0 && | ||
| 145 | (ioread32(I2C_REG_STS(alg_data)) & mstatus_active)) { | ||
| 146 | /* may be called from interrupt context */ | ||
| 147 | udelay(1); | ||
| 148 | timeout--; | ||
| 149 | } | ||
| 150 | |||
| 151 | dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n", | ||
| 152 | __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); | ||
| 153 | } | ||
| 154 | |||
| 155 | /** | ||
| 156 | * i2c_pnx_master_xmit - transmit data to slave | ||
| 157 | * @adap: pointer to I2C adapter structure | ||
| 158 | * | ||
| 159 | * Sends one byte of data to the slave | ||
| 160 | */ | ||
| 161 | static int i2c_pnx_master_xmit(struct i2c_adapter *adap) | ||
| 162 | { | ||
| 163 | struct i2c_pnx_algo_data *alg_data = adap->algo_data; | ||
| 164 | u32 val; | ||
| 165 | |||
| 166 | dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n", | ||
| 167 | __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); | ||
| 168 | |||
| 169 | if (alg_data->mif.len > 0) { | ||
| 170 | /* We still have something to talk about... */ | ||
| 171 | val = *alg_data->mif.buf++; | ||
| 172 | |||
| 173 | if (alg_data->mif.len == 1) { | ||
| 174 | val |= stop_bit; | ||
| 175 | if (!alg_data->last) | ||
| 176 | val |= start_bit; | ||
| 177 | } | ||
| 178 | |||
| 179 | alg_data->mif.len--; | ||
| 180 | iowrite32(val, I2C_REG_TX(alg_data)); | ||
| 181 | |||
| 182 | dev_dbg(&adap->dev, "%s(): xmit %#x [%d]\n", __FUNCTION__, | ||
| 183 | val, alg_data->mif.len + 1); | ||
| 184 | |||
| 185 | if (alg_data->mif.len == 0) { | ||
| 186 | if (alg_data->last) { | ||
| 187 | /* Wait until the STOP is seen. */ | ||
| 188 | if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) | ||
| 189 | dev_err(&adap->dev, "The bus is still " | ||
| 190 | "active after timeout\n"); | ||
| 191 | } | ||
| 192 | /* Disable master interrupts */ | ||
| 193 | iowrite32(ioread32(I2C_REG_CTL(alg_data)) & | ||
| 194 | ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie), | ||
| 195 | I2C_REG_CTL(alg_data)); | ||
| 196 | |||
| 197 | del_timer_sync(&alg_data->mif.timer); | ||
| 198 | |||
| 199 | dev_dbg(&adap->dev, "%s(): Waking up xfer routine.\n", | ||
| 200 | __FUNCTION__); | ||
| 201 | |||
| 202 | complete(&alg_data->mif.complete); | ||
| 203 | } | ||
| 204 | } else if (alg_data->mif.len == 0) { | ||
| 205 | /* zero-sized transfer */ | ||
| 206 | i2c_pnx_stop(adap); | ||
| 207 | |||
| 208 | /* Disable master interrupts. */ | ||
| 209 | iowrite32(ioread32(I2C_REG_CTL(alg_data)) & | ||
| 210 | ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie), | ||
| 211 | I2C_REG_CTL(alg_data)); | ||
| 212 | |||
| 213 | /* Stop timer. */ | ||
| 214 | del_timer_sync(&alg_data->mif.timer); | ||
| 215 | dev_dbg(&adap->dev, "%s(): Waking up xfer routine after " | ||
| 216 | "zero-xfer.\n", __FUNCTION__); | ||
| 217 | |||
| 218 | complete(&alg_data->mif.complete); | ||
| 219 | } | ||
| 220 | |||
| 221 | dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n", | ||
| 222 | __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); | ||
| 223 | |||
| 224 | return 0; | ||
| 225 | } | ||
| 226 | |||
| 227 | /** | ||
| 228 | * i2c_pnx_master_rcv - receive data from slave | ||
| 229 | * @adap: pointer to I2C adapter structure | ||
| 230 | * | ||
| 231 | * Reads one byte data from the slave | ||
| 232 | */ | ||
| 233 | static int i2c_pnx_master_rcv(struct i2c_adapter *adap) | ||
| 234 | { | ||
| 235 | struct i2c_pnx_algo_data *alg_data = adap->algo_data; | ||
| 236 | unsigned int val = 0; | ||
| 237 | u32 ctl = 0; | ||
| 238 | |||
| 239 | dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n", | ||
| 240 | __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); | ||
| 241 | |||
| 242 | /* Check, whether there is already data, | ||
| 243 | * or we didn't 'ask' for it yet. | ||
| 244 | */ | ||
| 245 | if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) { | ||
| 246 | dev_dbg(&adap->dev, "%s(): Write dummy data to fill " | ||
| 247 | "Rx-fifo...\n", __FUNCTION__); | ||
| 248 | |||
| 249 | if (alg_data->mif.len == 1) { | ||
| 250 | /* Last byte, do not acknowledge next rcv. */ | ||
| 251 | val |= stop_bit; | ||
| 252 | if (!alg_data->last) | ||
| 253 | val |= start_bit; | ||
| 254 | |||
| 255 | /* | ||
| 256 | * Enable interrupt RFDAIE (data in Rx fifo), | ||
| 257 | * and disable DRMIE (need data for Tx) | ||
| 258 | */ | ||
| 259 | ctl = ioread32(I2C_REG_CTL(alg_data)); | ||
| 260 | ctl |= mcntrl_rffie | mcntrl_daie; | ||
| 261 | ctl &= ~mcntrl_drmie; | ||
| 262 | iowrite32(ctl, I2C_REG_CTL(alg_data)); | ||
| 263 | } | ||
| 264 | |||
| 265 | /* | ||
| 266 | * Now we'll 'ask' for data: | ||
| 267 | * For each byte we want to receive, we must | ||
| 268 | * write a (dummy) byte to the Tx-FIFO. | ||
| 269 | */ | ||
| 270 | iowrite32(val, I2C_REG_TX(alg_data)); | ||
| 271 | |||
| 272 | return 0; | ||
| 273 | } | ||
| 274 | |||
| 275 | /* Handle data. */ | ||
| 276 | if (alg_data->mif.len > 0) { | ||
| 277 | val = ioread32(I2C_REG_RX(alg_data)); | ||
| 278 | *alg_data->mif.buf++ = (u8) (val & 0xff); | ||
| 279 | dev_dbg(&adap->dev, "%s(): rcv 0x%x [%d]\n", __FUNCTION__, val, | ||
| 280 | alg_data->mif.len); | ||
| 281 | |||
| 282 | alg_data->mif.len--; | ||
| 283 | if (alg_data->mif.len == 0) { | ||
| 284 | if (alg_data->last) | ||
| 285 | /* Wait until the STOP is seen. */ | ||
| 286 | if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) | ||
| 287 | dev_err(&adap->dev, "The bus is still " | ||
| 288 | "active after timeout\n"); | ||
| 289 | |||
| 290 | /* Disable master interrupts */ | ||
| 291 | ctl = ioread32(I2C_REG_CTL(alg_data)); | ||
| 292 | ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | | ||
| 293 | mcntrl_drmie | mcntrl_daie); | ||
| 294 | iowrite32(ctl, I2C_REG_CTL(alg_data)); | ||
| 295 | |||
| 296 | /* Kill timer. */ | ||
| 297 | del_timer_sync(&alg_data->mif.timer); | ||
| 298 | complete(&alg_data->mif.complete); | ||
| 299 | } | ||
| 300 | } | ||
| 301 | |||
| 302 | dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n", | ||
| 303 | __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); | ||
| 304 | |||
| 305 | return 0; | ||
| 306 | } | ||
| 307 | |||
| 308 | static irqreturn_t | ||
| 309 | i2c_pnx_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
| 310 | { | ||
| 311 | u32 stat, ctl; | ||
| 312 | struct i2c_adapter *adap = dev_id; | ||
| 313 | struct i2c_pnx_algo_data *alg_data = adap->algo_data; | ||
| 314 | |||
| 315 | dev_dbg(&adap->dev, "%s(): mstat = %x mctrl = %x, mode = %d\n", | ||
| 316 | __FUNCTION__, | ||
| 317 | ioread32(I2C_REG_STS(alg_data)), | ||
| 318 | ioread32(I2C_REG_CTL(alg_data)), | ||
| 319 | alg_data->mif.mode); | ||
| 320 | stat = ioread32(I2C_REG_STS(alg_data)); | ||
| 321 | |||
| 322 | /* let's see what kind of event this is */ | ||
| 323 | if (stat & mstatus_afi) { | ||
| 324 | /* We lost arbitration in the midst of a transfer */ | ||
| 325 | alg_data->mif.ret = -EIO; | ||
| 326 | |||
| 327 | /* Disable master interrupts. */ | ||
| 328 | ctl = ioread32(I2C_REG_CTL(alg_data)); | ||
| 329 | ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | | ||
| 330 | mcntrl_drmie); | ||
| 331 | iowrite32(ctl, I2C_REG_CTL(alg_data)); | ||
| 332 | |||
| 333 | /* Stop timer, to prevent timeout. */ | ||
| 334 | del_timer_sync(&alg_data->mif.timer); | ||
| 335 | complete(&alg_data->mif.complete); | ||
| 336 | } else if (stat & mstatus_nai) { | ||
| 337 | /* Slave did not acknowledge, generate a STOP */ | ||
| 338 | dev_dbg(&adap->dev, "%s(): " | ||
| 339 | "Slave did not acknowledge, generating a STOP.\n", | ||
| 340 | __FUNCTION__); | ||
| 341 | i2c_pnx_stop(adap); | ||
| 342 | |||
| 343 | /* Disable master interrupts. */ | ||
| 344 | ctl = ioread32(I2C_REG_CTL(alg_data)); | ||
| 345 | ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | | ||
| 346 | mcntrl_drmie); | ||
| 347 | iowrite32(ctl, I2C_REG_CTL(alg_data)); | ||
| 348 | |||
| 349 | /* Our return value. */ | ||
| 350 | alg_data->mif.ret = -EIO; | ||
| 351 | |||
| 352 | /* Stop timer, to prevent timeout. */ | ||
| 353 | del_timer_sync(&alg_data->mif.timer); | ||
| 354 | complete(&alg_data->mif.complete); | ||
| 355 | } else { | ||
| 356 | /* | ||
| 357 | * Two options: | ||
| 358 | * - Master Tx needs data. | ||
| 359 | * - There is data in the Rx-fifo | ||
| 360 | * The latter is only the case if we have requested for data, | ||
| 361 | * via a dummy write. (See 'i2c_pnx_master_rcv'.) | ||
| 362 | * We therefore check, as a sanity check, whether that interrupt | ||
| 363 | * has been enabled. | ||
| 364 | */ | ||
| 365 | if ((stat & mstatus_drmi) || !(stat & mstatus_rfe)) { | ||
| 366 | if (alg_data->mif.mode == I2C_SMBUS_WRITE) { | ||
| 367 | i2c_pnx_master_xmit(adap); | ||
| 368 | } else if (alg_data->mif.mode == I2C_SMBUS_READ) { | ||
| 369 | i2c_pnx_master_rcv(adap); | ||
| 370 | } | ||
| 371 | } | ||
| 372 | } | ||
| 373 | |||
| 374 | /* Clear TDI and AFI bits */ | ||
| 375 | stat = ioread32(I2C_REG_STS(alg_data)); | ||
| 376 | iowrite32(stat | mstatus_tdi | mstatus_afi, I2C_REG_STS(alg_data)); | ||
| 377 | |||
| 378 | dev_dbg(&adap->dev, "%s(): exiting, stat = %x ctrl = %x.\n", | ||
| 379 | __FUNCTION__, ioread32(I2C_REG_STS(alg_data)), | ||
| 380 | ioread32(I2C_REG_CTL(alg_data))); | ||
| 381 | |||
| 382 | return IRQ_HANDLED; | ||
| 383 | } | ||
| 384 | |||
| 385 | static void i2c_pnx_timeout(unsigned long data) | ||
| 386 | { | ||
| 387 | struct i2c_adapter *adap = (struct i2c_adapter *)data; | ||
| 388 | struct i2c_pnx_algo_data *alg_data = adap->algo_data; | ||
| 389 | u32 ctl; | ||
| 390 | |||
| 391 | dev_err(&adap->dev, "Master timed out. stat = %04x, cntrl = %04x. " | ||
| 392 | "Resetting master...\n", | ||
| 393 | ioread32(I2C_REG_STS(alg_data)), | ||
| 394 | ioread32(I2C_REG_CTL(alg_data))); | ||
| 395 | |||
| 396 | /* Reset master and disable interrupts */ | ||
| 397 | ctl = ioread32(I2C_REG_CTL(alg_data)); | ||
| 398 | ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | mcntrl_drmie); | ||
| 399 | iowrite32(ctl, I2C_REG_CTL(alg_data)); | ||
| 400 | |||
| 401 | ctl |= mcntrl_reset; | ||
| 402 | iowrite32(ctl, I2C_REG_CTL(alg_data)); | ||
| 403 | wait_reset(I2C_PNX_TIMEOUT, alg_data); | ||
| 404 | alg_data->mif.ret = -EIO; | ||
| 405 | complete(&alg_data->mif.complete); | ||
| 406 | } | ||
| 407 | |||
| 408 | static inline void bus_reset_if_active(struct i2c_adapter *adap) | ||
| 409 | { | ||
| 410 | struct i2c_pnx_algo_data *alg_data = adap->algo_data; | ||
| 411 | u32 stat; | ||
| 412 | |||
| 413 | if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_active) { | ||
| 414 | dev_err(&adap->dev, | ||
| 415 | "%s: Bus is still active after xfer. Reset it...\n", | ||
| 416 | adap->name); | ||
| 417 | iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, | ||
| 418 | I2C_REG_CTL(alg_data)); | ||
| 419 | wait_reset(I2C_PNX_TIMEOUT, alg_data); | ||
| 420 | } else if (!(stat & mstatus_rfe) || !(stat & mstatus_tfe)) { | ||
| 421 | /* If there is data in the fifo's after transfer, | ||
| 422 | * flush fifo's by reset. | ||
| 423 | */ | ||
| 424 | iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, | ||
| 425 | I2C_REG_CTL(alg_data)); | ||
| 426 | wait_reset(I2C_PNX_TIMEOUT, alg_data); | ||
| 427 | } else if (stat & mstatus_nai) { | ||
| 428 | iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, | ||
| 429 | I2C_REG_CTL(alg_data)); | ||
| 430 | wait_reset(I2C_PNX_TIMEOUT, alg_data); | ||
| 431 | } | ||
| 432 | } | ||
| 433 | |||
| 434 | /** | ||
| 435 | * i2c_pnx_xfer - generic transfer entry point | ||
| 436 | * @adap: pointer to I2C adapter structure | ||
| 437 | * @msgs: array of messages | ||
| 438 | * @num: number of messages | ||
| 439 | * | ||
| 440 | * Initiates the transfer | ||
| 441 | */ | ||
| 442 | static int | ||
| 443 | i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | ||
| 444 | { | ||
| 445 | struct i2c_msg *pmsg; | ||
| 446 | int rc = 0, completed = 0, i; | ||
| 447 | struct i2c_pnx_algo_data *alg_data = adap->algo_data; | ||
| 448 | u32 stat = ioread32(I2C_REG_STS(alg_data)); | ||
| 449 | |||
| 450 | dev_dbg(&adap->dev, "%s(): entering: %d messages, stat = %04x.\n", | ||
| 451 | __FUNCTION__, num, ioread32(I2C_REG_STS(alg_data))); | ||
| 452 | |||
| 453 | bus_reset_if_active(adap); | ||
| 454 | |||
| 455 | /* Process transactions in a loop. */ | ||
| 456 | for (i = 0; rc >= 0 && i < num; i++) { | ||
| 457 | u8 addr; | ||
| 458 | |||
| 459 | pmsg = &msgs[i]; | ||
| 460 | addr = pmsg->addr; | ||
| 461 | |||
| 462 | if (pmsg->flags & I2C_M_TEN) { | ||
| 463 | dev_err(&adap->dev, | ||
| 464 | "%s: 10 bits addr not supported!\n", | ||
| 465 | adap->name); | ||
| 466 | rc = -EINVAL; | ||
| 467 | break; | ||
| 468 | } | ||
| 469 | |||
| 470 | alg_data->mif.buf = pmsg->buf; | ||
| 471 | alg_data->mif.len = pmsg->len; | ||
| 472 | alg_data->mif.mode = (pmsg->flags & I2C_M_RD) ? | ||
| 473 | I2C_SMBUS_READ : I2C_SMBUS_WRITE; | ||
| 474 | alg_data->mif.ret = 0; | ||
| 475 | alg_data->last = (i == num - 1); | ||
| 476 | |||
| 477 | dev_dbg(&adap->dev, "%s(): mode %d, %d bytes\n", __FUNCTION__, | ||
| 478 | alg_data->mif.mode, | ||
| 479 | alg_data->mif.len); | ||
| 480 | |||
| 481 | i2c_pnx_arm_timer(adap); | ||
| 482 | |||
| 483 | /* initialize the completion var */ | ||
| 484 | init_completion(&alg_data->mif.complete); | ||
| 485 | |||
| 486 | /* Enable master interrupt */ | ||
| 487 | iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_afie | | ||
| 488 | mcntrl_naie | mcntrl_drmie, | ||
| 489 | I2C_REG_CTL(alg_data)); | ||
| 490 | |||
| 491 | /* Put start-code and slave-address on the bus. */ | ||
| 492 | rc = i2c_pnx_start(addr, adap); | ||
| 493 | if (rc < 0) | ||
| 494 | break; | ||
| 495 | |||
| 496 | /* Wait for completion */ | ||
| 497 | wait_for_completion(&alg_data->mif.complete); | ||
| 498 | |||
| 499 | if (!(rc = alg_data->mif.ret)) | ||
| 500 | completed++; | ||
| 501 | dev_dbg(&adap->dev, "%s(): Complete, return code = %d.\n", | ||
| 502 | __FUNCTION__, rc); | ||
| 503 | |||
| 504 | /* Clear TDI and AFI bits in case they are set. */ | ||
| 505 | if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_tdi) { | ||
| 506 | dev_dbg(&adap->dev, | ||
| 507 | "%s: TDI still set... clearing now.\n", | ||
| 508 | adap->name); | ||
| 509 | iowrite32(stat, I2C_REG_STS(alg_data)); | ||
| 510 | } | ||
| 511 | if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_afi) { | ||
| 512 | dev_dbg(&adap->dev, | ||
| 513 | "%s: AFI still set... clearing now.\n", | ||
| 514 | adap->name); | ||
| 515 | iowrite32(stat, I2C_REG_STS(alg_data)); | ||
| 516 | } | ||
| 517 | } | ||
| 518 | |||
| 519 | bus_reset_if_active(adap); | ||
| 520 | |||
| 521 | /* Cleanup to be sure... */ | ||
| 522 | alg_data->mif.buf = NULL; | ||
| 523 | alg_data->mif.len = 0; | ||
| 524 | |||
| 525 | dev_dbg(&adap->dev, "%s(): exiting, stat = %x\n", | ||
| 526 | __FUNCTION__, ioread32(I2C_REG_STS(alg_data))); | ||
| 527 | |||
| 528 | if (completed != num) | ||
| 529 | return ((rc < 0) ? rc : -EREMOTEIO); | ||
| 530 | |||
| 531 | return num; | ||
| 532 | } | ||
| 533 | |||
| 534 | static u32 i2c_pnx_func(struct i2c_adapter *adapter) | ||
| 535 | { | ||
| 536 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | ||
| 537 | } | ||
| 538 | |||
| 539 | static struct i2c_algorithm pnx_algorithm = { | ||
| 540 | .master_xfer = i2c_pnx_xfer, | ||
| 541 | .functionality = i2c_pnx_func, | ||
| 542 | }; | ||
| 543 | |||
| 544 | static int i2c_pnx_controller_suspend(struct platform_device *pdev, | ||
| 545 | pm_message_t state) | ||
| 546 | { | ||
| 547 | struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); | ||
| 548 | return i2c_pnx->suspend(pdev, state); | ||
| 549 | } | ||
| 550 | |||
| 551 | static int i2c_pnx_controller_resume(struct platform_device *pdev) | ||
| 552 | { | ||
| 553 | struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); | ||
| 554 | return i2c_pnx->resume(pdev); | ||
| 555 | } | ||
| 556 | |||
| 557 | static int __devinit i2c_pnx_probe(struct platform_device *pdev) | ||
| 558 | { | ||
| 559 | unsigned long tmp; | ||
| 560 | int ret = 0; | ||
| 561 | struct i2c_pnx_algo_data *alg_data; | ||
| 562 | int freq_mhz; | ||
| 563 | struct i2c_pnx_data *i2c_pnx = pdev->dev.platform_data; | ||
| 564 | |||
| 565 | if (!i2c_pnx || !i2c_pnx->adapter) { | ||
| 566 | dev_err(&pdev->dev, "%s: no platform data supplied\n", | ||
| 567 | __FUNCTION__); | ||
| 568 | ret = -EINVAL; | ||
| 569 | goto out; | ||
| 570 | } | ||
| 571 | |||
| 572 | platform_set_drvdata(pdev, i2c_pnx); | ||
| 573 | |||
| 574 | if (i2c_pnx->calculate_input_freq) | ||
| 575 | freq_mhz = i2c_pnx->calculate_input_freq(pdev); | ||
| 576 | else { | ||
| 577 | freq_mhz = PNX_DEFAULT_FREQ; | ||
| 578 | dev_info(&pdev->dev, "Setting bus frequency to default value: " | ||
| 579 | "%d MHz", freq_mhz); | ||
| 580 | } | ||
| 581 | |||
| 582 | i2c_pnx->adapter->algo = &pnx_algorithm; | ||
| 583 | |||
| 584 | alg_data = i2c_pnx->adapter->algo_data; | ||
| 585 | init_timer(&alg_data->mif.timer); | ||
| 586 | alg_data->mif.timer.function = i2c_pnx_timeout; | ||
| 587 | alg_data->mif.timer.data = (unsigned long)i2c_pnx->adapter; | ||
| 588 | |||
| 589 | /* Register I/O resource */ | ||
| 590 | if (!request_region(alg_data->base, I2C_PNX_REGION_SIZE, pdev->name)) { | ||
| 591 | dev_err(&pdev->dev, | ||
| 592 | "I/O region 0x%08x for I2C already in use.\n", | ||
| 593 | alg_data->base); | ||
| 594 | ret = -ENODEV; | ||
| 595 | goto out_drvdata; | ||
| 596 | } | ||
| 597 | |||
| 598 | if (!(alg_data->ioaddr = | ||
| 599 | (u32)ioremap(alg_data->base, I2C_PNX_REGION_SIZE))) { | ||
| 600 | dev_err(&pdev->dev, "Couldn't ioremap I2C I/O region\n"); | ||
| 601 | ret = -ENOMEM; | ||
| 602 | goto out_release; | ||
| 603 | } | ||
| 604 | |||
| 605 | i2c_pnx->set_clock_run(pdev); | ||
| 606 | |||
| 607 | /* | ||
| 608 | * Clock Divisor High This value is the number of system clocks | ||
| 609 | * the serial clock (SCL) will be high. | ||
| 610 | * For example, if the system clock period is 50 ns and the maximum | ||
| 611 | * desired serial period is 10000 ns (100 kHz), then CLKHI would be | ||
| 612 | * set to 0.5*(f_sys/f_i2c)-2=0.5*(20e6/100e3)-2=98. The actual value | ||
| 613 | * programmed into CLKHI will vary from this slightly due to | ||
| 614 | * variations in the output pad's rise and fall times as well as | ||
| 615 | * the deglitching filter length. | ||
| 616 | */ | ||
| 617 | |||
| 618 | tmp = ((freq_mhz * 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2; | ||
| 619 | iowrite32(tmp, I2C_REG_CKH(alg_data)); | ||
| 620 | iowrite32(tmp, I2C_REG_CKL(alg_data)); | ||
| 621 | |||
| 622 | iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data)); | ||
| 623 | if (wait_reset(I2C_PNX_TIMEOUT, alg_data)) { | ||
| 624 | ret = -ENODEV; | ||
| 625 | goto out_unmap; | ||
| 626 | } | ||
| 627 | init_completion(&alg_data->mif.complete); | ||
| 628 | |||
| 629 | ret = request_irq(alg_data->irq, i2c_pnx_interrupt, | ||
| 630 | 0, pdev->name, i2c_pnx->adapter); | ||
| 631 | if (ret) | ||
| 632 | goto out_clock; | ||
| 633 | |||
| 634 | /* Register this adapter with the I2C subsystem */ | ||
| 635 | i2c_pnx->adapter->dev.parent = &pdev->dev; | ||
| 636 | ret = i2c_add_adapter(i2c_pnx->adapter); | ||
| 637 | if (ret < 0) { | ||
| 638 | dev_err(&pdev->dev, "I2C: Failed to add bus\n"); | ||
| 639 | goto out_irq; | ||
| 640 | } | ||
| 641 | |||
| 642 | dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n", | ||
| 643 | i2c_pnx->adapter->name, alg_data->base, alg_data->irq); | ||
| 644 | |||
| 645 | return 0; | ||
| 646 | |||
| 647 | out_irq: | ||
| 648 | free_irq(alg_data->irq, alg_data); | ||
| 649 | out_clock: | ||
| 650 | i2c_pnx->set_clock_stop(pdev); | ||
| 651 | out_unmap: | ||
| 652 | iounmap((void *)alg_data->ioaddr); | ||
| 653 | out_release: | ||
| 654 | release_region(alg_data->base, I2C_PNX_REGION_SIZE); | ||
| 655 | out_drvdata: | ||
| 656 | platform_set_drvdata(pdev, NULL); | ||
| 657 | out: | ||
| 658 | return ret; | ||
| 659 | } | ||
| 660 | |||
| 661 | static int __devexit i2c_pnx_remove(struct platform_device *pdev) | ||
| 662 | { | ||
| 663 | struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); | ||
| 664 | struct i2c_adapter *adap = i2c_pnx->adapter; | ||
| 665 | struct i2c_pnx_algo_data *alg_data = adap->algo_data; | ||
| 666 | |||
| 667 | free_irq(alg_data->irq, alg_data); | ||
| 668 | i2c_del_adapter(adap); | ||
| 669 | i2c_pnx->set_clock_stop(pdev); | ||
| 670 | iounmap((void *)alg_data->ioaddr); | ||
| 671 | release_region(alg_data->base, I2C_PNX_REGION_SIZE); | ||
| 672 | platform_set_drvdata(pdev, NULL); | ||
| 673 | |||
| 674 | return 0; | ||
| 675 | } | ||
| 676 | |||
| 677 | static struct platform_driver i2c_pnx_driver = { | ||
| 678 | .driver = { | ||
| 679 | .name = "pnx-i2c", | ||
| 680 | .owner = THIS_MODULE, | ||
| 681 | }, | ||
| 682 | .probe = i2c_pnx_probe, | ||
| 683 | .remove = __devexit_p(i2c_pnx_remove), | ||
| 684 | .suspend = i2c_pnx_controller_suspend, | ||
| 685 | .resume = i2c_pnx_controller_resume, | ||
| 686 | }; | ||
| 687 | |||
| 688 | static int __init i2c_adap_pnx_init(void) | ||
| 689 | { | ||
| 690 | return platform_driver_register(&i2c_pnx_driver); | ||
| 691 | } | ||
| 692 | |||
| 693 | static void __exit i2c_adap_pnx_exit(void) | ||
| 694 | { | ||
| 695 | platform_driver_unregister(&i2c_pnx_driver); | ||
| 696 | } | ||
| 697 | |||
| 698 | MODULE_AUTHOR("Vitaly Wool, Dennis Kovalev <source@mvista.com>"); | ||
| 699 | MODULE_DESCRIPTION("I2C driver for Philips IP3204-based I2C busses"); | ||
| 700 | MODULE_LICENSE("GPL"); | ||
| 701 | |||
| 702 | #ifdef CONFIG_I2C_PNX_EARLY | ||
| 703 | /* We need to make sure I2C is initialized before USB */ | ||
| 704 | subsys_initcall(i2c_adap_pnx_init); | ||
| 705 | #else | ||
| 706 | mudule_init(i2c_adap_pnx_init); | ||
| 707 | #endif | ||
| 708 | module_exit(i2c_adap_pnx_exit); | ||
diff --git a/include/asm-arm/arch-pnx4008/i2c.h b/include/asm-arm/arch-pnx4008/i2c.h new file mode 100644 index 000000000000..92e8d65006f7 --- /dev/null +++ b/include/asm-arm/arch-pnx4008/i2c.h | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | /* | ||
| 2 | * PNX4008-specific tweaks for I2C IP3204 block | ||
| 3 | * | ||
| 4 | * Author: Vitaly Wool <vwool@ru.mvista.com> | ||
| 5 | * | ||
| 6 | * 2005 (c) MontaVista Software, Inc. This file is licensed under | ||
| 7 | * the terms of the GNU General Public License version 2. This program | ||
| 8 | * is licensed "as is" without any warranty of any kind, whether express | ||
| 9 | * or implied. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef __ASM_ARCH_I2C_H__ | ||
| 13 | #define __ASM_ARCH_I2C_H__ | ||
| 14 | |||
| 15 | #include <linux/pm.h> | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | |||
| 18 | enum { | ||
| 19 | mstatus_tdi = 0x00000001, | ||
| 20 | mstatus_afi = 0x00000002, | ||
| 21 | mstatus_nai = 0x00000004, | ||
| 22 | mstatus_drmi = 0x00000008, | ||
| 23 | mstatus_active = 0x00000020, | ||
| 24 | mstatus_scl = 0x00000040, | ||
| 25 | mstatus_sda = 0x00000080, | ||
| 26 | mstatus_rff = 0x00000100, | ||
| 27 | mstatus_rfe = 0x00000200, | ||
| 28 | mstatus_tff = 0x00000400, | ||
| 29 | mstatus_tfe = 0x00000800, | ||
| 30 | }; | ||
| 31 | |||
| 32 | enum { | ||
| 33 | mcntrl_tdie = 0x00000001, | ||
| 34 | mcntrl_afie = 0x00000002, | ||
| 35 | mcntrl_naie = 0x00000004, | ||
| 36 | mcntrl_drmie = 0x00000008, | ||
| 37 | mcntrl_daie = 0x00000020, | ||
| 38 | mcntrl_rffie = 0x00000040, | ||
| 39 | mcntrl_tffie = 0x00000080, | ||
| 40 | mcntrl_reset = 0x00000100, | ||
| 41 | mcntrl_cdbmode = 0x00000400, | ||
| 42 | }; | ||
| 43 | |||
| 44 | enum { | ||
| 45 | rw_bit = 1 << 0, | ||
| 46 | start_bit = 1 << 8, | ||
| 47 | stop_bit = 1 << 9, | ||
| 48 | }; | ||
| 49 | |||
| 50 | #define I2C_REG_RX(a) ((a)->ioaddr) /* Rx FIFO reg (RO) */ | ||
| 51 | #define I2C_REG_TX(a) ((a)->ioaddr) /* Tx FIFO reg (WO) */ | ||
| 52 | #define I2C_REG_STS(a) ((a)->ioaddr + 0x04) /* Status reg (RO) */ | ||
| 53 | #define I2C_REG_CTL(a) ((a)->ioaddr + 0x08) /* Ctl reg */ | ||
| 54 | #define I2C_REG_CKL(a) ((a)->ioaddr + 0x0c) /* Clock divider low */ | ||
| 55 | #define I2C_REG_CKH(a) ((a)->ioaddr + 0x10) /* Clock divider high */ | ||
| 56 | #define I2C_REG_ADR(a) ((a)->ioaddr + 0x14) /* I2C address */ | ||
| 57 | #define I2C_REG_RFL(a) ((a)->ioaddr + 0x18) /* Rx FIFO level (RO) */ | ||
| 58 | #define I2C_REG_TFL(a) ((a)->ioaddr + 0x1c) /* Tx FIFO level (RO) */ | ||
| 59 | #define I2C_REG_RXB(a) ((a)->ioaddr + 0x20) /* Num of bytes Rx-ed (RO) */ | ||
| 60 | #define I2C_REG_TXB(a) ((a)->ioaddr + 0x24) /* Num of bytes Tx-ed (RO) */ | ||
| 61 | #define I2C_REG_TXS(a) ((a)->ioaddr + 0x28) /* Tx slave FIFO (RO) */ | ||
| 62 | #define I2C_REG_STFL(a) ((a)->ioaddr + 0x2c) /* Tx slave FIFO level (RO) */ | ||
| 63 | |||
| 64 | #define HCLK_MHZ 13 | ||
| 65 | #define I2C_CHIP_NAME "PNX4008-I2C" | ||
| 66 | |||
| 67 | #endif /* __ASM_ARCH_I2C_H___ */ | ||
diff --git a/include/linux/i2c-pnx.h b/include/linux/i2c-pnx.h new file mode 100644 index 000000000000..e6e9c814da61 --- /dev/null +++ b/include/linux/i2c-pnx.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | /* | ||
| 2 | * Header file for I2C support on PNX010x/4008. | ||
| 3 | * | ||
| 4 | * Author: Dennis Kovalev <dkovalev@ru.mvista.com> | ||
| 5 | * | ||
| 6 | * 2004-2006 (c) MontaVista Software, Inc. This file is licensed under | ||
| 7 | * the terms of the GNU General Public License version 2. This program | ||
| 8 | * is licensed "as is" without any warranty of any kind, whether express | ||
| 9 | * or implied. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef __I2C_PNX_H__ | ||
| 13 | #define __I2C_PNX_H__ | ||
| 14 | |||
| 15 | #include <asm/arch/i2c.h> | ||
| 16 | |||
| 17 | struct i2c_pnx_mif { | ||
| 18 | int ret; /* Return value */ | ||
| 19 | int mode; /* Interface mode */ | ||
| 20 | struct completion complete; /* I/O completion */ | ||
| 21 | struct timer_list timer; /* Timeout */ | ||
| 22 | char * buf; /* Data buffer */ | ||
| 23 | int len; /* Length of data buffer */ | ||
| 24 | }; | ||
| 25 | |||
| 26 | struct i2c_pnx_algo_data { | ||
| 27 | u32 base; | ||
| 28 | u32 ioaddr; | ||
| 29 | int irq; | ||
| 30 | struct i2c_pnx_mif mif; | ||
| 31 | int last; | ||
| 32 | }; | ||
| 33 | |||
| 34 | struct i2c_pnx_data { | ||
| 35 | int (*suspend) (struct platform_device *pdev, pm_message_t state); | ||
| 36 | int (*resume) (struct platform_device *pdev); | ||
| 37 | u32 (*calculate_input_freq) (struct platform_device *pdev); | ||
| 38 | int (*set_clock_run) (struct platform_device *pdev); | ||
| 39 | int (*set_clock_stop) (struct platform_device *pdev); | ||
| 40 | struct i2c_adapter *adapter; | ||
| 41 | }; | ||
| 42 | |||
| 43 | #endif /* __I2C_PNX_H__ */ | ||
