diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-21 09:39:37 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-21 09:39:37 -0800 |
commit | 02d0a752460ea5dab34ce36c9ddc9c682e846a0d (patch) | |
tree | 094908b333a993b2160ee220f794a908a5e355b6 /drivers | |
parent | fb2e2c85375a0380d6818f153ffa2ae9ebbd055f (diff) | |
parent | 5f1b11555ef21fb3a8a9d21a2e5914e2bc1b9d9b (diff) |
Merge branch 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang:
"For 3.14, the I2C subsystem has the following to offer:
- new drivers for Renesas RIIC and RobotFuzz OSIF
- driver cleanups & improvements & bugfixes
Pretty standard stuff this time, I'd say. There is more complex stuff
coming up, but I didn't have the bandwidth between the years to pull
it in for this release. Sadly"
* 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (26 commits)
i2c: s3c2410: fix quirk usage for 64-bit
i2c: pnx: Use devm_*() functions
i2c: at91: add a new compatibility string for the at91sam9261
i2c-ismt: support I2C_SMBUS_I2C_BLOCK_DATA transaction type
i2c: Add bus driver for for OSIF USB i2c device.
i2c: i2c-tiny-usb: Remove RobotFuzz USB vendor:product ID
i2c: designware: remove HAVE_CLK build dependecy
Documentation: i2c: Remove obsolete example
i2c: nomadik: remove platform data header
i2c: nomadik: auto-calculate slave setup time
i2c: viperboard: remove superfluous assignment
i2c: xilinx: Use devm_* functions
i2c: xilinx: Do not enable irq before irq handler
i2c: xilinx: Fix i2c checkpatch warnings
i2c: at91: document clock properties
i2c: isch: Use devm_request_region()
i2c: viperboard: Use devm_kzalloc() functions
i2c: imx: propagate irq error code in probe
i2c: s3c2410: dont need CPU_FREQ transitions for exynos series
i2c: s3c2410: Add polling mode support
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/i2c/busses/Kconfig | 25 | ||||
-rw-r--r-- | drivers/i2c/busses/Makefile | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-at91.c | 3 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-designware-core.c | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-imx.c | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-isch.c | 7 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-ismt.c | 37 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-nomadik.c | 64 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pnx.c | 64 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-riic.c | 427 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-robotfuzz-osif.c | 202 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-s3c2410.c | 76 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-tiny-usb.c | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-viperboard.c | 16 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-xiic.c | 89 | ||||
-rw-r--r-- | drivers/i2c/muxes/i2c-mux-pca954x.c | 44 |
16 files changed, 881 insertions, 179 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 3b26129f605..6bcdea5856a 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -412,7 +412,6 @@ config I2C_DESIGNWARE_CORE config I2C_DESIGNWARE_PLATFORM tristate "Synopsys DesignWare Platform" - depends on HAVE_CLK select I2C_DESIGNWARE_CORE help If you say yes to this option, support will be included for the @@ -648,6 +647,16 @@ config I2C_PXA_SLAVE is necessary for systems where the PXA may be a target on the I2C bus. +config I2C_RIIC + tristate "Renesas RIIC adapter" + depends on ARCH_SHMOBILE || COMPILE_TEST + help + If you say yes to this option, support will be included for the + Renesas RIIC I2C interface. + + This driver can also be built as a module. If so, the module + will be called i2c-riic. + config HAVE_S3C2410_I2C bool help @@ -683,7 +692,7 @@ config I2C_SH7760 config I2C_SH_MOBILE tristate "SuperH Mobile I2C Controller" - depends on SUPERH || ARM || COMPILE_TEST + depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST help If you say yes to this option, support will be included for the built-in I2C interface on the Renesas SH-Mobile processor. @@ -796,7 +805,7 @@ config I2C_XLR config I2C_RCAR tristate "Renesas R-Car I2C Controller" - depends on ARM || COMPILE_TEST + depends on ARCH_SHMOBILE || COMPILE_TEST help If you say yes to this option, support will be included for the R-Car I2C controller. @@ -865,6 +874,16 @@ config I2C_PARPORT_LIGHT This support is also available as a module. If so, the module will be called i2c-parport-light. +config I2C_ROBOTFUZZ_OSIF + tristate "RobotFuzz Open Source InterFace USB adapter" + depends on USB + help + If you say yes to this option, support will be included for the + RobotFuzz Open Source InterFace USB to I2C interface. + + This driver can also be built as a module. If so, the module + will be called i2c-osif. + config I2C_TAOS_EVM tristate "TAOS evaluation module" depends on TTY diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index c73eb0ea788..a08931fe73e 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_I2C_PNX) += i2c-pnx.o obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o +obj-$(CONFIG_I2C_RIIC) += i2c-riic.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_S6000) += i2c-s6000.o obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o @@ -83,6 +84,7 @@ obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o +obj-$(CONFIG_I2C_ROBOTFUZZ_OSIF) += i2c-robotfuzz-osif.o obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o obj-$(CONFIG_I2C_VIPERBOARD) += i2c-viperboard.o diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 8edba9de76d..843d01268ae 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -589,6 +589,9 @@ static const struct of_device_id atmel_twi_dt_ids[] = { .compatible = "atmel,at91sam9260-i2c", .data = &at91sam9260_config, } , { + .compatible = "atmel,at91sam9261-i2c", + .data = &at91sam9261_config, + } , { .compatible = "atmel,at91sam9g20-i2c", .data = &at91sam9g20_config, } , { diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index e89e3e2145e..14c4b30d4cc 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -26,7 +26,6 @@ * */ #include <linux/export.h> -#include <linux/clk.h> #include <linux/errno.h> #include <linux/err.h> #include <linux/i2c.h> diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index d0cfbb4cb96..db895fb22e6 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -607,7 +607,7 @@ static int i2c_imx_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "can't get irq number\n"); - return -ENOENT; + return irq; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c index 8c38aaa7417..af213045ab7 100644 --- a/drivers/i2c/busses/i2c-isch.c +++ b/drivers/i2c/busses/i2c-isch.c @@ -275,7 +275,8 @@ static int smbus_sch_probe(struct platform_device *dev) if (!res) return -EBUSY; - if (!request_region(res->start, resource_size(res), dev->name)) { + if (!devm_request_region(&dev->dev, res->start, resource_size(res), + dev->name)) { dev_err(&dev->dev, "SMBus region 0x%x already in use!\n", sch_smba); return -EBUSY; @@ -294,7 +295,6 @@ static int smbus_sch_probe(struct platform_device *dev) retval = i2c_add_adapter(&sch_adapter); if (retval) { dev_err(&dev->dev, "Couldn't register adapter!\n"); - release_region(res->start, resource_size(res)); sch_smba = 0; } @@ -303,11 +303,8 @@ static int smbus_sch_probe(struct platform_device *dev) static int smbus_sch_remove(struct platform_device *pdev) { - struct resource *res; if (sch_smba) { i2c_del_adapter(&sch_adapter); - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - release_region(res->start, resource_size(res)); sch_smba = 0; } diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index 0043ede234c..bb132ea7d2b 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -344,6 +344,7 @@ static int ismt_process_desc(const struct ismt_desc *desc, data->word = dma_buffer[0] | (dma_buffer[1] << 8); break; case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_I2C_BLOCK_DATA: memcpy(&data->block[1], dma_buffer, desc->rxbytes); data->block[0] = desc->rxbytes; break; @@ -509,6 +510,41 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, } break; + case I2C_SMBUS_I2C_BLOCK_DATA: + /* Make sure the length is valid */ + if (data->block[0] < 1) + data->block[0] = 1; + + if (data->block[0] > I2C_SMBUS_BLOCK_MAX) + data->block[0] = I2C_SMBUS_BLOCK_MAX; + + if (read_write == I2C_SMBUS_WRITE) { + /* i2c Block Write */ + dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: WRITE\n"); + dma_size = data->block[0] + 1; + dma_direction = DMA_TO_DEVICE; + desc->wr_len_cmd = dma_size; + desc->control |= ISMT_DESC_I2C; + priv->dma_buffer[0] = command; + memcpy(&priv->dma_buffer[1], &data->block[1], dma_size); + } else { + /* i2c Block Read */ + dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: READ\n"); + dma_size = data->block[0]; + dma_direction = DMA_FROM_DEVICE; + desc->rd_len = dma_size; + desc->wr_len_cmd = command; + desc->control |= (ISMT_DESC_I2C | ISMT_DESC_CWRL); + /* + * Per the "Table 15-15. I2C Commands", + * in the External Design Specification (EDS), + * (Document Number: 508084, Revision: 2.0), + * the _rw bit must be 0 + */ + desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, 0); + } + break; + default: dev_err(dev, "Unsupported transaction %d\n", size); @@ -582,6 +618,7 @@ static u32 ismt_func(struct i2c_adapter *adap) I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_PEC; } diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 8bf9ac01301..4443613514e 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -22,7 +22,6 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/pm_runtime.h> -#include <linux/platform_data/i2c-nomadik.h> #include <linux/of.h> #include <linux/pinctrl/consumer.h> @@ -104,6 +103,29 @@ /* 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 nmk_i2c_controller - client specific controller configuration + * @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 + */ +struct nmk_i2c_controller { + u32 clk_freq; + unsigned char tft; + unsigned char rft; + int timeout; + enum i2c_freq_mode sm; +}; + /** * struct i2c_vendor_data - per-vendor variations * @has_mtdws: variant has the MTDWS bit @@ -340,6 +362,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); @@ -347,18 +371,38 @@ 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); + ns = DIV_ROUND_UP_ULL(1000000000ULL, i2c_clk); + switch (dev->cfg.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; - i2c_clk = clk_get_rate(dev->clk); + 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 @@ -915,11 +959,6 @@ static const struct i2c_algorithm nmk_i2c_algo = { }; static struct nmk_i2c_controller u8500_i2c = { - /* - * Slave data setup time; 250ns, 100ns, and 10ns, which - * is 14, 6 and 2 respectively for a 48Mhz i2c clock. - */ - .slsu = 0xe, .tft = 1, /* Tx FIFO threshold */ .rft = 8, /* Rx FIFO threshold */ .clk_freq = 400000, /* fast mode operation */ @@ -1027,7 +1066,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *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; diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index c9a352f0a9a..dc7ff829ad7 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -628,11 +628,9 @@ static int i2c_pnx_probe(struct platform_device *pdev) struct resource *res; u32 speed = I2C_PNX_SPEED_KHZ_DEFAULT * 1000; - alg_data = kzalloc(sizeof(*alg_data), GFP_KERNEL); - if (!alg_data) { - ret = -ENOMEM; - goto err_kzalloc; - } + alg_data = devm_kzalloc(&pdev->dev, sizeof(*alg_data), GFP_KERNEL); + if (!alg_data) + return -ENOMEM; platform_set_drvdata(pdev, alg_data); @@ -657,11 +655,9 @@ static int i2c_pnx_probe(struct platform_device *pdev) */ } #endif - 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->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(alg_data->clk)) + return PTR_ERR(alg_data->clk); init_timer(&alg_data->mif.timer); alg_data->mif.timer.function = i2c_pnx_timeout; @@ -672,31 +668,13 @@ static int i2c_pnx_probe(struct platform_device *pdev) /* Register I/O resource */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Unable to get mem resource.\n"); - ret = -EBUSY; - goto out_clkget; - } - if (!request_mem_region(res->start, I2C_PNX_REGION_SIZE, - pdev->name)) { - dev_err(&pdev->dev, - "I/O region 0x%08x for I2C already in use.\n", - res->start); - ret = -ENOMEM; - goto out_clkget; - } - - alg_data->base = res->start; - alg_data->ioaddr = ioremap(res->start, 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; - } + alg_data->ioaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(alg_data->ioaddr)) + return PTR_ERR(alg_data->ioaddr); ret = clk_enable(alg_data->clk); if (ret) - goto out_unmap; + return ret; freq = clk_get_rate(alg_data->clk); @@ -730,8 +708,8 @@ static int i2c_pnx_probe(struct platform_device *pdev) ret = alg_data->irq; goto out_clock; } - ret = request_irq(alg_data->irq, i2c_pnx_interrupt, - 0, pdev->name, alg_data); + ret = devm_request_irq(&pdev->dev, alg_data->irq, i2c_pnx_interrupt, + 0, pdev->name, alg_data); if (ret) goto out_clock; @@ -739,7 +717,7 @@ static int i2c_pnx_probe(struct platform_device *pdev) ret = i2c_add_numbered_adapter(&alg_data->adapter); if (ret < 0) { dev_err(&pdev->dev, "I2C: Failed to add bus\n"); - goto out_irq; + goto out_clock; } dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n", @@ -747,19 +725,8 @@ static int i2c_pnx_probe(struct platform_device *pdev) return 0; -out_irq: - free_irq(alg_data->irq, alg_data); out_clock: clk_disable(alg_data->clk); -out_unmap: - iounmap(alg_data->ioaddr); -out_release: - release_mem_region(res->start, I2C_PNX_REGION_SIZE); -out_clkget: - clk_put(alg_data->clk); -out_drvdata: - kfree(alg_data); -err_kzalloc: return ret; } @@ -767,13 +734,8 @@ static int i2c_pnx_remove(struct platform_device *pdev) { struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev); - free_irq(alg_data->irq, alg_data); i2c_del_adapter(&alg_data->adapter); clk_disable(alg_data->clk); - iounmap(alg_data->ioaddr); - release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE); - clk_put(alg_data->clk); - kfree(alg_data); return 0; } diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c new file mode 100644 index 00000000000..9e1f8bacfb3 --- /dev/null +++ b/drivers/i2c/busses/i2c-riic.c @@ -0,0 +1,427 @@ +/* + * Renesas RIIC driver + * + * Copyright (C) 2013 Wolfram Sang <wsa@sang-engineering.com> + * Copyright (C) 2013 Renesas Solutions Corp. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +/* + * This i2c core has a lot of interrupts, namely 8. We use their chaining as + * some kind of state machine. + * + * 1) The main xfer routine kicks off a transmission by putting the start bit + * (or repeated start) on the bus and enabling the transmit interrupt (TIE) + * since we need to send the slave address + RW bit in every case. + * + * 2) TIE sends slave address + RW bit and selects how to continue. + * + * 3a) Write case: We keep utilizing TIE as long as we have data to send. If we + * are done, we switch over to the transmission done interrupt (TEIE) and mark + * the message as completed (includes sending STOP) there. + * + * 3b) Read case: We switch over to receive interrupt (RIE). One dummy read is + * needed to start clocking, then we keep receiving until we are done. Note + * that we use the RDRFS mode all the time, i.e. we ACK/NACK every byte by + * writing to the ACKBT bit. I tried using the RDRFS mode only at the end of a + * message to create the final NACK as sketched in the datasheet. This caused + * some subtle races (when byte n was processed and byte n+1 was already + * waiting), though, and I started with the safe approach. + * + * 4) If we got a NACK somewhere, we flag the error and stop the transmission + * via NAKIE. + * + * Also check the comments in the interrupt routines for some gory details. + */ + +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#define RIIC_ICCR1 0x00 +#define RIIC_ICCR2 0x04 +#define RIIC_ICMR1 0x08 +#define RIIC_ICMR3 0x10 +#define RIIC_ICSER 0x18 +#define RIIC_ICIER 0x1c +#define RIIC_ICSR2 0x24 +#define RIIC_ICBRL 0x34 +#define RIIC_ICBRH 0x38 +#define RIIC_ICDRT 0x3c +#define RIIC_ICDRR 0x40 + +#define ICCR1_ICE 0x80 +#define ICCR1_IICRST 0x40 +#define ICCR1_SOWP 0x10 + +#define ICCR2_BBSY 0x80 +#define ICCR2_SP 0x08 +#define ICCR2_RS 0x04 +#define ICCR2_ST 0x02 + +#define ICMR1_CKS_MASK 0x70 +#define ICMR1_BCWP 0x08 +#define ICMR1_CKS(_x) ((((_x) << 4) & ICMR1_CKS_MASK) | ICMR1_BCWP) + +#define ICMR3_RDRFS 0x20 +#define ICMR3_ACKWP 0x10 +#define ICMR3_ACKBT 0x08 + +#define ICIER_TIE 0x80 +#define ICIER_TEIE 0x40 +#define ICIER_RIE 0x20 +#define ICIER_NAKIE 0x10 + +#define ICSR2_NACKF 0x10 + +/* ICBRx (@ PCLK 33MHz) */ +#define ICBR_RESERVED 0xe0 /* Should be 1 on writes */ +#define ICBRL_SP100K (19 | ICBR_RESERVED) +#define ICBRH_SP100K (16 | ICBR_RESERVED) +#define ICBRL_SP400K (21 | ICBR_RESERVED) +#define ICBRH_SP400K (9 | ICBR_RESERVED) + +#define RIIC_INIT_MSG -1 + +struct riic_dev { + void __iomem *base; + u8 *buf; + struct i2c_msg *msg; + int bytes_left; + int err; + int is_last; + struct completion msg_done; + struct i2c_adapter adapter; + struct clk *clk; +}; + +struct riic_irq_desc { + int res_num; + irq_handler_t isr; + char *name; +}; + +static inline void riic_clear_set_bit(struct riic_dev *riic, u8 clear, u8 set, u8 reg) +{ + writeb((readb(riic->base + reg) & ~clear) | set, riic->base + reg); +} + +static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct riic_dev *riic = i2c_get_adapdata(adap); + unsigned long time_left; + int i, ret; + u8 start_bit; + + ret = clk_prepare_enable(riic->clk); + if (ret) + return ret; + + if (readb(riic->base + RIIC_ICCR2) & ICCR2_BBSY) { + riic->err = -EBUSY; + goto out; + } + + reinit_completion(&riic->msg_done); + riic->err = 0; + + writeb(0, riic->base + RIIC_ICSR2); + + for (i = 0, start_bit = ICCR2_ST; i < num; i++) { + riic->bytes_left = RIIC_INIT_MSG; + riic->buf = msgs[i].buf; + riic->msg = &msgs[i]; + riic->is_last = (i == num - 1); + + writeb(ICIER_NAKIE | ICIER_TIE, riic->base + RIIC_ICIER); + + writeb(start_bit, riic->base + RIIC_ICCR2); + + time_left = wait_for_completion_timeout(&riic->msg_done, riic->adapter.timeout); + if (time_left == 0) + riic->err = -ETIMEDOUT; + + if (riic->err) + break; + + start_bit = ICCR2_RS; + } + + out: + clk_disable_unprepare(riic->clk); + + return riic->err ?: num; +} + +static irqreturn_t riic_tdre_isr(int irq, void *data) +{ + struct riic_dev *riic = data; + u8 val; + + if (!riic->bytes_left) + return IRQ_NONE; + + if (riic->bytes_left == RIIC_INIT_MSG) { + val = !!(riic->msg->flags & I2C_M_RD); + if (val) + /* On read, switch over to receive interrupt */ + riic_clear_set_bit(riic, ICIER_TIE, ICIER_RIE, RIIC_ICIER); + else + /* On write, initialize length */ + riic->bytes_left = riic->msg->len; + + val |= (riic->msg->addr << 1); + } else { + val = *riic->buf; + riic->buf++; + riic->bytes_left--; + } + + /* + * Switch to transmission ended interrupt when done. Do check here + * after bytes_left was initialized to support SMBUS_QUICK (new msg has + * 0 length then) + */ + if (riic->bytes_left == 0) + riic_clear_set_bit(riic, ICIER_TIE, ICIER_TEIE, RIIC_ICIER); + + /* + * This acks the TIE interrupt. We get another TIE immediately if our + * value could be moved to the shadow shift register right away. So + * this must be after updates to ICIER (where we want to disable TIE)! + */ + writeb(val, riic->base + RIIC_ICDRT); + + return IRQ_HANDLED; +} + +static irqreturn_t riic_tend_isr(int irq, void *data) +{ + struct riic_dev *riic = data; + + if (readb(riic->base + RIIC_ICSR2) & ICSR2_NACKF) { + /* We got a NACKIE */ + readb(riic->base + RIIC_ICDRR); /* dummy read */ + riic->err = -ENXIO; + } else if (riic->bytes_left) { + return IRQ_NONE; + } + + if (riic->is_last || riic->err) + writeb(ICCR2_SP, riic->base + RIIC_ICCR2); + + writeb(0, riic->base + RIIC_ICIER); + complete(&riic->msg_done); + + return IRQ_HANDLED; +} + +static irqreturn_t riic_rdrf_isr(int irq, void *data) +{ + struct riic_dev *riic = data; + + if (!riic->bytes_left) + return IRQ_NONE; + + if (riic->bytes_left == RIIC_INIT_MSG) { + riic->bytes_left = riic->msg->len; + readb(riic->base + RIIC_ICDRR); /* dummy read */ + return IRQ_HANDLED; + } + + if (riic->bytes_left == 1) { + /* STOP must come before we set ACKBT! */ + if (riic->is_last) + writeb(ICCR2_SP, riic->base + RIIC_ICCR2); + + riic_clear_set_bit(riic, 0, ICMR3_ACKBT, RIIC_ICMR3); + + writeb(0, riic->base + RIIC_ICIER); + complete(&riic->msg_done); + } else { + riic_clear_set_bit(riic, ICMR3_ACKBT, 0, RIIC_ICMR3); + } + + /* Reading acks the RIE interrupt */ + *riic->buf = readb(riic->base + RIIC_ICDRR); + riic->buf++; + riic->bytes_left--; + + return IRQ_HANDLED; +} + +static u32 riic_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm riic_algo = { + .master_xfer = riic_xfer, + .functionality = riic_func, +}; + +static int riic_init_hw(struct riic_dev *riic, u32 spd) +{ + int ret; + unsigned long rate; + + ret = clk_prepare_enable(riic->clk); + if (ret) + return ret; + + /* + * TODO: Implement formula to calculate the timing values depending on + * variable parent clock rate and arbitrary bus speed + */ + rate = clk_get_rate(riic->clk); + if (rate != 33325000) { + dev_err(&riic->adapter.dev, + "invalid parent clk (%lu). Must be 33325000Hz\n", rate); + clk_disable_unprepare(riic->clk); + return -EINVAL; + } + + /* Changing the order of accessing IICRST and ICE may break things! */ + writeb(ICCR1_IICRST | ICCR1_SOWP, riic->base + RIIC_ICCR1); + riic_clear_set_bit(riic, 0, ICCR1_ICE, RIIC_ICCR1); + + switch (spd) { + case 100000: + writeb(ICMR1_CKS(3), riic->base + RIIC_ICMR1); + writeb(ICBRH_SP100K, riic->base + RIIC_ICBRH); + writeb(ICBRL_SP100K, riic->base + RIIC_ICBRL); + break; + case 400000: + writeb(ICMR1_CKS(1), riic->base + RIIC_ICMR1); + writeb(ICBRH_SP400K, riic->base + RIIC_ICBRH); + writeb(ICBRL_SP400K, riic->base + RIIC_ICBRL); + break; + default: + dev_err(&riic->adapter.dev, + "unsupported bus speed (%dHz). Use 100000 or 400000\n", spd); + clk_disable_unprepare(riic->clk); + return -EINVAL; + } + + writeb(0, riic->base + RIIC_ICSER); + writeb(ICMR3_ACKWP | ICMR3_RDRFS, riic->base + RIIC_ICMR3); + + riic_clear_set_bit(riic, ICCR1_IICRST, 0, RIIC_ICCR1); + + clk_disable_unprepare(riic->clk); + + return 0; +} + +static struct riic_irq_desc riic_irqs[] = { + { .res_num = 0, .isr = riic_tend_isr, .name = "riic-tend" }, + { .res_num = 1, .isr = riic_rdrf_isr, .name = "riic-rdrf" }, + { .res_num = 2, .isr = riic_tdre_isr, .name = "riic-tdre" }, + { .res_num = 5, .isr = riic_tend_isr, .name = "riic-nack" }, +}; + +static int riic_i2c_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct riic_dev *riic; + struct i2c_adapter *adap; + struct resource *res; + u32 bus_rate = 0; + int i, ret; + + riic = devm_kzalloc(&pdev->dev, sizeof(*riic), GFP_KERNEL); + if (!riic) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + riic->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(riic->base)) + return PTR_ERR(riic->base); + + riic->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(riic->clk)) { + dev_err(&pdev->dev, "missing controller clock"); + return PTR_ERR(riic->clk); + } + + for (i = 0; i < ARRAY_SIZE(riic_irqs); i++) { + res = platform_get_resource(pdev, IORESOURCE_IRQ, riic_irqs[i].res_num); + if (!res) + return -ENODEV; + + ret = devm_request_irq(&pdev->dev, res->start, riic_irqs[i].isr, + 0, riic_irqs[i].name, riic); + if (ret) { + dev_err(&pdev->dev, "failed to request irq %s\n", riic_irqs[i].name); + return ret; + } + } + + adap = &riic->adapter; + i2c_set_adapdata(adap, riic); + strlcpy(adap->name, "Renesas RIIC adapter", sizeof(adap->name)); + adap->owner = THIS_MODULE; + adap->algo = &riic_algo; + adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; + + init_completion(&riic->msg_done); + + of_property_read_u32(np, "clock-frequency", &bus_rate); + ret = riic_init_hw(riic, bus_rate); + if (ret) + return ret; + + + ret = i2c_add_adapter(adap); + if (ret) { + dev_err(&pdev->dev, "failed to add adapter\n"); + return ret; + } + + platform_set_drvdata(pdev, riic); + + dev_info(&pdev->dev, "registered with %dHz bus speed\n", bus_rate); + return 0; +} + +static int riic_i2c_remove(struct platform_device *pdev) +{ + struct riic_dev *riic = platform_get_drvdata(pdev); + + writeb(0, riic->base + RIIC_ICIER); + i2c_del_adapter(&riic->adapter); + + return 0; +} + +static struct of_device_id riic_i2c_dt_ids[] = { + { .compatible = "renesas,riic-rz" }, + { /* Sentinel */ }, +}; + +static struct platform_driver riic_i2c_driver = { + .probe = riic_i2c_probe, + .remove = riic_i2c_remove, + .driver = { + .name = "i2c-riic", + .owner = THIS_MODULE, + .of_match_table = riic_i2c_dt_ids, + }, +}; + +module_platform_driver(riic_i2c_driver); + +MODULE_DESCRIPTION("Renesas RIIC adapter"); +MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, riic_i2c_dt_ids); diff --git a/drivers/i2c/busses/i2c-robotfuzz-osif.c b/drivers/i2c/busses/i2c-robotfuzz-osif.c new file mode 100644 index 00000000000..ced9c6a308d --- /dev/null +++ b/drivers/i2c/busses/i2c-robotfuzz-osif.c @@ -0,0 +1,202 @@ +/* + * Driver for RobotFuzz OSIF + * + * Copyright (c) 2013 Andrew Lunn <andrew@lunn.ch> + * Copyright (c) 2007 Barry Carter <Barry.Carter@robotfuzz.com> + * + * Based on the i2c-tiny-usb by + * + * Copyright (C) 2006 Til Harbaum (Till@Harbaum.org) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/usb.h> + +#define OSIFI2C_READ 20 +#define OSIFI2C_WRITE 21 +#define OSIFI2C_STOP 22 +#define OSIFI2C_STATUS 23 +#define OSIFI2C_SET_BIT_RATE 24 + +#define STATUS_ADDRESS_ACK 0 +#define STATUS_ADDRESS_NAK 2 + +struct osif_priv { + struct usb_device *usb_dev; + struct usb_interface *interface; + struct i2c_adapter adapter; + unsigned char status; +}; + +static int osif_usb_read(struct i2c_adapter *adapter, int cmd, + int value, int index, void *data, int len) +{ + struct osif_priv *priv = adapter->algo_data; + + return usb_con |