diff options
Diffstat (limited to 'drivers/i2c/busses')
-rw-r--r-- | drivers/i2c/busses/Kconfig | 10 | ||||
-rw-r--r-- | drivers/i2c/busses/Makefile | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-octeon.c | 651 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pnx.c | 285 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-tiny-usb.c | 12 |
5 files changed, 823 insertions, 136 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 5f318ce2977..737f05200b1 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -564,6 +564,16 @@ config I2C_VERSATILE This driver can also be built as a module. If so, the module will be called i2c-versatile. +config I2C_OCTEON + tristate "Cavium OCTEON I2C bus support" + depends on CPU_CAVIUM_OCTEON + help + Say yes if you want to support the I2C serial bus on Cavium + OCTEON SOC. + + This driver can also be built as a module. If so, the module + will be called i2c-octeon. + comment "External I2C/SMBus adapter drivers" config I2C_PARPORT diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 302c551977b..c2c4ea1908d 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o obj-$(CONFIG_I2C_STU300) += i2c-stu300.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o +obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o # External I2C/SMBus adapter drivers obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c new file mode 100644 index 00000000000..60375504fa4 --- /dev/null +++ b/drivers/i2c/busses/i2c-octeon.c @@ -0,0 +1,651 @@ +/* + * (C) Copyright 2009-2010 + * Nokia Siemens Networks, michael.lawnick.ext@nsn.com + * + * Portions Copyright (C) 2010 Cavium Networks, Inc. + * + * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/init.h> + +#include <linux/io.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/platform_device.h> + +#include <asm/octeon/octeon.h> + +#define DRV_NAME "i2c-octeon" + +/* The previous out-of-tree version was implicitly version 1.0. */ +#define DRV_VERSION "2.0" + +/* register offsets */ +#define SW_TWSI 0x00 +#define TWSI_INT 0x10 + +/* Controller command patterns */ +#define SW_TWSI_V 0x8000000000000000ull +#define SW_TWSI_EOP_TWSI_DATA 0x0C00000100000000ull +#define SW_TWSI_EOP_TWSI_CTL 0x0C00000200000000ull +#define SW_TWSI_EOP_TWSI_CLKCTL 0x0C00000300000000ull +#define SW_TWSI_EOP_TWSI_STAT 0x0C00000300000000ull +#define SW_TWSI_EOP_TWSI_RST 0x0C00000700000000ull +#define SW_TWSI_OP_TWSI_CLK 0x0800000000000000ull +#define SW_TWSI_R 0x0100000000000000ull + +/* Controller command and status bits */ +#define TWSI_CTL_CE 0x80 +#define TWSI_CTL_ENAB 0x40 +#define TWSI_CTL_STA 0x20 +#define TWSI_CTL_STP 0x10 +#define TWSI_CTL_IFLG 0x08 +#define TWSI_CTL_AAK 0x04 + +/* Some status values */ +#define STAT_START 0x08 +#define STAT_RSTART 0x10 +#define STAT_TXADDR_ACK 0x18 +#define STAT_TXDATA_ACK 0x28 +#define STAT_RXADDR_ACK 0x40 +#define STAT_RXDATA_ACK 0x50 +#define STAT_IDLE 0xF8 + +struct octeon_i2c { + wait_queue_head_t queue; + struct i2c_adapter adap; + int irq; + int twsi_freq; + int sys_freq; + resource_size_t twsi_phys; + void __iomem *twsi_base; + resource_size_t regsize; + struct device *dev; +}; + +/** + * octeon_i2c_write_sw - write an I2C core register. + * @i2c: The struct octeon_i2c. + * @eop_reg: Register selector. + * @data: Value to be written. + * + * The I2C core registers are accessed indirectly via the SW_TWSI CSR. + */ +static void octeon_i2c_write_sw(struct octeon_i2c *i2c, + u64 eop_reg, + u8 data) +{ + u64 tmp; + + __raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI); + do { + tmp = __raw_readq(i2c->twsi_base + SW_TWSI); + } while ((tmp & SW_TWSI_V) != 0); +} + +/** + * octeon_i2c_read_sw - write an I2C core register. + * @i2c: The struct octeon_i2c. + * @eop_reg: Register selector. + * + * Returns the data. + * + * The I2C core registers are accessed indirectly via the SW_TWSI CSR. + */ +static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 eop_reg) +{ + u64 tmp; + + __raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI); + do { + tmp = __raw_readq(i2c->twsi_base + SW_TWSI); + } while ((tmp & SW_TWSI_V) != 0); + + return tmp & 0xFF; +} + +/** + * octeon_i2c_write_int - write the TWSI_INT register + * @i2c: The struct octeon_i2c. + * @data: Value to be written. + */ +static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data) +{ + u64 tmp; + + __raw_writeq(data, i2c->twsi_base + TWSI_INT); + tmp = __raw_readq(i2c->twsi_base + TWSI_INT); +} + +/** + * octeon_i2c_int_enable - enable the TS interrupt. + * @i2c: The struct octeon_i2c. + * + * The interrupt will be asserted when there is non-STAT_IDLE state in + * the SW_TWSI_EOP_TWSI_STAT register. + */ +static void octeon_i2c_int_enable(struct octeon_i2c *i2c) +{ + octeon_i2c_write_int(i2c, 0x40); +} + +/** + * octeon_i2c_int_disable - disable the TS interrupt. + * @i2c: The struct octeon_i2c. + */ +static void octeon_i2c_int_disable(struct octeon_i2c *i2c) +{ + octeon_i2c_write_int(i2c, 0); +} + +/** + * octeon_i2c_unblock - unblock the bus. + * @i2c: The struct octeon_i2c. + * + * If there was a reset while a device was driving 0 to bus, + * bus is blocked. We toggle it free manually by some clock + * cycles and send a stop. + */ +static void octeon_i2c_unblock(struct octeon_i2c *i2c) +{ + int i; + + dev_dbg(i2c->dev, "%s\n", __func__); + for (i = 0; i < 9; i++) { + octeon_i2c_write_int(i2c, 0x0); + udelay(5); + octeon_i2c_write_int(i2c, 0x200); + udelay(5); + } + octeon_i2c_write_int(i2c, 0x300); + udelay(5); + octeon_i2c_write_int(i2c, 0x100); + udelay(5); + octeon_i2c_write_int(i2c, 0x0); +} + +/** + * octeon_i2c_isr - the interrupt service routine. + * @int: The irq, unused. + * @dev_id: Our struct octeon_i2c. + */ +static irqreturn_t octeon_i2c_isr(int irq, void *dev_id) +{ + struct octeon_i2c *i2c = dev_id; + + octeon_i2c_int_disable(i2c); + wake_up_interruptible(&i2c->queue); + + return IRQ_HANDLED; +} + + +static int octeon_i2c_test_iflg(struct octeon_i2c *i2c) +{ + return (octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_CTL) & TWSI_CTL_IFLG) != 0; +} + +/** + * octeon_i2c_wait - wait for the IFLG to be set. + * @i2c: The struct octeon_i2c. + * + * Returns 0 on success, otherwise a negative errno. + */ +static int octeon_i2c_wait(struct octeon_i2c *i2c) +{ + int result; + + octeon_i2c_int_enable(i2c); + + result = wait_event_interruptible_timeout(i2c->queue, + octeon_i2c_test_iflg(i2c), + i2c->adap.timeout); + + octeon_i2c_int_disable(i2c); + + if (result < 0) { + dev_dbg(i2c->dev, "%s: wait interrupted\n", __func__); + return result; + } else if (result == 0) { + dev_dbg(i2c->dev, "%s: timeout\n", __func__); + result = -ETIMEDOUT; + } + + return 0; +} + +/** + * octeon_i2c_start - send START to the bus. + * @i2c: The struct octeon_i2c. + * + * Returns 0 on success, otherwise a negative errno. + */ +static int octeon_i2c_start(struct octeon_i2c *i2c) +{ + u8 data; + int result; + + octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, + TWSI_CTL_ENAB | TWSI_CTL_STA); + + result = octeon_i2c_wait(i2c); + if (result) { + if (octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT) == STAT_IDLE) { + /* + * Controller refused to send start flag May + * be a client is holding SDA low - let's try + * to free it. + */ + octeon_i2c_unblock(i2c); + octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, + TWSI_CTL_ENAB | TWSI_CTL_STA); + + result = octeon_i2c_wait(i2c); + } + if (result) + return result; + } + + data = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT); + if ((data != STAT_START) && (data != STAT_RSTART)) { + dev_err(i2c->dev, "%s: bad status (0x%x)\n", __func__, data); + return -EIO; + } + + return 0; +} + +/** + * octeon_i2c_stop - send STOP to the bus. + * @i2c: The struct octeon_i2c. + * + * Returns 0 on success, otherwise a negative errno. + */ +static int octeon_i2c_stop(struct octeon_i2c *i2c) +{ + u8 data; + + octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, + TWSI_CTL_ENAB | TWSI_CTL_STP); + + data = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT); + + if (data != STAT_IDLE) { + dev_err(i2c->dev, "%s: bad status(0x%x)\n", __func__, data); + return -EIO; + } + return 0; +} + +/** + * octeon_i2c_write - send data to the bus. + * @i2c: The struct octeon_i2c. + * @target: Target address. + * @data: Pointer to the data to be sent. + * @length: Length of the data. + * + * The address is sent over the bus, then the data. + * + * Returns 0 on success, otherwise a negative errno. + */ +static int octeon_i2c_write(struct octeon_i2c *i2c, int target, + const u8 *data, int length) +{ + int i, result; + u8 tmp; + + result = octeon_i2c_start(i2c); + if (result) + return result; + + octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, target << 1); + octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB); + + result = octeon_i2c_wait(i2c); + if (result) + return result; + + for (i = 0; i < length; i++) { + tmp = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT); + if ((tmp != STAT_TXADDR_ACK) && (tmp != STAT_TXDATA_ACK)) { + dev_err(i2c->dev, + "%s: bad status before write (0x%x)\n", + __func__, tmp); + return -EIO; + } + + octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, data[i]); + octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB); + + result = octeon_i2c_wait(i2c); + if (result) + return result; + } + + return 0; +} + +/** + * octeon_i2c_read - receive data from the bus. + * @i2c: The struct octeon_i2c. + * @target: Target address. + * @data: Pointer to the location to store the datae . + * @length: Length of the data. + * + * The address is sent over the bus, then the data is read. + * + * Returns 0 on success, otherwise a negative errno. + */ +static int octeon_i2c_read(struct octeon_i2c *i2c, int target, + u8 *data, int length) +{ + int i, result; + u8 tmp; + + if (length < 1) + return -EINVAL; + + result = octeon_i2c_start(i2c); + if (result) + return result; + + octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, (target<<1) | 1); + octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB); + + result = octeon_i2c_wait(i2c); + if (result) + return result; + + for (i = 0; i < length; i++) { + tmp = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT); + if ((tmp != STAT_RXDATA_ACK) && (tmp != STAT_RXADDR_ACK)) { + dev_err(i2c->dev, + "%s: bad status before read (0x%x)\n", + __func__, tmp); + return -EIO; + } + + if (i+1 < length) + octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, + TWSI_CTL_ENAB | TWSI_CTL_AAK); + else + octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, + TWSI_CTL_ENAB); + + result = octeon_i2c_wait(i2c); + if (result) + return result; + + data[i] = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_DATA); + } + return 0; +} + +/** + * octeon_i2c_xfer - The driver's master_xfer function. + * @adap: Pointer to the i2c_adapter structure. + * @msgs: Pointer to the messages to be processed. + * @num: Length of the MSGS array. + * + * Returns the number of messages processed, or a negative errno on + * failure. + */ +static int octeon_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, + int num) +{ + struct i2c_msg *pmsg; + int i; + int ret = 0; + struct octeon_i2c *i2c = i2c_get_adapdata(adap); + + for (i = 0; ret == 0 && i < num; i++) { + pmsg = &msgs[i]; + dev_dbg(i2c->dev, + "Doing %s %d byte(s) to/from 0x%02x - %d of %d messages\n", + pmsg->flags & I2C_M_RD ? "read" : "write", + pmsg->len, pmsg->addr, i + 1, num); + if (pmsg->flags & I2C_M_RD) + ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf, + pmsg->len); + else + ret = octeon_i2c_write(i2c, pmsg->addr, pmsg->buf, + pmsg->len); + } + octeon_i2c_stop(i2c); + + return (ret != 0) ? ret : num; +} + +static u32 octeon_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm octeon_i2c_algo = { + .master_xfer = octeon_i2c_xfer, + .functionality = octeon_i2c_functionality, +}; + +static struct i2c_adapter octeon_i2c_ops = { + .owner = THIS_MODULE, + .name = "OCTEON adapter", + .algo = &octeon_i2c_algo, + .timeout = 2, +}; + +/** + * octeon_i2c_setclock - Calculate and set clock divisors. + */ +static int __init octeon_i2c_setclock(struct octeon_i2c *i2c) +{ + int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff; + int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 1000000; + + for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) { + /* + * An mdiv value of less than 2 seems to not work well + * with ds1337 RTCs, so we constrain it to larger + * values. + */ + for (mdiv_idx = 15; mdiv_idx >= 2 && delta_hz != 0; mdiv_idx--) { + /* + * For given ndiv and mdiv values check the + * two closest thp values. + */ + tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10; + tclk *= (1 << ndiv_idx); + thp_base = (i2c->sys_freq / (tclk * 2)) - 1; + for (inc = 0; inc <= 1; inc++) { + thp_idx = thp_base + inc; + if (thp_idx < 5 || thp_idx > 0xff) + continue; + + foscl = i2c->sys_freq / (2 * (thp_idx + 1)); + foscl = foscl / (1 << ndiv_idx); + foscl = foscl / (mdiv_idx + 1) / 10; + diff = abs(foscl - i2c->twsi_freq); + if (diff < delta_hz) { + delta_hz = diff; + thp = thp_idx; + mdiv = mdiv_idx; + ndiv = ndiv_idx; + } + } + } + } + octeon_i2c_write_sw(i2c, SW_TWSI_OP_TWSI_CLK, thp); + octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv); + + return 0; +} + +static int __init octeon_i2c_initlowlevel(struct octeon_i2c *i2c) +{ + u8 status; + int tries; + + /* disable high level controller, enable bus access */ + octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB); + + /* reset controller */ + octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_RST, 0); + + for (tries = 10; tries; tries--) { + udelay(1); + status = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT); + if (status == STAT_IDLE) + return 0; + } + dev_err(i2c->dev, "%s: TWSI_RST failed! (0x%x)\n", __func__, status); + return -EIO; +} + +static int __devinit octeon_i2c_probe(struct platform_device *pdev) +{ + int irq, result = 0; + struct octeon_i2c *i2c; + struct octeon_i2c_data *i2c_data; + struct resource *res_mem; + + /* All adaptors have an irq. */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); + if (!i2c) { + dev_err(&pdev->dev, "kzalloc failed\n"); + result = -ENOMEM; + goto out; + } + i2c->dev = &pdev->dev; + i2c_data = pdev->dev.platform_data; + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (res_mem == NULL) { + dev_err(i2c->dev, "found no memory resource\n"); + result = -ENXIO; + goto fail_region; + } + + if (i2c_data == NULL) { + dev_err(i2c->dev, "no I2C frequency data\n"); + result = -ENXIO; + goto fail_region; + } + + i2c->twsi_phys = res_mem->start; + i2c->regsize = resource_size(res_mem); + i2c->twsi_freq = i2c_data->i2c_freq; + i2c->sys_freq = i2c_data->sys_freq; + + if (!request_mem_region(i2c->twsi_phys, i2c->regsize, res_mem->name)) { + dev_err(i2c->dev, "request_mem_region failed\n"); + goto fail_region; + } + i2c->twsi_base = ioremap(i2c->twsi_phys, i2c->regsize); + + init_waitqueue_head(&i2c->queue); + + i2c->irq = irq; + + result = request_irq(i2c->irq, octeon_i2c_isr, 0, DRV_NAME, i2c); + if (result < 0) { + dev_err(i2c->dev, "failed to attach interrupt\n"); + goto fail_irq; + } + + result = octeon_i2c_initlowlevel(i2c); + if (result) { + dev_err(i2c->dev, "init low level failed\n"); + goto fail_add; + } + + result = octeon_i2c_setclock(i2c); + if (result) { + dev_err(i2c->dev, "clock init failed\n"); + goto fail_add; + } + + i2c->adap = octeon_i2c_ops; + i2c->adap.dev.parent = &pdev->dev; + i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0; + i2c_set_adapdata(&i2c->adap, i2c); + platform_set_drvdata(pdev, i2c); + + result = i2c_add_numbered_adapter(&i2c->adap); + if (result < 0) { + dev_err(i2c->dev, "failed to add adapter\n"); + goto fail_add; + } + + dev_info(i2c->dev, "version %s\n", DRV_VERSION); + + return result; + +fail_add: + platform_set_drvdata(pdev, NULL); + free_irq(i2c->irq, i2c); +fail_irq: + iounmap(i2c->twsi_base); + release_mem_region(i2c->twsi_phys, i2c->regsize); +fail_region: + kfree(i2c); +out: + return result; +}; + +static int __devexit octeon_i2c_remove(struct platform_device *pdev) +{ + struct octeon_i2c *i2c = platform_get_drvdata(pdev); + + i2c_del_adapter(&i2c->adap); + platform_set_drvdata(pdev, NULL); + free_irq(i2c->irq, i2c); + iounmap(i2c->twsi_base); + release_mem_region(i2c->twsi_phys, i2c->regsize); + kfree(i2c); + return 0; +}; + +static struct platform_driver octeon_i2c_driver = { + .probe = octeon_i2c_probe, + .remove = __devexit_p(octeon_i2c_remove), + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME, + }, +}; + +static int __init octeon_i2c_init(void) +{ + int rv; + + rv = platform_driver_register(&octeon_i2c_driver); + return rv; +} + +static void __exit octeon_i2c_exit(void) +{ + platform_driver_unregister(&octeon_i2c_driver); +} + +MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>"); +MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); +MODULE_ALIAS("platform:" DRV_NAME); + +module_init(octeon_i2c_init); +module_exit(octeon_i2c_exit); diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 5d1c2603a13..2b0bd0b042d 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -20,15 +20,15 @@ #include <linux/platform_device.h> #include <linux/i2c-pnx.h> #include <linux/io.h> +#include <linux/err.h> +#include <linux/clk.h> + #include <mach/hardware.h> #include <mach/i2c.h> -#include <asm/irq.h> -#include <asm/uaccess.h> #define I2C_PNX_TIMEOUT 10 /* msec */ #define I2C_PNX_SPEED_KHZ 100 #define I2C_PNX_REGION_SIZE 0x100 -#define PNX_DEFAULT_FREQ 13 /* MHz */ static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data) { @@ -50,22 +50,21 @@ static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data) return (timeout <= 0); } -static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap) +static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data) { - struct i2c_pnx_algo_data *data = adap->algo_data; - struct timer_list *timer = &data->mif.timer; - int expires = I2C_PNX_TIMEOUT / (1000 / HZ); + struct timer_list *timer = &alg_data->mif.timer; + unsigned long expires = msecs_to_jiffies(I2C_PNX_TIMEOUT); if (expires <= 1) expires = 2; del_timer_sync(timer); - dev_dbg(&adap->dev, "Timer armed at %lu plus %u jiffies.\n", + dev_dbg(&alg_data->adapter.dev, "Timer armed at %lu plus %lu jiffies.\n", jiffies, expires); timer->expires = jiffies + expires; - timer->data = (unsigned long)adap; + timer->data = (unsigned long)&alg_data; add_timer(timer); } @@ -77,34 +76,34 @@ static inline void i2c_pnx_arm_timer(struct i2c_adapter *adap) * * Generate a START signal in the desired mode. */ -static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap) +static int i2c_pnx_start(unsigned char slave_addr, + struct i2c_pnx_algo_data *alg_data) { - struct i2c_pnx_algo_data *alg_data = adap->algo_data; - - dev_dbg(&adap->dev, "%s(): addr 0x%x mode %d\n", __func__, + dev_dbg(&alg_data->adapter.dev, "%s(): addr 0x%x mode %d\n", __func__, slave_addr, alg_data->mif.mode); /* Check for 7 bit slave addresses only */ if (slave_addr & ~0x7f) { - dev_err(&adap->dev, "%s: Invalid slave address %x. " - "Only 7-bit addresses are supported\n", - adap->name, slave_addr); + dev_err(&alg_data->adapter.dev, + "%s: Invalid slave address %x. Only 7-bit addresses are supported\n", + alg_data->adapter.name, slave_addr); return -EINVAL; } /* First, make sure bus is idle */ if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) { /* Somebody else is monopolizing the bus */ - dev_err(&adap->dev, "%s: Bus busy. Slave addr = %02x, " - "cntrl = %x, stat = %x\n", - adap->name, slave_addr, - ioread32(I2C_REG_CTL(alg_data)), - ioread32(I2C_REG_STS(alg_data))); + dev_err(&alg_data->adapter.dev, + "%s: Bus busy. Slave addr = %02x, cntrl = %x, stat = %x\n", + alg_data->adapter.name, slave_addr, + ioread32(I2C_REG_CTL(alg_data)), + ioread32(I2C_REG_STS(alg_data))); return -EBUSY; } else if (ioread32(I2C_REG_STS(alg_data)) & mstatus_afi) { /* Sorry, we lost the bus */ - dev_err(&adap->dev, "%s: Arbitration failure. " - "Slave addr = %02x\n", adap->name, slave_addr); + dev_err(&alg_data->adapter.dev, + "%s: Arbitration failure. Slave addr = %02x\n", + alg_data->adapter.name, slave_addr); return -EIO; } @@ -115,14 +114,14 @@ static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap) iowrite32(ioread32(I2C_REG_STS(alg_data)) | mstatus_tdi | mstatus_afi, I2C_REG_STS(alg_data)); - dev_dbg(&adap->dev, "%s(): sending %#x\n", __func__, + dev_dbg(&alg_data->adapter.dev, "%s(): sending %#x\n", __func__, (slave_addr << 1) | start_bit | alg_data->mif.mode); /* Write the slave address, START bit and R/W bit */ iowrite32((slave_addr << 1) | start_bit | alg_data->mif.mode, I2C_REG_TX(alg_data)); - dev_dbg(&adap->dev, "%s(): exit\n", __func__); + dev_dbg(&alg_data->adapter.dev, "%s(): exit\n", __func__); return 0; } @@ -133,13 +132,12 @@ static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap) * * Generate a STOP signal to terminate the master transaction. */ -static void i2c_pnx_stop(struct i2c_adapter *adap) +static void i2c_pnx_stop(struct i2c_pnx_algo_data *alg_data) { - struct i2c_pnx_algo_data *alg_data = adap->algo_data; /* Only 1 msec max timeout due to interrupt context */ long timeout = 1000; - dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n", + dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n", __func__, ioread32(I2C_REG_STS(alg_data))); /* Write a STOP bit to TX FIFO */ @@ -153,7 +151,7 @@ static void i2c_pnx_stop(struct i2c_adapter *adap) timeout--; } - dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n", + dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n", __func__, ioread32(I2C_REG_STS(alg_data))); } @@ -163,12 +161,11 @@ static void i2c_pnx_stop(struct i2c_adapter *adap) * * Sends one byte of data to the slave */ -static int i2c_pnx_master_xmit(struct i2c_adapter *adap) +static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data) { - struct i2c_pnx_algo_data *alg_data = adap->algo_data; u32 val; - dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n", + dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n", __func__, ioread32(I2C_REG_STS(alg_data))); if (alg_data->mif.len > 0) { @@ -184,15 +181,15 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap) alg_data->mif.len--; iowrite32(val, I2C_REG_TX(alg_data)); - dev_dbg(&adap->dev, "%s(): xmit %#x [%d]\n", __func__, - val, alg_data->mif.len + 1); + dev_dbg(&alg_data->adapter.dev, "%s(): xmit %#x [%d]\n", + __func__, val, alg_data->mif.len + 1); if (alg_data->mif.len == 0) { if (alg_data->last) { /* Wait until the STOP is seen. */ if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) - dev_err(&adap->dev, "The bus is still " - "active after timeout\n"); + dev_err(&alg_data->adapter.dev, + "The bus is still active after timeout\n"); } /* Disable master interrupts */ iowrite32(ioread32(I2C_REG_CTL(alg_data)) & @@ -201,14 +198,15 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap) del_timer_sync(&alg_data->mif.timer); - dev_dbg(&adap->dev, "%s(): Waking up xfer routine.\n", + dev_dbg(&alg_data->adapter.dev, + "%s(): Waking up xfer routine.\n", __func__); complete(&alg_data->mif.complete); } } else if (alg_data->mif.len == 0) { /* zero-sized transfer */ - i2c_pnx_stop(adap); + i2c_pnx_stop(alg_data); /* Disable master interrupts. */ iowrite32(ioread32(I2C_REG_CTL(alg_data)) & @@ -217,13 +215,14 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap) /* Stop timer. */ del_timer_sync(&alg_data->mif.timer); - dev_dbg(&adap->dev, "%s(): Waking up xfer routine after " - "zero-xfer.\n", __func__); + dev_dbg(&alg_data->adapter.dev, + "%s(): Waking up xfer routine after zero-xfer.\n", + __func__); complete(&alg_data->mif.complete); } - dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n", + dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n", __func__, ioread32(I2C_REG_STS(alg_data))); return 0; @@ -235,21 +234,21 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap) * * Reads one byte data from the slave */ -static int i2c_pnx_master_rcv(struct i2c_adapter *adap) +static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data) { - struct i2c_pnx_algo_data *alg_data = adap->algo_data; unsigned int val = 0; u32 ctl = 0; - dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n", + dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n", __func__, ioread32(I2C_REG_STS(alg_data))); /* Check, whether there is already data, * or we didn't 'ask' for it yet. */ if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) { - dev_dbg(&adap->dev, "%s(): Write dummy data to fill " - "Rx-fifo...\n", __func__); + dev_dbg(&alg_data->adapter.dev, + "%s(): Write dummy data to fill Rx-fifo...\n", + __func__); if (alg_data->mif.len == 1) { /* Last byte, do not acknowledge next rcv. */ @@ -281,16 +280,16 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap) if (alg_data->mif.len > 0) { val = ioread32(I2C_REG_RX(alg_data)); *alg_data->mif.buf++ = (u8) (val & 0xff); - dev_dbg(&adap->dev, "%s(): rcv 0x%x [%d]\n", __func__, val, - alg_data->mif.len); + dev_dbg(&alg_data->adapter.dev, "%s(): rcv 0x%x [%d]\n", + __func__, val, alg_data->mif.len); alg_data->mif.len--; if (alg_data->mif.len == 0) { if (alg_data->last) /* Wait until the STOP is seen. */ if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) - dev_err(&adap->dev, "The bus is still " - "active after timeout\n"); + dev_err(&alg_data->adapter.dev, + "The bus is still active after timeout\n"); /* Disable master interrupts */ ctl = ioread32(I2C_REG_CTL(alg_data)); @@ -304,7 +303,7 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap) } } - dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n", + dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n", __func__, ioread32(I2C_REG_STS(alg_data))); return 0; @@ -312,11 +311,11 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap) static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) { + struct i2c_pnx_algo_data *alg_data = dev_id; u32 stat, ctl; - struct i2c_adapter *adap = dev_id; - struct i2c_pnx_algo_data *alg_data = adap->algo_data; - dev_dbg(&adap->dev, "%s(): mstat = %x mctrl = %x, mode = %d\n", + dev_dbg(&alg_data->adapter.dev, + "%s(): mstat = %x mctrl = %x, mode = %d\n", __func__, ioread32(I2C_REG_STS(alg_data)), ioread32(I2C_REG_CTL(alg_data)), @@ -339,10 +338,10 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) complete(&alg_data->mif.complete); } else if (stat & mstatus_nai) { /* Slave did not acknowledge, generate a STOP */ - dev_dbg(&adap->dev, "%s(): " - "Slave did not acknowledge, generating a STOP.\n", + dev_dbg(&alg_data->adapter.dev, + "%s(): Slave did not acknowledge, generating a STOP.\n", __func__); - i2c_pnx_stop(adap); + i2c_pnx_stop(alg_data); /* Disable master interrupts. */ ctl = ioread32(I2C_REG_CTL(alg_data)); @@ -368,9 +367,9 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) */ if ((stat & mstatus_drmi) || !(stat & mstatus_rfe)) { if (alg_data->mif.mode == I2C_SMBUS_WRITE) { - i2c_pnx_master_xmit(adap); + i2c_pnx_master_xmit(alg_data); } else if (alg_data->mif.mode == I2C_SMBUS_READ) { - i2c_pnx_master_rcv(adap); + i2c_pnx_master_rcv(alg_data); } } } @@ -379,7 +378,8 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) stat = ioread32(I2C_REG_STS(alg_data)); iowrite32(stat | mstatus_tdi | mstatus_afi, I2C_REG_STS(alg_data)); - dev_dbg(&adap->dev, "%s(): exiting, stat = %x ctrl = %x.\n", + dev_dbg(&alg_data->adapter.dev, + "%s(): exiting, stat = %x ctrl = %x.\n", __func__, ioread32(I2C_REG_STS(alg_data)), ioread32(I2C_REG_CTL(alg_data))); @@ -388,14 +388,13 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) static void i2c_pnx_timeout(unsigned long data) { - struct i2c_adapter *adap = (struct i2c_adapter *)data; - struct i2c_pnx_algo_data *alg_data = adap->algo_data; + struct i2c_pnx_algo_data *alg_data = (struct i2c_pnx_algo_data *)data; u32 ctl; - dev_err(&adap->dev, "Master timed out. stat = %04x, cntrl = %04x. " - "Resetting master...\n", - ioread32(I2C_REG_STS(alg_data)), - ioread32(I2C_REG_CTL(alg_data))); + dev_err(&alg_data->adapter.dev, + "Master timed out. stat = %04x, cntrl = %04x. Resetting master...\n", + ioread32(I2C_REG_STS(alg_data)), + ioread32(I2C_REG_CTL(alg_data))); /* Reset master and disable interrupts */ ctl = ioread32(I2C_REG_CTL(alg_data)); @@ -409,15 +408,14 @@ static void i2c_pnx_timeout(unsigned long data) complete(&alg_data->mif.complete); } -static inline void bus_reset_if_active(struct i2c_adapter *adap) +static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data) { - struct i2c_pnx_algo_data *alg_data = adap->algo_data; u32 stat; if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_active) { - dev_err(&adap->dev, + dev_err(&alg_data->adapter.dev, "%s: Bus is still active after xfer. Reset it...\n", - adap->name); + alg_data->adapter.name); iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset, I2C_REG_CTL(alg_data)); wait_reset(I2C_PNX_TIMEOUT, alg_data); @@ -451,10 +449,11 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) struct i2c_pnx_algo_data *alg_data = adap->algo_data; u32 stat = ioread32(I2C_REG_STS(alg_data)); - dev_dbg(&adap->dev, "%s(): entering: %d messages, stat = %04x.\n", + dev_dbg(&alg_data->adapter.dev, + "%s(): entering: %d messages, stat = %04x.\n", __func__, num, ioread32(I2C_REG_STS(alg_data))); - bus_reset_if_active(adap); + bus_reset_if_active(alg_data); /* Process transactions in a loop. */ for (i = 0; rc >= 0 && i < num; i++) { @@ -464,9 +463,9 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) addr = pmsg->addr; if (pmsg->flags & I2C_M_TEN) { - dev_err(&adap->dev, + dev_err(&alg_data->adapter.dev, "%s: 10 bits addr not supported!\n", - adap->name); + alg_data->adapter.name); rc = -EINVAL; break; } @@ -478,11 +477,10 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) alg_data->mif.ret = 0; alg_data->last = (i == num - 1); - dev_dbg(&adap->dev, "%s(): mode %d, %d bytes\n", __func__, - alg_data->mif.mode, - alg_data->mif.len); + dev_dbg(&alg_data->adapter.dev, "%s(): mode %d, %d bytes\n", + __func__, alg_data->mif.mode, alg_data->mif.len); - i2c_pnx_arm_timer(adap); + i2c_pnx_arm_timer(alg_data); /* initialize the completion var */ init_completion(&alg_data->mif.complete); @@ -493,7 +491,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) I2C_REG_CTL(alg_data)); /* Put start-code and slave-address on the bus. */ - rc = i2c_pnx_start(addr, adap); + rc = i2c_pnx_start(addr, alg_data); if (rc < 0) break; @@ -502,31 +500,32 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (!(rc = alg_data->mif.ret)) completed++; - dev_dbg(&adap->dev, "%s(): Complete, return code = %d.\n", + dev_dbg(&alg_data->adapter.dev, + "%s(): Complete, return code = %d.\n", __func__, rc); /* Clear TDI and AFI bits in case they are set. */ if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_tdi) { - dev_dbg(&adap->dev, + dev_dbg(&alg_data->adapter.dev, "%s: TDI still set... clearing now.\n", - adap->name); + alg_data->adapter.name); iowrite32(stat, I2C_REG_STS(alg_data)); } if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_afi) { - dev_dbg(&adap->dev, + dev_dbg(&alg_data->adapter.dev, "%s: AFI still set... clearing now.\n", - adap->name); + alg_data->adapter.name); iowrite32(stat, I2C_REG_STS(alg_data)); } } - bus_reset_if_active(adap); + bus_reset_if_active(alg_data); /* Cleanup to be sure... */ alg_data->mif.buf = NULL; alg_data->mif.len = 0; - dev_dbg(&adap->dev, "%s(): exiting, stat = %x\n", + dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x\n", __func__, ioread32(I2C_REG_STS(alg_data))); if (completed != num) @@ -545,69 +544,92 @@ static struct i2c_algorithm pnx_algorithm = { .functionality = i2c_pnx_func, }; +#ifdef CONFIG_PM static int i2c_pnx_controller_suspend(struct platform_device *pdev, pm_message_t state) { - struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); - return i2c_pnx->suspend(pdev, state); + struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev); + + /* FIXME: shouldn't this be clk_disable? */ + clk_enable(alg_data->clk); + + return 0; } static int i2c_pnx_controller_resume(struct platform_device *pdev) { - struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); - return i2c_pnx->resume(pdev); + struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev); + + return clk_enable(alg_data->clk); } +#else +#define i2c_pnx_controller_suspend NULL +#define i2c_pnx_controller_resume NULL +#endif static int __devinit i2c_pnx_probe(struct platform_device *pdev) { unsigned long tmp; int ret = 0; struct i2c_pnx_algo_data *alg_data; - int freq_mhz; + unsigned long freq; struct i2c_pnx_data *i2c_pnx = pdev->dev.platform_data; - if (!i2c_pnx || !i2c_pnx->adapter) { + if (!i2c_pnx || !i2c_pnx->name) { dev_err(&pdev->dev, "%s: no platform data supplied\n", __func__); ret = -EINVAL; goto out; } - platform_set_drvdata(pdev, i2c_pnx); - - if (i2c_pnx->calculate_input_freq) - freq_mhz = i2c_pnx->calculate_input_freq(pdev); - else { - freq_mhz = PNX_DEFAULT_FREQ; - dev_info(&pdev->dev, "Setting bus frequency to default value: " - "%d MHz\n", freq_mhz); + alg_data = kzalloc(sizeof(*alg_data), GFP_KERNEL); + if (!alg_data) { + ret = -ENOMEM; + goto err_kzalloc; } - i2c_pnx->adapter->algo = &pnx_algorithm; + platform_set_drvdata(pdev, alg_data); + + strlcpy(alg_data->adapter.name, i2c_pnx->name, + sizeof(alg_data->adapter.name)); + alg_data->adapter.dev.parent = &pdev->dev; + alg_data->adapter.algo = &pnx_algorithm; + alg_data->adapter.algo_data = alg_data; + alg_data->adapter.nr = pdev->id; + alg_data->i2c_pnx = i2c_pnx; + + alg_data->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(alg_data->clk)) { + ret = PTR_ERR(alg_data->clk); + goto out_drvdata; + } - alg_data = i2c_pnx->adapter->algo_data; init_timer(&alg_data->mif.timer); alg_data->mif.timer.function = i2c_pnx_timeout; - alg_data->mif.timer.data = (unsigned long)i2c_pnx->adapter; + alg_data->mif.timer.data = (unsigned long)alg_data; /* Register I/O resource */ - if (!request_mem_region(alg_data->base, I2C_PNX_REGION_SIZE, + if (!request_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE, pdev->name)) { dev_err(&pdev->dev, "I/O region 0x%08x for I2C already in use.\n", - alg_data->base); + i2c_pnx->base); ret = -ENODEV; - goto out_drvdata; + goto out_clkget; } - if (!(alg_data->ioaddr = - (u32)ioremap(alg_data->base, I2C_PNX_REGION_SIZE))) { + alg_data->ioaddr = ioremap(i2c_pnx->base, I2C_PNX_REGION_SIZE); + if (!alg_data->ioaddr) { dev_err(&pdev->dev, "Couldn't ioremap I2C I/O region\n"); ret = -ENOMEM; goto out_release; } - i2c_pnx->set_clock_run(pdev); + ret = clk_enable(alg_data->clk); + if (ret) + goto out_unmap; + + freq = clk_get_rate(alg_data->clk); /* * Clock Divisor High This value is the number of system clocks @@ -620,45 +642,47 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) * the deglitching filter length. */ - tmp = ((freq_mhz * 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2; + tmp = ((freq / 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2; iowrite32(tmp, I2C_REG_CKH(alg_data)); iowrite32(tmp, I2C_REG_CKL(alg_data)); iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data)); if (wait_reset(I2C_PNX_TIMEOUT, alg_data)) { ret = -ENODEV; - goto out_unmap; + goto out_clock; } init_completion(&alg_data->mif.complete); - ret = request_irq(alg_data->irq, i2c_pnx_interrupt, - 0, pdev->name, i2c_pnx->adapter); + ret = request_irq(i2c_pnx->irq, i2c_pnx_interrupt, + 0, pdev->name, alg_data); if (ret) goto out_clock; /* Register this adapter with the I2C subsystem */ - i2c_pnx->adapter->dev.parent = &pdev->dev; - i2c_pnx->adapter->nr = pdev->id; - ret = i2c_add_numbered_adapter(i2c_pnx->adapter); + ret = i2c_add_numbered_adapter(&alg_data->adapter); if (ret < 0) { dev_err(&pdev->dev, "I2C: Failed to add bus\n"); goto out_irq; } dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n", - i2c_pnx->adapter->name, alg_data->base, alg_data->irq); + alg_data->adapter.name, i2c_pnx->base, i2c_pnx->irq); return 0; out_irq: - free_irq(alg_data->irq, i2c_pnx->adapter); + free_irq(i2c_pnx->irq, alg_data); out_clock: - i2c_pnx->set_clock_stop(pdev); + clk_disable(alg_data->clk); out_unmap: - iounmap((void *)alg_data->ioaddr); + iounmap(alg_data->ioaddr); out_release: - release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE); + release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE); +out_clkget: + clk_put(alg_data->clk); out_drvdata: + kfree(alg_data); +err_kzalloc: platform_set_drvdata(pdev, NULL); out: return ret; @@ -666,15 +690,16 @@ out: static int __devexit i2c_pnx_remove(struct platform_device *pdev) { - struct i2c_pnx_data *i2c_pnx = platform_get_drvdata(pdev); - struct i2c_adapter *adap = i2c_pnx->adapter; - struct i2c_pnx_algo_data *alg_data = adap->algo_data; - - free_irq(alg_data->irq, i2c_pnx->adapter); - i2c_del_adapter(adap); - i2c_pnx->set_clock_stop(pdev); - iounmap((void *)alg_data->ioaddr); - release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE); + struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev); + struct i2c_pnx_data *i2c_pnx = alg_data->i2c_pnx; + + free_irq(i2c_pnx->irq, alg_data); + i2c_del_adapter(&alg_data->adapter); + clk_disable(alg_data->clk); + iounmap(alg_data->ioaddr); + release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE); + clk_put(alg_data->clk); + kfree(alg_data); platform_set_drvdata(pdev, NULL); return 0; diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c index b1c050ff311..e29b6d5ba8e 100644 --- a/drivers/i2c/busses/i2c-tiny-usb.c +++ b/drivers/i2c/busses/i2c-tiny-usb.c @@ -13,6 +13,7 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/module.h> +#include <linux/types.h> /* include interfaces to usb layer */ #include <linux/usb.h> @@ -31,8 +32,8 @@ #define CMD_I2C_IO_END (1<<1) /* i2c bit delay, default is 10us -> 100kHz */ -static int delay = 10; -module_param(delay, int, 0); +static unsigned short delay = 10; +module_param(delay, ushort, 0); MODULE_PARM_DESC(delay, "bit delay in microseconds, " "e.g. 10 for 100kHz (default is 100kHz)"); @@ -109,7 +110,7 @@ static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) static u32 usb_func(struct i2c_adapter *adapter) { - u32 func; + __le32 func; /* get functionality from adapter */ if (usb_read(adapter, CMD_GET_FUNC, 0, 0, &func, sizeof(func)) != @@ -118,7 +119,7 @@ static u32 usb_func(struct i2c_adapter *adapter) return 0; } - return func; + return le32_to_cpu(func); } /* This is the actual algorithm we define */ @@ -216,8 +217,7 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface, "i2c-tiny-usb at bus %03d device %03d", dev->usb_dev->bus->busnum, dev->usb_dev->devnum); - if (usb_write(&dev->adapter, CMD_SET_DELAY, - cpu_to_le16(delay), 0, NULL, 0) != 0) { + if (usb_write(&dev->adapter, CMD_SET_DELAY, delay, 0, NULL, 0) != 0) { dev_err(&dev->adapter.dev, "failure setting delay to %dus\n", delay); retval = -EIO; |