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 ...
This commit is contained in:
Коммит
02d0a75246
|
@ -9,6 +9,7 @@ Required properties :
|
|||
- interrupts: interrupt number to the cpu.
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
- clocks: phandles to input clocks.
|
||||
|
||||
Optional properties:
|
||||
- Child nodes conforming to i2c bus binding
|
||||
|
@ -21,6 +22,7 @@ i2c0: i2c@fff84000 {
|
|||
interrupts = <12 4 6>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&twi0_clk>;
|
||||
|
||||
24c512@50 {
|
||||
compatible = "24c512";
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
* NXP PCA954x I2C bus switch
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: Must contain one of the following.
|
||||
"nxp,pca9540", "nxp,pca9542", "nxp,pca9543", "nxp,pca9544",
|
||||
"nxp,pca9545", "nxp,pca9546", "nxp,pca9547", "nxp,pca9548"
|
||||
|
||||
- reg: The I2C address of the device.
|
||||
|
||||
The following required properties are defined externally:
|
||||
|
||||
- Standard I2C mux properties. See i2c-mux.txt in this directory.
|
||||
- I2C child bus nodes. See i2c-mux.txt in this directory.
|
||||
|
||||
Optional Properties:
|
||||
|
||||
- reset-gpios: Reference to the GPIO connected to the reset input.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
i2c-switch@74 {
|
||||
compatible = "nxp,pca9548";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x74>;
|
||||
|
||||
i2c@2 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <2>;
|
||||
|
||||
eeprom@54 {
|
||||
compatible = "at,24c08";
|
||||
reg = <0x54>;
|
||||
};
|
||||
};
|
||||
|
||||
i2c@4 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <4>;
|
||||
|
||||
rtc@51 {
|
||||
compatible = "nxp,pcf8563";
|
||||
reg = <0x51>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,29 @@
|
|||
Device tree configuration for Renesas RIIC driver
|
||||
|
||||
Required properties:
|
||||
- compatible : "renesas,riic-<soctype>". "renesas,riic-rz" as fallback
|
||||
- reg : address start and address range size of device
|
||||
- interrupts : 8 interrupts (TEI, RI, TI, SPI, STI, NAKI, ALI, TMOI)
|
||||
- clock-frequency : frequency of bus clock in Hz
|
||||
- #address-cells : should be <1>
|
||||
- #size-cells : should be <0>
|
||||
|
||||
Pinctrl properties might be needed, too. See there.
|
||||
|
||||
Example:
|
||||
|
||||
i2c0: i2c@fcfee000 {
|
||||
compatible = "renesas,riic-r7s72100", "renesas,riic-rz";
|
||||
reg = <0xfcfee000 0x44>;
|
||||
interrupts = <0 157 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 158 IRQ_TYPE_EDGE_RISING>,
|
||||
<0 159 IRQ_TYPE_EDGE_RISING>,
|
||||
<0 160 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 161 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 162 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 163 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 164 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clock-frequency = <100000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
|
@ -10,6 +10,8 @@ Required properties:
|
|||
inside HDMIPHY block found on several samsung SoCs
|
||||
(d) "samsung, exynos5440-i2c", for s3c2440-like i2c used
|
||||
on EXYNOS5440 which does not need GPIO configuration.
|
||||
(e) "samsung, exynos5-sata-phy-i2c", for s3c2440-like i2c used as
|
||||
a host to SATA PHY controller on an internal bus.
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: interrupt number to the cpu.
|
||||
|
|
|
@ -64,9 +64,6 @@ EINVAL
|
|||
detected before any I/O operation was started. Use a more
|
||||
specific fault code when you can.
|
||||
|
||||
One example would be a driver trying an SMBus Block Write
|
||||
with block size outside the range of 1-32 bytes.
|
||||
|
||||
EIO
|
||||
This rather vague error means something went wrong when
|
||||
performing an I/O operation. Use a more specific fault
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -588,6 +588,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,
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
*
|
||||
*/
|
||||
#include <linux/export.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
|
@ -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_control_msg(priv->usb_dev, usb_rcvctrlpipe(priv->usb_dev, 0),
|
||||
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
|
||||
USB_DIR_IN, value, index, data, len, 2000);
|
||||
}
|
||||
|
||||
static int osif_usb_write(struct i2c_adapter *adapter, int cmd,
|
||||
int value, int index, void *data, int len)
|
||||
{
|
||||
|
||||
struct osif_priv *priv = adapter->algo_data;
|
||||
|
||||
return usb_control_msg(priv->usb_dev, usb_sndctrlpipe(priv->usb_dev, 0),
|
||||
cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
|
||||
value, index, data, len, 2000);
|
||||
}
|
||||
|
||||
static int osif_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
struct osif_priv *priv = adapter->algo_data;
|
||||
struct i2c_msg *pmsg;
|
||||
int ret = 0;
|
||||
int i, cmd;
|
||||
|
||||
for (i = 0; ret >= 0 && i < num; i++) {
|
||||
pmsg = &msgs[i];
|
||||
|
||||
if (pmsg->flags & I2C_M_RD) {
|
||||
cmd = OSIFI2C_READ;
|
||||
|
||||
ret = osif_usb_read(adapter, cmd, pmsg->flags,
|
||||
pmsg->addr, pmsg->buf,
|
||||
pmsg->len);
|
||||
if (ret != pmsg->len) {
|
||||
dev_err(&adapter->dev, "failure reading data\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
} else {
|
||||
cmd = OSIFI2C_WRITE;
|
||||
|
||||
ret = osif_usb_write(adapter, cmd, pmsg->flags,
|
||||
pmsg->addr, pmsg->buf, pmsg->len);
|
||||
if (ret != pmsg->len) {
|
||||
dev_err(&adapter->dev, "failure writing data\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
}
|
||||
|
||||
ret = osif_usb_read(adapter, OSIFI2C_STOP, 0, 0, NULL, 0);
|
||||
if (ret) {
|
||||
dev_err(&adapter->dev, "failure sending STOP\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
/* read status */
|
||||
ret = osif_usb_read(adapter, OSIFI2C_STATUS, 0, 0,
|
||||
&priv->status, 1);
|
||||
if (ret != 1) {
|
||||
dev_err(&adapter->dev, "failure reading status\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
if (priv->status != STATUS_ADDRESS_ACK) {
|
||||
dev_dbg(&adapter->dev, "status = %d\n", priv->status);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static u32 osif_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm osif_algorithm = {
|
||||
.master_xfer = osif_xfer,
|
||||
.functionality = osif_func,
|
||||
};
|
||||
|
||||
#define USB_OSIF_VENDOR_ID 0x1964
|
||||
#define USB_OSIF_PRODUCT_ID 0x0001
|
||||
|
||||
static struct usb_device_id osif_table[] = {
|
||||
{ USB_DEVICE(USB_OSIF_VENDOR_ID, USB_OSIF_PRODUCT_ID) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, osif_table);
|
||||
|
||||
static int osif_probe(struct usb_interface *interface,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
struct osif_priv *priv;
|
||||
u16 version;
|
||||
|
||||
priv = devm_kzalloc(&interface->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->usb_dev = usb_get_dev(interface_to_usbdev(interface));
|
||||
priv->interface = interface;
|
||||
|
||||
usb_set_intfdata(interface, priv);
|
||||
|
||||
priv->adapter.owner = THIS_MODULE;
|
||||
priv->adapter.class = I2C_CLASS_HWMON;
|
||||
priv->adapter.algo = &osif_algorithm;
|
||||
priv->adapter.algo_data = priv;
|
||||
snprintf(priv->adapter.name, sizeof(priv->adapter.name),
|
||||
"OSIF at bus %03d device %03d",
|
||||
priv->usb_dev->bus->busnum, priv->usb_dev->devnum);
|
||||
|
||||
/*
|
||||
* Set bus frequency. The frequency is:
|
||||
* 120,000,000 / ( 16 + 2 * div * 4^prescale).
|
||||
* Using dev = 52, prescale = 0 give 100KHz */
|
||||
ret = osif_usb_read(&priv->adapter, OSIFI2C_SET_BIT_RATE, 52, 0,
|
||||
NULL, 0);
|
||||
if (ret) {
|
||||
dev_err(&interface->dev, "failure sending bit rate");
|
||||
usb_put_dev(priv->usb_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c_add_adapter(&(priv->adapter));
|
||||
|
||||
version = le16_to_cpu(priv->usb_dev->descriptor.bcdDevice);
|
||||
dev_info(&interface->dev,
|
||||
"version %x.%02x found at bus %03d address %03d",
|
||||
version >> 8, version & 0xff,
|
||||
priv->usb_dev->bus->busnum, priv->usb_dev->devnum);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void osif_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct osif_priv *priv = usb_get_intfdata(interface);
|
||||
|
||||
i2c_del_adapter(&(priv->adapter));
|
||||
usb_set_intfdata(interface, NULL);
|
||||
usb_put_dev(priv->usb_dev);
|
||||
}
|
||||
|
||||
static struct usb_driver osif_driver = {
|
||||
.name = "RobotFuzz Open Source InterFace, OSIF",
|
||||
.probe = osif_probe,
|
||||
.disconnect = osif_disconnect,
|
||||
.id_table = osif_table,
|
||||
};
|
||||
|
||||
module_usb_driver(osif_driver);
|
||||
|
||||
MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
|
||||
MODULE_AUTHOR("Barry Carter <barry.carter@robotfuzz.com>");
|
||||
MODULE_DESCRIPTION("RobotFuzz OSIF driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -86,6 +86,7 @@
|
|||
#define QUIRK_S3C2440 (1 << 0)
|
||||
#define QUIRK_HDMIPHY (1 << 1)
|
||||
#define QUIRK_NO_GPIO (1 << 2)
|
||||
#define QUIRK_POLL (1 << 3)
|
||||
|
||||
/* Max time to wait for bus to become idle after a xfer (in us) */
|
||||
#define S3C2410_IDLE_TIMEOUT 5000
|
||||
|
@ -101,7 +102,7 @@ enum s3c24xx_i2c_state {
|
|||
|
||||
struct s3c24xx_i2c {
|
||||
wait_queue_head_t wait;
|
||||
unsigned int quirks;
|
||||
kernel_ulong_t quirks;
|
||||
unsigned int suspended:1;
|
||||
|
||||
struct i2c_msg *msg;
|
||||
|
@ -123,7 +124,7 @@ struct s3c24xx_i2c {
|
|||
struct s3c2410_platform_i2c *pdata;
|
||||
int gpios[2];
|
||||
struct pinctrl *pctrl;
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
#if defined(CONFIG_ARM_S3C24XX_CPUFREQ)
|
||||
struct notifier_block freq_transition;
|
||||
#endif
|
||||
};
|
||||
|
@ -142,6 +143,8 @@ static struct platform_device_id s3c24xx_driver_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
|
||||
|
||||
static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id s3c24xx_i2c_match[] = {
|
||||
{ .compatible = "samsung,s3c2410-i2c", .data = (void *)0 },
|
||||
|
@ -150,6 +153,8 @@ static const struct of_device_id s3c24xx_i2c_match[] = {
|
|||
.data = (void *)(QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO) },
|
||||
{ .compatible = "samsung,exynos5440-i2c",
|
||||
.data = (void *)(QUIRK_S3C2440 | QUIRK_NO_GPIO) },
|
||||
{ .compatible = "samsung,exynos5-sata-phy-i2c",
|
||||
.data = (void *)(QUIRK_S3C2440 | QUIRK_POLL | QUIRK_NO_GPIO) },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, s3c24xx_i2c_match);
|
||||
|
@ -160,12 +165,12 @@ MODULE_DEVICE_TABLE(of, s3c24xx_i2c_match);
|
|||
* Get controller type either from device tree or platform device variant.
|
||||
*/
|
||||
|
||||
static inline unsigned int s3c24xx_get_device_quirks(struct platform_device *pdev)
|
||||
static inline kernel_ulong_t s3c24xx_get_device_quirks(struct platform_device *pdev)
|
||||
{
|
||||
if (pdev->dev.of_node) {
|
||||
const struct of_device_id *match;
|
||||
match = of_match_node(s3c24xx_i2c_match, pdev->dev.of_node);
|
||||
return (unsigned int)match->data;
|
||||
return (kernel_ulong_t)match->data;
|
||||
}
|
||||
|
||||
return platform_get_device_id(pdev)->driver_data;
|
||||
|
@ -188,7 +193,8 @@ static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret)
|
|||
if (ret)
|
||||
i2c->msg_idx = ret;
|
||||
|
||||
wake_up(&i2c->wait);
|
||||
if (!(i2c->quirks & QUIRK_POLL))
|
||||
wake_up(&i2c->wait);
|
||||
}
|
||||
|
||||
static inline void s3c24xx_i2c_disable_ack(struct s3c24xx_i2c *i2c)
|
||||
|
@ -225,6 +231,22 @@ static inline void s3c24xx_i2c_enable_irq(struct s3c24xx_i2c *i2c)
|
|||
writel(tmp | S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON);
|
||||
}
|
||||
|
||||
static bool is_ack(struct s3c24xx_i2c *i2c)
|
||||
{
|
||||
int tries;
|
||||
|
||||
for (tries = 50; tries; --tries) {
|
||||
if (readl(i2c->regs + S3C2410_IICCON)
|
||||
& S3C2410_IICCON_IRQPEND) {
|
||||
if (!(readl(i2c->regs + S3C2410_IICSTAT)
|
||||
& S3C2410_IICSTAT_LASTBIT))
|
||||
return true;
|
||||
}
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
dev_err(i2c->dev, "ack was not recieved\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* s3c24xx_i2c_message_start
|
||||
*
|
||||
|
@ -269,6 +291,16 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
|
|||
|
||||
stat |= S3C2410_IICSTAT_START;
|
||||
writel(stat, i2c->regs + S3C2410_IICSTAT);
|
||||
|
||||
if (i2c->quirks & QUIRK_POLL) {
|
||||
while ((i2c->msg_num != 0) && is_ack(i2c)) {
|
||||
i2c_s3c_irq_nextbyte(i2c, stat);
|
||||
stat = readl(i2c->regs + S3C2410_IICSTAT);
|
||||
|
||||
if (stat & S3C2410_IICSTAT_ARBITR)
|
||||
dev_err(i2c->dev, "deal with arbitration loss\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
|
||||
|
@ -676,6 +708,15 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
|
|||
s3c24xx_i2c_enable_irq(i2c);
|
||||
s3c24xx_i2c_message_start(i2c, msgs);
|
||||
|
||||
if (i2c->quirks & QUIRK_POLL) {
|
||||
ret = i2c->msg_idx;
|
||||
|
||||
if (ret != num)
|
||||
dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
|
||||
|
||||
ret = i2c->msg_idx;
|
||||
|
@ -821,6 +862,9 @@ static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)
|
|||
if (div1 == 512)
|
||||
iiccon |= S3C2410_IICCON_TXDIV_512;
|
||||
|
||||
if (i2c->quirks & QUIRK_POLL)
|
||||
iiccon |= S3C2410_IICCON_SCALE(2);
|
||||
|
||||
writel(iiccon, i2c->regs + S3C2410_IICCON);
|
||||
|
||||
if (i2c->quirks & QUIRK_S3C2440) {
|
||||
|
@ -843,7 +887,7 @@ static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
#if defined(CONFIG_ARM_S3C24XX_CPUFREQ)
|
||||
|
||||
#define freq_to_i2c(_n) container_of(_n, struct s3c24xx_i2c, freq_transition)
|
||||
|
||||
|
@ -1118,18 +1162,20 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
|
|||
* ensure no current IRQs pending
|
||||
*/
|
||||
|
||||
i2c->irq = ret = platform_get_irq(pdev, 0);
|
||||
if (ret <= 0) {
|
||||
dev_err(&pdev->dev, "cannot find IRQ\n");
|
||||
return ret;
|
||||
}
|
||||
if (!(i2c->quirks & QUIRK_POLL)) {
|
||||
i2c->irq = ret = platform_get_irq(pdev, 0);
|
||||
if (ret <= 0) {
|
||||
dev_err(&pdev->dev, "cannot find IRQ\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq, 0,
|
||||
dev_name(&pdev->dev), i2c);
|
||||
dev_name(&pdev->dev), i2c);
|
||||
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
|
||||
return ret;
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = s3c24xx_i2c_register_cpufreq(i2c);
|
||||
|
|
|
@ -162,7 +162,6 @@ static const struct i2c_algorithm usb_algorithm = {
|
|||
static const struct usb_device_id i2c_tiny_usb_table[] = {
|
||||
{ USB_DEVICE(0x0403, 0xc631) }, /* FTDI */
|
||||
{ USB_DEVICE(0x1c40, 0x0534) }, /* EZPrototypes */
|
||||
{ USB_DEVICE(0x1964, 0x0001) }, /* Robofuzz OSIF */
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
|
|
|
@ -118,8 +118,7 @@ static int vprbrd_i2c_addr(struct usb_device *usb_dev,
|
|||
static int vprbrd_i2c_read(struct vprbrd *vb, struct i2c_msg *msg)
|
||||
{
|
||||
int ret;
|
||||
u16 remain_len, bytes_xfer, len1, len2,
|
||||
start = 0x0000;
|
||||
u16 remain_len, len1, len2, start = 0x0000;
|
||||
struct vprbrd_i2c_read_msg *rmsg =
|
||||
(struct vprbrd_i2c_read_msg *)vb->buf;
|
||||
|
||||
|
@ -166,7 +165,6 @@ static int vprbrd_i2c_read(struct vprbrd *vb, struct i2c_msg *msg)
|
|||
rmsg->header.len3 = remain_len - 512;
|
||||
rmsg->header.len4 = 0x00;
|
||||
rmsg->header.len5 = 0x00;
|
||||
bytes_xfer = remain_len;
|
||||
remain_len = 0;
|
||||
} else if (remain_len <= 1022) {
|
||||
len1 = 512;
|
||||
|
@ -367,7 +365,7 @@ static int vprbrd_i2c_probe(struct platform_device *pdev)
|
|||
int ret;
|
||||
int pipe;
|
||||
|
||||
vb_i2c = kzalloc(sizeof(*vb_i2c), GFP_KERNEL);
|
||||
vb_i2c = devm_kzalloc(&pdev->dev, sizeof(*vb_i2c), GFP_KERNEL);
|
||||
if (vb_i2c == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -394,14 +392,12 @@ static int vprbrd_i2c_probe(struct platform_device *pdev)
|
|||
if (ret != 1) {
|
||||
dev_err(&pdev->dev,
|
||||
"failure setting i2c_bus_freq to %d\n", i2c_bus_freq);
|
||||
ret = -EIO;
|
||||
goto error;
|
||||
return -EIO;
|
||||
}
|
||||
} else {
|
||||
dev_err(&pdev->dev,
|
||||
"invalid i2c_bus_freq setting:%d\n", i2c_bus_freq);
|
||||
ret = -EIO;
|
||||
goto error;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
vb_i2c->i2c.dev.parent = &pdev->dev;
|
||||
|
@ -412,10 +408,6 @@ static int vprbrd_i2c_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, vb_i2c);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
kfree(vb_i2c);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vprbrd_i2c_remove(struct platform_device *pdev)
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
|
@ -69,7 +70,7 @@ struct xiic_i2c {
|
|||
struct i2c_adapter adap;
|
||||
struct i2c_msg *tx_msg;
|
||||
spinlock_t lock;
|
||||
unsigned int tx_pos;
|
||||
unsigned int tx_pos;
|
||||
unsigned int nmsgs;
|
||||
enum xilinx_i2c_state state;
|
||||
struct i2c_msg *rx_msg;
|
||||
|
@ -272,8 +273,8 @@ static void xiic_read_rx(struct xiic_i2c *i2c)
|
|||
|
||||
bytes_in_fifo = xiic_getreg8(i2c, XIIC_RFO_REG_OFFSET) + 1;
|
||||
|
||||
dev_dbg(i2c->adap.dev.parent, "%s entry, bytes in fifo: %d, msg: %d"
|
||||
", SR: 0x%x, CR: 0x%x\n",
|
||||
dev_dbg(i2c->adap.dev.parent,
|
||||
"%s entry, bytes in fifo: %d, msg: %d, SR: 0x%x, CR: 0x%x\n",
|
||||
__func__, bytes_in_fifo, xiic_rx_space(i2c),
|
||||
xiic_getreg8(i2c, XIIC_SR_REG_OFFSET),
|
||||
xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
|
||||
|
@ -340,9 +341,10 @@ static void xiic_process(struct xiic_i2c *i2c)
|
|||
ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
|
||||
pend = isr & ier;
|
||||
|
||||
dev_dbg(i2c->adap.dev.parent, "%s entry, IER: 0x%x, ISR: 0x%x, "
|
||||
"pend: 0x%x, SR: 0x%x, msg: %p, nmsgs: %d\n",
|
||||
__func__, ier, isr, pend, xiic_getreg8(i2c, XIIC_SR_REG_OFFSET),
|
||||
dev_dbg(i2c->adap.dev.parent, "%s: IER: 0x%x, ISR: 0x%x, pend: 0x%x\n",
|
||||
__func__, ier, isr, pend);
|
||||
dev_dbg(i2c->adap.dev.parent, "%s: SR: 0x%x, msg: %p, nmsgs: %d\n",
|
||||
__func__, xiic_getreg8(i2c, XIIC_SR_REG_OFFSET),
|
||||
i2c->tx_msg, i2c->nmsgs);
|
||||
|
||||
/* Do not processes a devices interrupts if the device has no
|
||||
|
@ -542,9 +544,10 @@ static void xiic_start_send(struct xiic_i2c *i2c)
|
|||
|
||||
xiic_irq_clr(i2c, XIIC_INTR_TX_ERROR_MASK);
|
||||
|
||||
dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, len: %d, "
|
||||
"ISR: 0x%x, CR: 0x%x\n",
|
||||
__func__, msg, msg->len, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
|
||||
dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, len: %d",
|
||||
__func__, msg, msg->len);
|
||||
dev_dbg(i2c->adap.dev.parent, "%s entry, ISR: 0x%x, CR: 0x%x\n",
|
||||
__func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
|
||||
xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
|
||||
|
||||
if (!(msg->flags & I2C_M_NOSTART)) {
|
||||
|
@ -695,32 +698,20 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
|||
int ret, irq;
|
||||
u8 i;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
goto resource_missing;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
goto resource_missing;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
|
||||
i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
|
||||
if (!i2c)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
|
||||
dev_err(&pdev->dev, "Memory region busy\n");
|
||||
ret = -EBUSY;
|
||||
goto request_mem_failed;
|
||||
}
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2c->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(i2c->base))
|
||||
return PTR_ERR(i2c->base);
|
||||
|
||||
i2c->base = ioremap(res->start, resource_size(res));
|
||||
if (!i2c->base) {
|
||||
dev_err(&pdev->dev, "Unable to map registers\n");
|
||||
ret = -EIO;
|
||||
goto map_failed;
|
||||
}
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
/* hook up driver to tree */
|
||||
platform_set_drvdata(pdev, i2c);
|
||||
|
@ -729,21 +720,23 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
|||
i2c->adap.dev.parent = &pdev->dev;
|
||||
i2c->adap.dev.of_node = pdev->dev.of_node;
|
||||
|
||||
xiic_reinit(i2c);
|
||||
|
||||
spin_lock_init(&i2c->lock);
|
||||
init_waitqueue_head(&i2c->wait);
|
||||
ret = request_irq(irq, xiic_isr, 0, pdev->name, i2c);
|
||||
if (ret) {
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, irq, xiic_isr, 0, pdev->name, i2c);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Cannot claim IRQ\n");
|
||||
goto request_irq_failed;
|
||||
return ret;
|
||||
}
|
||||
|
||||
xiic_reinit(i2c);
|
||||
|
||||
/* add i2c adapter to i2c tree */
|
||||
ret = i2c_add_adapter(&i2c->adap);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to add adapter\n");
|
||||
goto add_adapter_failed;
|
||||
xiic_deinit(i2c);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pdata) {
|
||||
|
@ -753,43 +746,17 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
return 0;
|
||||
|
||||
add_adapter_failed:
|
||||
free_irq(irq, i2c);
|
||||
request_irq_failed:
|
||||
xiic_deinit(i2c);
|
||||
iounmap(i2c->base);
|
||||
map_failed:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
request_mem_failed:
|
||||
kfree(i2c);
|
||||
|
||||
return ret;
|
||||
resource_missing:
|
||||
dev_err(&pdev->dev, "IRQ or Memory resource is missing\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int xiic_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct xiic_i2c *i2c = platform_get_drvdata(pdev);
|
||||
struct resource *res;
|
||||
|
||||
/* remove adapter & data */
|
||||
i2c_del_adapter(&i2c->adap);
|
||||
|
||||
xiic_deinit(i2c);
|
||||
|
||||
free_irq(platform_get_irq(pdev, 0), i2c);
|
||||
|
||||
iounmap(i2c->base);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (res)
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
|
||||
kfree(i2c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,14 +35,15 @@
|
|||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-mux.h>
|
||||
|
||||
#include <linux/i2c/pca954x.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define PCA954X_MAX_NCHANS 8
|
||||
|
||||
|
@ -186,28 +187,43 @@ static int pca954x_probe(struct i2c_client *client,
|
|||
{
|
||||
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
|
||||
struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||
struct device_node *np = client->dev.of_node;
|
||||
int num, force, class;
|
||||
struct pca954x *data;
|
||||
int ret = -ENODEV;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
|
||||
goto err;
|
||||
return -ENODEV;
|
||||
|
||||
data = kzalloc(sizeof(struct pca954x), GFP_KERNEL);
|
||||
if (!data) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct pca954x), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
|
||||
if (IS_ENABLED(CONFIG_OF) && np) {
|
||||
enum of_gpio_flags flags;
|
||||
int gpio;
|
||||
|
||||
/* Get the mux out of reset if a reset GPIO is specified. */
|
||||
gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
|
||||
if (gpio_is_valid(gpio)) {
|
||||
ret = devm_gpio_request_one(&client->dev, gpio,
|
||||
flags & OF_GPIO_ACTIVE_LOW ?
|
||||
GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
|
||||
"pca954x reset");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the mux register at addr to verify
|
||||
* that the mux is in fact present. This also
|
||||
* initializes the mux to disconnected state.
|
||||
*/
|
||||
if (i2c_smbus_write_byte(client, 0) < 0) {
|
||||
dev_warn(&client->dev, "probe failed\n");
|
||||
goto exit_free;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
data->type = id->driver_data;
|
||||
|
@ -252,9 +268,6 @@ static int pca954x_probe(struct i2c_client *client,
|
|||
virt_reg_failed:
|
||||
for (num--; num >= 0; num--)
|
||||
i2c_del_mux_adapter(data->virt_adaps[num]);
|
||||
exit_free:
|
||||
kfree(data);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -270,7 +283,6 @@ static int pca954x_remove(struct i2c_client *client)
|
|||
data->virt_adaps[i] = NULL;
|
||||
}
|
||||
|
||||
kfree(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@ struct i2c_pnx_algo_data {
|
|||
int last;
|
||||
struct clk *clk;
|
||||
struct i2c_adapter adapter;
|
||||
phys_addr_t base;
|
||||
int irq;
|
||||
u32 timeout;
|
||||
};
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009 ST-Ericsson
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef __PDATA_I2C_NOMADIK_H
|
||||
#define __PDATA_I2C_NOMADIK_H
|
||||
|
||||
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
|
||||
* @slsu: Slave data setup time in ns.
|
||||
* The needed setup time for three modes of operation
|
||||
* are 250ns, 100ns and 10ns respectively thus leading
|
||||
* to the values of 14, 6, 2 for a 48 MHz i2c clk
|
||||
* @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 short slsu;
|
||||
unsigned char tft;
|
||||
unsigned char rft;
|
||||
int timeout;
|
||||
enum i2c_freq_mode sm;
|
||||
};
|
||||
|
||||
#endif /* __PDATA_I2C_NOMADIK_H */
|
Загрузка…
Ссылка в новой задаче