diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-nomadik.c')
| -rw-r--r-- | drivers/i2c/busses/i2c-nomadik.c | 465 |
1 files changed, 266 insertions, 199 deletions
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 5267ab93d55..0e55d85fd4e 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -14,17 +14,16 @@ */ #include <linux/init.h> #include <linux/module.h> -#include <linux/platform_device.h> +#include <linux/amba/bus.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/i2c.h> #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> -#include <linux/regulator/consumer.h> #include <linux/pm_runtime.h> - -#include <plat/i2c.h> +#include <linux/of.h> +#include <linux/pinctrl/consumer.h> #define DRIVER_NAME "nmk-i2c" @@ -104,6 +103,23 @@ /* maximum threshold value */ #define MAX_I2C_FIFO_THRESHOLD 15 +enum i2c_freq_mode { + I2C_FREQ_MODE_STANDARD, /* up to 100 Kb/s */ + I2C_FREQ_MODE_FAST, /* up to 400 Kb/s */ + I2C_FREQ_MODE_HIGH_SPEED, /* up to 3.4 Mb/s */ + I2C_FREQ_MODE_FAST_PLUS, /* up to 1 Mb/s */ +}; + +/** + * struct i2c_vendor_data - per-vendor variations + * @has_mtdws: variant has the MTDWS bit + * @fifodepth: variant FIFO depth + */ +struct i2c_vendor_data { + bool has_mtdws; + u32 fifodepth; +}; + enum i2c_status { I2C_NOP, I2C_ON_GOING, @@ -136,32 +152,38 @@ struct i2c_nmk_client { /** * struct nmk_i2c_dev - private data structure of the controller. - * @pdev: parent platform device. + * @vendor: vendor data for this variant. + * @adev: parent amba device. * @adap: corresponding I2C adapter. * @irq: interrupt line for the controller. * @virtbase: virtual io memory area. * @clk: hardware i2c block clock. - * @cfg: machine provided controller configuration. * @cli: holder of client specific data. + * @clk_freq: clock frequency for the operation mode + * @tft: Tx FIFO Threshold in bytes + * @rft: Rx FIFO Threshold in bytes + * @timeout Slave response timeout (ms) + * @sm: speed mode * @stop: stop condition. * @xfer_complete: acknowledge completion for a I2C message. * @result: controller propogated result. - * @regulator: pointer to i2c regulator. - * @busy: Busy doing transfer. */ struct nmk_i2c_dev { - struct platform_device *pdev; + struct i2c_vendor_data *vendor; + struct amba_device *adev; struct i2c_adapter adap; int irq; void __iomem *virtbase; struct clk *clk; - struct nmk_i2c_controller cfg; struct i2c_nmk_client cli; + u32 clk_freq; + unsigned char tft; + unsigned char rft; + int timeout; + enum i2c_freq_mode sm; int stop; struct completion xfer_complete; int result; - struct regulator *regulator; - bool busy; }; /* controller's abort causes */ @@ -217,7 +239,7 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev) } } - dev_err(&dev->pdev->dev, + dev_err(&dev->adev->dev, "flushing operation timed out giving up after %d attempts", LOOP_ATTEMPTS); @@ -276,15 +298,32 @@ exit: /** * load_i2c_mcr_reg() - load the MCR register * @dev: private data of controller + * @flags: message flags */ -static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *dev) +static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *dev, u16 flags) { u32 mcr = 0; + unsigned short slave_adr_3msb_bits; - /* 7-bit address transaction */ - mcr |= GEN_MASK(1, I2C_MCR_AM, 12); mcr |= GEN_MASK(dev->cli.slave_adr, I2C_MCR_A7, 1); + if (unlikely(flags & I2C_M_TEN)) { + /* 10-bit address transaction */ + mcr |= GEN_MASK(2, I2C_MCR_AM, 12); + /* + * Get the top 3 bits. + * EA10 represents extended address in MCR. This includes + * the extension (MSB bits) of the 7 bit address loaded + * in A7 + */ + slave_adr_3msb_bits = (dev->cli.slave_adr >> 7) & 0x7; + + mcr |= GEN_MASK(slave_adr_3msb_bits, I2C_MCR_EA10, 8); + } else { + /* 7-bit address transaction */ + mcr |= GEN_MASK(1, I2C_MCR_AM, 12); + } + /* start byte procedure not applied */ mcr |= GEN_MASK(0, I2C_MCR_SB, 11); @@ -313,6 +352,8 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) { u32 brcr1, brcr2; u32 i2c_clk, div; + u32 ns; + u16 slsu; writel(0x0, dev->virtbase + I2C_CR); writel(0x0, dev->virtbase + I2C_HSMCR); @@ -320,29 +361,45 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) writel(0x0, dev->virtbase + I2C_RFTR); writel(0x0, dev->virtbase + I2C_DMAR); + i2c_clk = clk_get_rate(dev->clk); + /* * set the slsu: * * slsu defines the data setup time after SCL clock - * stretching in terms of i2c clk cycles. The - * needed setup time for the three modes are 250ns, - * 100ns, 10ns respectively thus leading to the values - * of 14, 6, 2 for a 48 MHz i2c clk. + * stretching in terms of i2c clk cycles + 1 (zero means + * "wait one cycle"), the needed setup time for the three + * modes are 250ns, 100ns, 10ns respectively. + * + * As the time for one cycle T in nanoseconds is + * T = (1/f) * 1000000000 => + * slsu = cycles / (1000000000 / f) + 1 */ - writel(dev->cfg.slsu << 16, dev->virtbase + I2C_SCR); - - i2c_clk = clk_get_rate(dev->clk); + ns = DIV_ROUND_UP_ULL(1000000000ULL, i2c_clk); + switch (dev->sm) { + case I2C_FREQ_MODE_FAST: + case I2C_FREQ_MODE_FAST_PLUS: + slsu = DIV_ROUND_UP(100, ns); /* Fast */ + break; + case I2C_FREQ_MODE_HIGH_SPEED: + slsu = DIV_ROUND_UP(10, ns); /* High */ + break; + case I2C_FREQ_MODE_STANDARD: + default: + slsu = DIV_ROUND_UP(250, ns); /* Standard */ + break; + } + slsu += 1; - /* fallback to std. mode if machine has not provided it */ - if (dev->cfg.clk_freq == 0) - dev->cfg.clk_freq = 100000; + dev_dbg(&dev->adev->dev, "calculated SLSU = %04x\n", slsu); + writel(slsu << 16, dev->virtbase + I2C_SCR); /* * The spec says, in case of std. mode the divider is * 2 whereas it is 3 for fast and fastplus mode of * operation. TODO - high speed support. */ - div = (dev->cfg.clk_freq > 100000) ? 3 : 2; + div = (dev->clk_freq > 100000) ? 3 : 2; /* * generate the mask for baud rate counters. The controller @@ -352,7 +409,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) * so set brcr1 to 0. */ brcr1 = 0 << 16; - brcr2 = (i2c_clk/(dev->cfg.clk_freq * div)) & 0xffff; + brcr2 = (i2c_clk/(dev->clk_freq * div)) & 0xffff; /* set the baud rate counter register */ writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR); @@ -363,37 +420,37 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) * TODO - support for fast mode plus (up to 1Mb/s) * and high speed (up to 3.4 Mb/s) */ - if (dev->cfg.sm > I2C_FREQ_MODE_FAST) { - dev_err(&dev->pdev->dev, + if (dev->sm > I2C_FREQ_MODE_FAST) { + dev_err(&dev->adev->dev, "do not support this mode defaulting to std. mode\n"); brcr2 = i2c_clk/(100000 * 2) & 0xffff; writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR); writel(I2C_FREQ_MODE_STANDARD << 4, dev->virtbase + I2C_CR); } - writel(dev->cfg.sm << 4, dev->virtbase + I2C_CR); + writel(dev->sm << 4, dev->virtbase + I2C_CR); /* set the Tx and Rx FIFO threshold */ - writel(dev->cfg.tft, dev->virtbase + I2C_TFTR); - writel(dev->cfg.rft, dev->virtbase + I2C_RFTR); + writel(dev->tft, dev->virtbase + I2C_TFTR); + writel(dev->rft, dev->virtbase + I2C_RFTR); } /** * read_i2c() - Read from I2C client device * @dev: private data of I2C Driver + * @flags: message flags * * This function reads from i2c client device when controller is in * master mode. There is a completion timeout. If there is no transfer * before timeout error is returned. */ -static int read_i2c(struct nmk_i2c_dev *dev) +static int read_i2c(struct nmk_i2c_dev *dev, u16 flags) { u32 status = 0; - u32 mcr; - u32 irq_mask = 0; + u32 mcr, irq_mask; int timeout; - mcr = load_i2c_mcr_reg(dev); + mcr = load_i2c_mcr_reg(dev, flags); writel(mcr, dev->virtbase + I2C_MCR); /* load the current CR value */ @@ -409,7 +466,7 @@ static int read_i2c(struct nmk_i2c_dev *dev) irq_mask = (I2C_IT_RXFNF | I2C_IT_RXFF | I2C_IT_MAL | I2C_IT_BERR); - if (dev->stop) + if (dev->stop || !dev->vendor->has_mtdws) irq_mask |= I2C_IT_MTD; else irq_mask |= I2C_IT_MTDWS; @@ -422,16 +479,9 @@ static int read_i2c(struct nmk_i2c_dev *dev) timeout = wait_for_completion_timeout( &dev->xfer_complete, dev->adap.timeout); - if (timeout < 0) { - dev_err(&dev->pdev->dev, - "wait_for_completion_timeout " - "returned %d waiting for event\n", timeout); - status = timeout; - } - if (timeout == 0) { /* Controller timed out */ - dev_err(&dev->pdev->dev, "read from slave 0x%x timed out\n", + dev_err(&dev->adev->dev, "read from slave 0x%x timed out\n", dev->cli.slave_adr); status = -ETIMEDOUT; } @@ -459,17 +509,17 @@ static void fill_tx_fifo(struct nmk_i2c_dev *dev, int no_bytes) /** * write_i2c() - Write data to I2C client. * @dev: private data of I2C Driver + * @flags: message flags * * This function writes data to I2C client */ -static int write_i2c(struct nmk_i2c_dev *dev) +static int write_i2c(struct nmk_i2c_dev *dev, u16 flags) { u32 status = 0; - u32 mcr; - u32 irq_mask = 0; + u32 mcr, irq_mask; int timeout; - mcr = load_i2c_mcr_reg(dev); + mcr = load_i2c_mcr_reg(dev, flags); writel(mcr, dev->virtbase + I2C_MCR); @@ -496,7 +546,7 @@ static int write_i2c(struct nmk_i2c_dev *dev) * set the MTDWS bit (Master Transaction Done Without Stop) * to start repeated start operation */ - if (dev->stop) + if (dev->stop || !dev->vendor->has_mtdws) irq_mask |= I2C_IT_MTD; else irq_mask |= I2C_IT_MTDWS; @@ -509,16 +559,9 @@ static int write_i2c(struct nmk_i2c_dev *dev) timeout = wait_for_completion_timeout( &dev->xfer_complete, dev->adap.timeout); - if (timeout < 0) { - dev_err(&dev->pdev->dev, - "wait_for_completion_timeout " - "returned %d waiting for event\n", timeout); - status = timeout; - } - if (timeout == 0) { /* Controller timed out */ - dev_err(&dev->pdev->dev, "write to slave 0x%x timed out\n", + dev_err(&dev->adev->dev, "write to slave 0x%x timed out\n", dev->cli.slave_adr); status = -ETIMEDOUT; } @@ -538,11 +581,11 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags) if (flags & I2C_M_RD) { /* read operation */ dev->cli.operation = I2C_READ; - status = read_i2c(dev); + status = read_i2c(dev, flags); } else { /* write operation */ dev->cli.operation = I2C_WRITE; - status = write_i2c(dev); + status = write_i2c(dev, flags); } if (status || (dev->result)) { @@ -557,7 +600,7 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags) if (((i2c_sr >> 2) & 0x3) == 0x3) { /* get the abort cause */ cause = (i2c_sr >> 4) & 0x7; - dev_err(&dev->pdev->dev, "%s\n", + dev_err(&dev->adev->dev, "%s\n", cause >= ARRAY_SIZE(abort_causes) ? "unknown reason" : abort_causes[cause]); @@ -621,22 +664,12 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags) static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num_msgs) { - int status; + int status = 0; int i; struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap); int j; - dev->busy = true; - - if (dev->regulator) - regulator_enable(dev->regulator); - pm_runtime_get_sync(&dev->pdev->dev); - - clk_enable(dev->clk); - - status = init_hw(dev); - if (status) - goto out; + pm_runtime_get_sync(&dev->adev->dev); /* Attempt three times to send the message queue */ for (j = 0; j < 3; j++) { @@ -644,13 +677,6 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, setup_i2c_controller(dev); for (i = 0; i < num_msgs; i++) { - if (unlikely(msgs[i].flags & I2C_M_TEN)) { - dev_err(&dev->pdev->dev, - "10 bit addressing not supported\n"); - - status = -EINVAL; - goto out; - } dev->cli.slave_adr = msgs[i].addr; dev->cli.buffer = msgs[i].buf; dev->cli.count = msgs[i].len; @@ -665,13 +691,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, break; } -out: - clk_disable(dev->clk); - pm_runtime_put_sync(&dev->pdev->dev); - if (dev->regulator) - regulator_disable(dev->regulator); - - dev->busy = false; + pm_runtime_put_sync(&dev->adev->dev); /* return the no. messages processed */ if (status) @@ -709,8 +729,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) struct nmk_i2c_dev *dev = arg; u32 tft, rft; u32 count; - u32 misr; - u32 src = 0; + u32 misr, src; /* load Tx FIFO and Rx FIFO threshold values */ tft = readl(dev->virtbase + I2C_TFTR); @@ -790,7 +809,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) if (dev->cli.count) { dev->result = -EIO; - dev_err(&dev->pdev->dev, + dev_err(&dev->adev->dev, "%lu bytes still remain to be xfered\n", dev->cli.count); (void) init_hw(dev); @@ -834,7 +853,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) dev->result = -EIO; (void) init_hw(dev); - dev_err(&dev->pdev->dev, "Tx Fifo Over run\n"); + dev_err(&dev->adev->dev, "Tx Fifo Over run\n"); complete(&dev->xfer_complete); break; @@ -847,51 +866,80 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) case I2C_IT_RFSE: case I2C_IT_WTSR: case I2C_IT_STD: - dev_err(&dev->pdev->dev, "unhandled Interrupt\n"); + dev_err(&dev->adev->dev, "unhandled Interrupt\n"); break; default: - dev_err(&dev->pdev->dev, "spurious Interrupt..\n"); + dev_err(&dev->adev->dev, "spurious Interrupt..\n"); break; } return IRQ_HANDLED; } - -#ifdef CONFIG_PM -static int nmk_i2c_suspend(struct device *dev) +#ifdef CONFIG_PM_SLEEP +static int nmk_i2c_suspend_late(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct nmk_i2c_dev *nmk_i2c = platform_get_drvdata(pdev); + int ret; - if (nmk_i2c->busy) - return -EBUSY; + ret = pm_runtime_force_suspend(dev); + if (ret) + return ret; + pinctrl_pm_select_sleep_state(dev); return 0; } -static int nmk_i2c_resume(struct device *dev) +static int nmk_i2c_resume_early(struct device *dev) +{ + return pm_runtime_force_resume(dev); +} +#endif + +#ifdef CONFIG_PM +static int nmk_i2c_runtime_suspend(struct device *dev) { + struct amba_device *adev = to_amba_device(dev); + struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev); + + clk_disable_unprepare(nmk_i2c->clk); + pinctrl_pm_select_idle_state(dev); return 0; } -#else -#define nmk_i2c_suspend NULL -#define nmk_i2c_resume NULL + +static int nmk_i2c_runtime_resume(struct device *dev) +{ + struct amba_device *adev = to_amba_device(dev); + struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev); + int ret; + + ret = clk_prepare_enable(nmk_i2c->clk); + if (ret) { + dev_err(dev, "can't prepare_enable clock\n"); + return ret; + } + + pinctrl_pm_select_default_state(dev); + + ret = init_hw(nmk_i2c); + if (ret) { + clk_disable_unprepare(nmk_i2c->clk); + pinctrl_pm_select_idle_state(dev); + } + + return ret; +} #endif -/* - * We use noirq so that we suspend late and resume before the wakeup interrupt - * to ensure that we do the !pm_runtime_suspended() check in resume before - * there has been a regular pm runtime resume (via pm_runtime_get_sync()). - */ static const struct dev_pm_ops nmk_i2c_pm = { - .suspend_noirq = nmk_i2c_suspend, - .resume_noirq = nmk_i2c_resume, + SET_LATE_SYSTEM_SLEEP_PM_OPS(nmk_i2c_suspend_late, nmk_i2c_resume_early) + SET_PM_RUNTIME_PM_OPS(nmk_i2c_runtime_suspend, + nmk_i2c_runtime_resume, + NULL) }; static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; } static const struct i2c_algorithm nmk_i2c_algo = { @@ -899,125 +947,125 @@ static const struct i2c_algorithm nmk_i2c_algo = { .functionality = nmk_i2c_functionality }; -static int __devinit nmk_i2c_probe(struct platform_device *pdev) +static void nmk_i2c_of_probe(struct device_node *np, + struct nmk_i2c_dev *nmk) +{ + /* Default to 100 kHz if no frequency is given in the node */ + if (of_property_read_u32(np, "clock-frequency", &nmk->clk_freq)) + nmk->clk_freq = 100000; + + /* This driver only supports 'standard' and 'fast' modes of operation. */ + if (nmk->clk_freq <= 100000) + nmk->sm = I2C_FREQ_MODE_STANDARD; + else + nmk->sm = I2C_FREQ_MODE_FAST; + nmk->tft = 1; /* Tx FIFO threshold */ + nmk->rft = 8; /* Rx FIFO threshold */ + nmk->timeout = 200; /* Slave response timeout(ms) */ +} + +static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) { int ret = 0; - struct resource *res; - struct nmk_i2c_controller *pdata = - pdev->dev.platform_data; + struct device_node *np = adev->dev.of_node; struct nmk_i2c_dev *dev; struct i2c_adapter *adap; + struct i2c_vendor_data *vendor = id->data; + u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1; - dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL); + dev = devm_kzalloc(&adev->dev, sizeof(struct nmk_i2c_dev), GFP_KERNEL); if (!dev) { - dev_err(&pdev->dev, "cannot allocate memory\n"); + dev_err(&adev->dev, "cannot allocate memory\n"); ret = -ENOMEM; goto err_no_mem; } - dev->busy = false; - dev->pdev = pdev; - platform_set_drvdata(pdev, dev); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENOENT; - goto err_no_resource; + dev->vendor = vendor; + dev->adev = adev; + nmk_i2c_of_probe(np, dev); + + if (dev->tft > max_fifo_threshold) { + dev_warn(&adev->dev, "requested TX FIFO threshold %u, adjusted down to %u\n", + dev->tft, max_fifo_threshold); + dev->tft = max_fifo_threshold; } - if (request_mem_region(res->start, resource_size(res), - DRIVER_NAME "I/O region") == NULL) { - ret = -EBUSY; - goto err_no_region; + if (dev->rft > max_fifo_threshold) { + dev_warn(&adev->dev, "requested RX FIFO threshold %u, adjusted down to %u\n", + dev->rft, max_fifo_threshold); + dev->rft = max_fifo_threshold; } - dev->virtbase = ioremap(res->start, resource_size(res)); + amba_set_drvdata(adev, dev); + + dev->virtbase = devm_ioremap(&adev->dev, adev->res.start, + resource_size(&adev->res)); if (!dev->virtbase) { ret = -ENOMEM; - goto err_no_ioremap; + goto err_no_mem; } - dev->irq = platform_get_irq(pdev, 0); - ret = request_irq(dev->irq, i2c_irq_handler, 0, + dev->irq = adev->irq[0]; + ret = devm_request_irq(&adev->dev, dev->irq, i2c_irq_handler, 0, DRIVER_NAME, dev); if (ret) { - dev_err(&pdev->dev, "cannot claim the irq %d\n", dev->irq); - goto err_irq; - } - - dev->regulator = regulator_get(&pdev->dev, "v-i2c"); - if (IS_ERR(dev->regulator)) { - dev_warn(&pdev->dev, "could not get i2c regulator\n"); - dev->regulator = NULL; + dev_err(&adev->dev, "cannot claim the irq %d\n", dev->irq); + goto err_no_mem; } - pm_suspend_ignore_children(&pdev->dev, true); - pm_runtime_enable(&pdev->dev); + pm_suspend_ignore_children(&adev->dev, true); - dev->clk = clk_get(&pdev->dev, NULL); + dev->clk = devm_clk_get(&adev->dev, NULL); if (IS_ERR(dev->clk)) { - dev_err(&pdev->dev, "could not get i2c clock\n"); + dev_err(&adev->dev, "could not get i2c clock\n"); ret = PTR_ERR(dev->clk); - goto err_no_clk; + goto err_no_mem; + } + + ret = clk_prepare_enable(dev->clk); + if (ret) { + dev_err(&adev->dev, "can't prepare_enable clock\n"); + goto err_no_mem; } + init_hw(dev); + adap = &dev->adap; - adap->dev.parent = &pdev->dev; + adap->dev.of_node = np; + adap->dev.parent = &adev->dev; adap->owner = THIS_MODULE; - adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED; adap->algo = &nmk_i2c_algo; - adap->timeout = pdata->timeout ? msecs_to_jiffies(pdata->timeout) : - msecs_to_jiffies(20000); + adap->timeout = msecs_to_jiffies(dev->timeout); snprintf(adap->name, sizeof(adap->name), - "Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start); - - /* fetch the controller id */ - adap->nr = pdev->id; - - /* fetch the controller configuration from machine */ - dev->cfg.clk_freq = pdata->clk_freq; - dev->cfg.slsu = pdata->slsu; - dev->cfg.tft = pdata->tft; - dev->cfg.rft = pdata->rft; - dev->cfg.sm = pdata->sm; + "Nomadik I2C at %pR", &adev->res); i2c_set_adapdata(adap, dev); - dev_info(&pdev->dev, + dev_info(&adev->dev, "initialize %s on virtual base %p\n", adap->name, dev->virtbase); - ret = i2c_add_numbered_adapter(adap); + ret = i2c_add_adapter(adap); if (ret) { - dev_err(&pdev->dev, "failed to add adapter\n"); - goto err_add_adap; + dev_err(&adev->dev, "failed to add adapter\n"); + goto err_no_adap; } + pm_runtime_put(&adev->dev); + return 0; - err_add_adap: - clk_put(dev->clk); - err_no_clk: - if (dev->regulator) - regulator_put(dev->regulator); - pm_runtime_disable(&pdev->dev); - free_irq(dev->irq, dev); - err_irq: - iounmap(dev->virtbase); - err_no_ioremap: - release_mem_region(res->start, resource_size(res)); - err_no_region: - platform_set_drvdata(pdev, NULL); - err_no_resource: - kfree(dev); + err_no_adap: + clk_disable_unprepare(dev->clk); err_no_mem: return ret; } -static int __devexit nmk_i2c_remove(struct platform_device *pdev) +static int nmk_i2c_remove(struct amba_device *adev) { - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct nmk_i2c_dev *dev = platform_get_drvdata(pdev); + struct resource *res = &adev->res; + struct nmk_i2c_dev *dev = amba_get_drvdata(adev); i2c_del_adapter(&dev->adap); flush_i2c_fifo(dev); @@ -1025,38 +1073,58 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev) clear_all_interrupts(dev); /* disable the controller */ i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE); - free_irq(dev->irq, dev); - iounmap(dev->virtbase); + clk_disable_unprepare(dev->clk); if (res) release_mem_region(res->start, resource_size(res)); - clk_put(dev->clk); - if (dev->regulator) - regulator_put(dev->regulator); - pm_runtime_disable(&pdev->dev); - platform_set_drvdata(pdev, NULL); - kfree(dev); return 0; } -static struct platform_driver nmk_i2c_driver = { - .driver = { +static struct i2c_vendor_data vendor_stn8815 = { + .has_mtdws = false, + .fifodepth = 16, /* Guessed from TFTR/RFTR = 7 */ +}; + +static struct i2c_vendor_data vendor_db8500 = { + .has_mtdws = true, + .fifodepth = 32, /* Guessed from TFTR/RFTR = 15 */ +}; + +static struct amba_id nmk_i2c_ids[] = { + { + .id = 0x00180024, + .mask = 0x00ffffff, + .data = &vendor_stn8815, + }, + { + .id = 0x00380024, + .mask = 0x00ffffff, + .data = &vendor_db8500, + }, + {}, +}; + +MODULE_DEVICE_TABLE(amba, nmk_i2c_ids); + +static struct amba_driver nmk_i2c_driver = { + .drv = { .owner = THIS_MODULE, .name = DRIVER_NAME, .pm = &nmk_i2c_pm, }, + .id_table = nmk_i2c_ids, .probe = nmk_i2c_probe, - .remove = __devexit_p(nmk_i2c_remove), + .remove = nmk_i2c_remove, }; static int __init nmk_i2c_init(void) { - return platform_driver_register(&nmk_i2c_driver); + return amba_driver_register(&nmk_i2c_driver); } static void __exit nmk_i2c_exit(void) { - platform_driver_unregister(&nmk_i2c_driver); + amba_driver_unregister(&nmk_i2c_driver); } subsys_initcall(nmk_i2c_init); @@ -1065,4 +1133,3 @@ module_exit(nmk_i2c_exit); MODULE_AUTHOR("Sachin Verma, Srinidhi KASAGAR"); MODULE_DESCRIPTION("Nomadik/Ux500 I2C driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRIVER_NAME); |
