Commit 96895199 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'i2c/for-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull i2c updates from Wolfram Sang:
 "For 3.19, the I2C subsystem has to offer special candy this time.
  Right in time for Christmas :)

   - I2C slave framework: finally, a generic mechanism for Linux being
     an I2C slave (if the bus driver supports that).  Docs are still
     missing but will come later this cycle, the code is good enough to
     go.
   - I2C muxes represent their topology in sysfs much more detailed.
     This will help users to navigate around much easier.
   - irq population of i2c clients is now done at probe time, not device
     creation time, to have better support for deferred probing.
   - new drivers for Imagination SCB, Amlogic Meson
   - DMA support added for Freescale IMX, Renesas SHMobile
   - slightly bigger driver updates to OMAP, i801, AT91, and rk3x
     (mostly quirk handling, timing updates, and using better kernel
     interfaces)
   - eeprom driver can now write with byte-access (very slow, but OK to
     have)
   - and the bunch of smaller fixes, cleanups, ID updates..."

* 'i2c/for-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (56 commits)
  i2c: sh_mobile: remove unneeded DMA mask
  i2c: rcar: add slave support
  i2c: slave-eeprom: add eeprom simulator driver
  i2c: core changes for slave support
  MAINTAINERS: add I2C dt bindings also to I2C realm
  i2c: designware: Fix falling time bindings doc
  i2c: davinci: switch to use platform_get_irq
  Documentation: i2c: Use PM ops instead of legacy suspend/resume
  i2c: sh_mobile: optimize irq entry
  i2c: pxa: add support for SCCB devices
  omap: i2c: don't check bus state IP rev3.3 and earlier
  i2c: s3c2410: Handle i2c sys_cfg register in i2c driver
  i2c: rk3x: add Kconfig dependency on COMMON_CLK
  i2c: omap: add notes related to i2c multimaster mode
  i2c: omap: don't reset controller if Arbitration Lost detected
  i2c: omap: implement workaround for handling invalid BB-bit values
  i2c: omap: cleanup register definitions
  i2c: rk3x: handle dynamic clock rate changes correctly
  i2c: at91: enable probe deferring on dma channel request
  i2c: at91: remove legacy DMA support
  ...
parents 8fd9589c 6cf710d4
...@@ -14,10 +14,10 @@ Optional properties : ...@@ -14,10 +14,10 @@ Optional properties :
- i2c-sda-hold-time-ns : should contain the SDA hold time in nanoseconds. - i2c-sda-hold-time-ns : should contain the SDA hold time in nanoseconds.
This option is only supported in hardware blocks version 1.11a or newer. This option is only supported in hardware blocks version 1.11a or newer.
- i2c-scl-falling-time : should contain the SCL falling time in nanoseconds. - i2c-scl-falling-time-ns : should contain the SCL falling time in nanoseconds.
This value which is by default 300ns is used to compute the tLOW period. This value which is by default 300ns is used to compute the tLOW period.
- i2c-sda-falling-time : should contain the SDA falling time in nanoseconds. - i2c-sda-falling-time-ns : should contain the SDA falling time in nanoseconds.
This value which is by default 300ns is used to compute the tHIGH period. This value which is by default 300ns is used to compute the tHIGH period.
Example : Example :
......
IMG Serial Control Bus (SCB) I2C Controller
Required Properties:
- compatible: "img,scb-i2c"
- reg: Physical base address and length of controller registers
- interrupts: Interrupt number used by the controller
- clocks : Should contain a clock specifier for each entry in clock-names
- clock-names : Should contain the following entries:
"scb", for the SCB core clock.
"sys", for the system clock.
- clock-frequency: The I2C bus frequency in Hz
- #address-cells: Should be <1>
- #size-cells: Should be <0>
Example:
i2c@18100000 {
compatible = "img,scb-i2c";
reg = <0x18100000 0x200>;
interrupts = <GIC_SHARED 2 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&i2c0_clk>, <&system_clk>;
clock-names = "scb", "sys";
clock-frequency = <400000>;
#address-cells = <1>;
#size-cells = <0>;
};
...@@ -11,6 +11,8 @@ Required properties: ...@@ -11,6 +11,8 @@ Required properties:
Optional properties: Optional properties:
- clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz. - clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz.
The absence of the propoerty indicates the default frequency 100 kHz. The absence of the propoerty indicates the default frequency 100 kHz.
- dmas: A list of two dma specifiers, one for each entry in dma-names.
- dma-names: should contain "tx" and "rx".
Examples: Examples:
...@@ -26,3 +28,12 @@ i2c@70038000 { /* HS-I2C on i.MX51 */ ...@@ -26,3 +28,12 @@ i2c@70038000 { /* HS-I2C on i.MX51 */
interrupts = <64>; interrupts = <64>;
clock-frequency = <400000>; clock-frequency = <400000>;
}; };
i2c0: i2c@40066000 { /* i2c0 on vf610 */
compatible = "fsl,vf610-i2c";
reg = <0x40066000 0x1000>;
interrupts =<0 71 0x04>;
dmas = <&edma0 0 50>,
<&edma0 0 51>;
dma-names = "rx","tx";
};
Amlogic Meson I2C controller
Required properties:
- compatible: must be "amlogic,meson6-i2c"
- reg: physical address and length of the device registers
- interrupts: a single interrupt specifier
- clocks: clock for the device
- #address-cells: should be <1>
- #size-cells: should be <0>
Optional properties:
- clock-frequency: the desired I2C bus clock frequency in Hz; in
absence of this property the default value is used (100 kHz).
Examples:
i2c@c8100500 {
compatible = "amlogic,meson6-i2c";
reg = <0xc8100500 0x20>;
interrupts = <0 92 1>;
clocks = <&clk81>;
#address-cells = <1>;
#size-cells = <0>;
};
...@@ -2,6 +2,15 @@ Device tree configuration for Renesas IIC (sh_mobile) driver ...@@ -2,6 +2,15 @@ Device tree configuration for Renesas IIC (sh_mobile) driver
Required properties: Required properties:
- compatible : "renesas,iic-<soctype>". "renesas,rmobile-iic" as fallback - compatible : "renesas,iic-<soctype>". "renesas,rmobile-iic" as fallback
Examples with soctypes are:
- "renesas,iic-r8a73a4" (R-Mobile APE6)
- "renesas,iic-r8a7740" (R-Mobile A1)
- "renesas,iic-r8a7790" (R-Car H2)
- "renesas,iic-r8a7791" (R-Car M2-W)
- "renesas,iic-r8a7792" (R-Car V2H)
- "renesas,iic-r8a7793" (R-Car M2-N)
- "renesas,iic-r8a7794" (R-Car E2)
- "renesas,iic-sh73a0" (SH-Mobile AG5)
- reg : address start and address range size of device - reg : address start and address range size of device
- interrupts : interrupt of device - interrupts : interrupt of device
- clocks : clock for device - clocks : clock for device
...@@ -10,6 +19,11 @@ Required properties: ...@@ -10,6 +19,11 @@ Required properties:
Optional properties: Optional properties:
- clock-frequency : frequency of bus clock in Hz. Default 100kHz if unset. - clock-frequency : frequency of bus clock in Hz. Default 100kHz if unset.
- dmas : Must contain a list of two references to DMA
specifiers, one for transmission, and one for
reception.
- dma-names : Must contain a list of two DMA names, "tx" and "rx".
Pinctrl properties might be needed, too. See there. Pinctrl properties might be needed, too. See there.
......
...@@ -17,6 +17,9 @@ adi,adt7473 +/-1C TDM Extended Temp Range I.C ...@@ -17,6 +17,9 @@ adi,adt7473 +/-1C TDM Extended Temp Range I.C
adi,adt7475 +/-1C TDM Extended Temp Range I.C adi,adt7475 +/-1C TDM Extended Temp Range I.C
adi,adt7476 +/-1C TDM Extended Temp Range I.C adi,adt7476 +/-1C TDM Extended Temp Range I.C
adi,adt7490 +/-1C TDM Extended Temp Range I.C adi,adt7490 +/-1C TDM Extended Temp Range I.C
adi,adxl345 Three-Axis Digital Accelerometer
adi,adxl346 Three-Axis Digital Accelerometer
adi,adxl34x Three-Axis Digital Accelerometer
at,24c08 i2c serial eeprom (24cxx) at,24c08 i2c serial eeprom (24cxx)
atmel,24c00 i2c serial eeprom (24cxx) atmel,24c00 i2c serial eeprom (24cxx)
atmel,24c01 i2c serial eeprom (24cxx) atmel,24c01 i2c serial eeprom (24cxx)
...@@ -76,7 +79,12 @@ ovti,ov5642 OV5642: Color CMOS QSXGA (5-megapixel) Image Sensor with OmniBSI an ...@@ -76,7 +79,12 @@ ovti,ov5642 OV5642: Color CMOS QSXGA (5-megapixel) Image Sensor with OmniBSI an
pericom,pt7c4338 Real-time Clock Module pericom,pt7c4338 Real-time Clock Module
plx,pex8648 48-Lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch plx,pex8648 48-Lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch
ramtron,24c64 i2c serial eeprom (24cxx) ramtron,24c64 i2c serial eeprom (24cxx)
ricoh,r2025sd I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
ricoh,r2221tl I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
ricoh,rs5c372a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC ricoh,rs5c372a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
ricoh,rs5c372b I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
ricoh,rv5c386 I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
ricoh,rv5c387a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
samsung,24ad0xd1 S524AD0XF1 (128K/256K-bit Serial EEPROM for Low Power) samsung,24ad0xd1 S524AD0XF1 (128K/256K-bit Serial EEPROM for Low Power)
sii,s35390a 2-wire CMOS real-time clock sii,s35390a 2-wire CMOS real-time clock
st-micro,24c256 i2c serial eeprom (24cxx) st-micro,24c256 i2c serial eeprom (24cxx)
......
...@@ -29,6 +29,7 @@ Supported adapters: ...@@ -29,6 +29,7 @@ Supported adapters:
* Intel Wildcat Point-LP (PCH) * Intel Wildcat Point-LP (PCH)
* Intel BayTrail (SOC) * Intel BayTrail (SOC)
* Intel Sunrise Point-H (PCH) * Intel Sunrise Point-H (PCH)
* Intel Sunrise Point-LP (PCH)
Datasheets: Publicly available at the Intel website Datasheets: Publicly available at the Intel website
On Intel Patsburg and later chipsets, both the normal host SMBus controller On Intel Patsburg and later chipsets, both the normal host SMBus controller
......
...@@ -79,11 +79,10 @@ static struct i2c_driver example_driver = { ...@@ -79,11 +79,10 @@ static struct i2c_driver example_driver = {
.driver = { .driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "example", .name = "example",
.pm = &example_pm_ops,
}, },
.attach_adapter = example_attach_adapter, .attach_adapter = example_attach_adapter,
.detach_client = example_detach, .detach_client = example_detach,
.suspend = example_suspend,
.resume = example_resume,
}; };
...@@ -272,10 +271,9 @@ static struct i2c_driver example_driver = { ...@@ -272,10 +271,9 @@ static struct i2c_driver example_driver = {
.driver = { .driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "example", .name = "example",
.pm = &example_pm_ops,
}, },
.id_table = example_idtable, .id_table = example_idtable,
.probe = example_probe, .probe = example_probe,
.remove = example_remove, .remove = example_remove,
.suspend = example_suspend,
.resume = example_resume,
}; };
...@@ -36,6 +36,7 @@ MODULE_DEVICE_TABLE(i2c, foo_idtable); ...@@ -36,6 +36,7 @@ MODULE_DEVICE_TABLE(i2c, foo_idtable);
static struct i2c_driver foo_driver = { static struct i2c_driver foo_driver = {
.driver = { .driver = {
.name = "foo", .name = "foo",
.pm = &foo_pm_ops, /* optional */
}, },
.id_table = foo_idtable, .id_table = foo_idtable,
...@@ -47,8 +48,6 @@ static struct i2c_driver foo_driver = { ...@@ -47,8 +48,6 @@ static struct i2c_driver foo_driver = {
.address_list = normal_i2c, .address_list = normal_i2c,
.shutdown = foo_shutdown, /* optional */ .shutdown = foo_shutdown, /* optional */
.suspend = foo_suspend, /* optional */
.resume = foo_resume, /* optional */
.command = foo_command, /* optional, deprecated */ .command = foo_command, /* optional, deprecated */
} }
...@@ -279,8 +278,9 @@ Power Management ...@@ -279,8 +278,9 @@ Power Management
If your I2C device needs special handling when entering a system low If your I2C device needs special handling when entering a system low
power state -- like putting a transceiver into a low power mode, or power state -- like putting a transceiver into a low power mode, or
activating a system wakeup mechanism -- do that in the suspend() method. activating a system wakeup mechanism -- do that by implementing the
The resume() method should reverse what the suspend() method does. appropriate callbacks for the dev_pm_ops of the driver (like suspend
and resume).
These are standard driver model calls, and they work just like they These are standard driver model calls, and they work just like they
would for any other driver stack. The calls can sleep, and can use would for any other driver stack. The calls can sleep, and can use
......
...@@ -4657,6 +4657,7 @@ W: https://i2c.wiki.kernel.org/ ...@@ -4657,6 +4657,7 @@ W: https://i2c.wiki.kernel.org/
Q: https://patchwork.ozlabs.org/project/linux-i2c/list/ Q: https://patchwork.ozlabs.org/project/linux-i2c/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/i2c/
F: Documentation/i2c/ F: Documentation/i2c/
F: drivers/i2c/ F: drivers/i2c/
F: include/linux/i2c.h F: include/linux/i2c.h
......
...@@ -110,6 +110,16 @@ config I2C_STUB ...@@ -110,6 +110,16 @@ config I2C_STUB
If you don't know what to do here, definitely say N. If you don't know what to do here, definitely say N.
config I2C_SLAVE
bool "I2C slave support"
if I2C_SLAVE
config I2C_SLAVE_EEPROM
tristate "I2C eeprom slave driver"
endif
config I2C_DEBUG_CORE config I2C_DEBUG_CORE
bool "I2C Core debugging messages" bool "I2C Core debugging messages"
help help
......
...@@ -9,6 +9,7 @@ obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o ...@@ -9,6 +9,7 @@ obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
obj-$(CONFIG_I2C_MUX) += i2c-mux.o obj-$(CONFIG_I2C_MUX) += i2c-mux.o
obj-y += algos/ busses/ muxes/ obj-y += algos/ busses/ muxes/
obj-$(CONFIG_I2C_STUB) += i2c-stub.o obj-$(CONFIG_I2C_STUB) += i2c-stub.o
obj-$(CONFIG_I2C_SLAVE_EEPROM) += i2c-slave-eeprom.o
ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG
CFLAGS_i2c-core.o := -Wno-deprecated-declarations CFLAGS_i2c-core.o := -Wno-deprecated-declarations
...@@ -123,6 +123,7 @@ config I2C_I801 ...@@ -123,6 +123,7 @@ config I2C_I801
Wildcat Point-LP (PCH) Wildcat Point-LP (PCH)
BayTrail (SOC) BayTrail (SOC)
Sunrise Point-H (PCH) Sunrise Point-H (PCH)
Sunrise Point-LP (PCH)
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called i2c-i801. will be called i2c-i801.
...@@ -523,6 +524,16 @@ config I2C_IBM_IIC ...@@ -523,6 +524,16 @@ config I2C_IBM_IIC
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called i2c-ibm_iic. will be called i2c-ibm_iic.
config I2C_IMG
tristate "Imagination Technologies I2C SCB Controller"
depends on MIPS || METAG || COMPILE_TEST
help
Say Y here if you want to use the IMG I2C SCB controller,
available on the TZ1090 and other IMG SoCs.
This driver can also be built as a module. If so, the module
will be called i2c-img-scb.
config I2C_IMX config I2C_IMX
tristate "IMX I2C interface" tristate "IMX I2C interface"
depends on ARCH_MXC depends on ARCH_MXC
...@@ -553,6 +564,13 @@ config I2C_KEMPLD ...@@ -553,6 +564,13 @@ config I2C_KEMPLD
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called i2c-kempld. will be called i2c-kempld.
config I2C_MESON
tristate "Amlogic Meson I2C controller"
depends on ARCH_MESON
help
If you say yes to this option, support will be included for the
I2C interface on the Amlogic Meson family of SoCs.
config I2C_MPC config I2C_MPC
tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx" tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx"
depends on PPC depends on PPC
...@@ -702,7 +720,7 @@ config I2C_RIIC ...@@ -702,7 +720,7 @@ config I2C_RIIC
config I2C_RK3X config I2C_RK3X
tristate "Rockchip RK3xxx I2C adapter" tristate "Rockchip RK3xxx I2C adapter"
depends on OF depends on OF && COMMON_CLK
help help
Say Y here to include support for the I2C adapter in Rockchip RK3xxx Say Y here to include support for the I2C adapter in Rockchip RK3xxx
SoCs. SoCs.
......
...@@ -50,9 +50,11 @@ obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o ...@@ -50,9 +50,11 @@ obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o
obj-$(CONFIG_I2C_HIX5HD2) += i2c-hix5hd2.o obj-$(CONFIG_I2C_HIX5HD2) += i2c-hix5hd2.o
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
obj-$(CONFIG_I2C_IMG) += i2c-img-scb.o
obj-$(CONFIG_I2C_IMX) += i2c-imx.o obj-$(CONFIG_I2C_IMX) += i2c-imx.o
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o
obj-$(CONFIG_I2C_MESON) += i2c-meson.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
obj-$(CONFIG_I2C_MXS) += i2c-mxs.o obj-$(CONFIG_I2C_MXS) += i2c-mxs.o
......
...@@ -31,10 +31,13 @@ ...@@ -31,10 +31,13 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/platform_data/dma-atmel.h> #include <linux/platform_data/dma-atmel.h>
#include <linux/pm_runtime.h>
#include <linux/pinctrl/consumer.h>
#define DEFAULT_TWI_CLK_HZ 100000 /* max 400 Kbits/s */ #define DEFAULT_TWI_CLK_HZ 100000 /* max 400 Kbits/s */
#define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */ #define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */
#define AT91_I2C_DMA_THRESHOLD 8 /* enable DMA if transfer size is bigger than this threshold */ #define AT91_I2C_DMA_THRESHOLD 8 /* enable DMA if transfer size is bigger than this threshold */
#define AUTOSUSPEND_TIMEOUT 2000
/* AT91 TWI register definitions */ /* AT91 TWI register definitions */
#define AT91_TWI_CR 0x0000 /* Control Register */ #define AT91_TWI_CR 0x0000 /* Control Register */
...@@ -72,7 +75,6 @@ struct at91_twi_pdata { ...@@ -72,7 +75,6 @@ struct at91_twi_pdata {
unsigned clk_max_div; unsigned clk_max_div;
unsigned clk_offset; unsigned clk_offset;
bool has_unre_flag; bool has_unre_flag;
bool has_dma_support;
struct at_dma_slave dma_slave; struct at_dma_slave dma_slave;
}; };
...@@ -481,6 +483,10 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) ...@@ -481,6 +483,10 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num); dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);
ret = pm_runtime_get_sync(dev->dev);
if (ret < 0)
goto out;
/* /*
* The hardware can handle at most two messages concatenated by a * The hardware can handle at most two messages concatenated by a
* repeated start via it's internal address feature. * repeated start via it's internal address feature.
...@@ -488,18 +494,21 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) ...@@ -488,18 +494,21 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
if (num > 2) { if (num > 2) {
dev_err(dev->dev, dev_err(dev->dev,
"cannot handle more than two concatenated messages.\n"); "cannot handle more than two concatenated messages.\n");
return 0; ret = 0;
goto out;
} else if (num == 2) { } else if (num == 2) {
int internal_address = 0; int internal_address = 0;
int i; int i;
if (msg->flags & I2C_M_RD) { if (msg->flags & I2C_M_RD) {
dev_err(dev->dev, "first transfer must be write.\n"); dev_err(dev->dev, "first transfer must be write.\n");
return -EINVAL; ret = -EINVAL;
goto out;
} }
if (msg->len > 3) { if (msg->len > 3) {
dev_err(dev->dev, "first message size must be <= 3.\n"); dev_err(dev->dev, "first message size must be <= 3.\n");
return -EINVAL; ret = -EINVAL;
goto out;
} }
/* 1st msg is put into the internal address, start with 2nd */ /* 1st msg is put into the internal address, start with 2nd */
...@@ -523,7 +532,12 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) ...@@ -523,7 +532,12 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
ret = at91_do_twi_transfer(dev); ret = at91_do_twi_transfer(dev);
return (ret < 0) ? ret : num; ret = (ret < 0) ? ret : num;
out:
pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
return ret;
} }
static u32 at91_twi_func(struct i2c_adapter *adapter) static u32 at91_twi_func(struct i2c_adapter *adapter)
...@@ -541,35 +555,30 @@ static struct at91_twi_pdata at91rm9200_config = { ...@@ -541,35 +555,30 @@ static struct at91_twi_pdata at91rm9200_config = {
.clk_max_div = 5, .clk_max_div = 5,
.clk_offset = 3, .clk_offset = 3,
.has_unre_flag = true, .has_unre_flag = true,
.has_dma_support = false,
}; };
static struct at91_twi_pdata at91sam9261_config = { static struct at91_twi_pdata at91sam9261_config = {
.clk_max_div = 5, .clk_max_div = 5,
.clk_offset = 4, .clk_offset = 4,
.has_unre_flag = false, .has_unre_flag = false,
.has_dma_support = false,
}; };
static struct at91_twi_pdata at91sam9260_config = { static struct at91_twi_pdata at91sam9260_config = {
.clk_max_div = 7, .clk_max_div = 7,
.clk_offset = 4, .clk_offset = 4,
.has_unre_flag = false, .has_unre_flag = false,
.has_dma_support = false,
}; };
static struct at91_twi_pdata at91sam9g20_config = { static struct at91_twi_pdata at91sam9g20_config = {
.clk_max_div = 7, .clk_max_div = 7,
.clk_offset = 4, .clk_offset = 4,
.has_unre_flag = false, .has_unre_flag = false,
.has_dma_support = false,
}; };
static struct at91_twi_pdata at91sam9g10_config = { static struct at91_twi_pdata at91sam9g10_config = {
.clk_max_div = 7, .clk_max_div = 7,
.clk_offset = 4, .clk_offset = 4,
.has_unre_flag = false, .has_unre_flag = false,
.has_dma_support = false,
}; };
static const struct platform_device_id at91_twi_devtypes[] = { static const struct platform_device_id at91_twi_devtypes[] = {
...@@ -598,7 +607,6 @@ static struct at91_twi_pdata at91sam9x5_config = { ...@@ -598,7 +607,6 @@ static struct at91_twi_pdata at91sam9x5_config = {
.clk_max_div = 7, .clk_max_div = 7,
.clk_offset = 4, .clk_offset = 4,
.has_unre_flag = false, .has_unre_flag = false,
.has_dma_support = true,
}; };
static const struct of_device_id atmel_twi_dt_ids[] = { static const struct of_device_id atmel_twi_dt_ids[] = {
...@@ -627,30 +635,11 @@ static const struct of_device_id atmel_twi_dt_ids[] = { ...@@ -627,30 +635,11 @@ static const struct of_device_id atmel_twi_dt_ids[] = {
MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids); MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids);
#endif #endif
static bool filter(struct dma_chan *chan, void *pdata)
{
struct at91_twi_pdata *sl_pdata = pdata;
struct at_dma_slave *sl;
if (!sl_pdata)
return false;
sl = &sl_pdata->dma_slave;
if (sl && (sl->dma_dev == chan->device->dev)) {
chan->private = sl;
return true;
} else {
return false;
}
}
static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr) static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr)
{ {
int ret = 0; int ret = 0;
struct at91_twi_pdata *pdata = dev->pdata;
struct dma_slave_config slave_config; struct dma_slave_config slave_config;
struct at91_twi_dma *dma = &dev->dma; struct at91_twi_dma *dma = &dev->dma;
dma_cap_mask_t mask;
memset(&slave_config, 0, sizeof(slave_config)); memset(&slave_config, 0, sizeof(slave_config));
slave_config.src_addr = (dma_addr_t)phy_addr + AT91_TWI_RHR; slave_config.src_addr = (dma_addr_t)phy_addr + AT91_TWI_RHR;
...@@ -661,22 +650,17 @@ static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr) ...@@ -661,22 +650,17 @@ static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr)
slave_config.dst_maxburst = 1; slave_config.dst_maxburst = 1;
slave_config.device_fc = false; slave_config.device_fc = false;
dma_cap_zero(mask); dma->chan_tx = dma_request_slave_channel_reason(dev->dev, "tx");
dma_cap_set(DMA_SLAVE, mask); if (IS_ERR(dma->chan_tx)) {
ret = PTR_ERR(dma->chan_tx);
dma->chan_tx = dma_request_slave_channel_compat(mask, filter, pdata, dma->chan_tx = NULL;
dev->dev, "tx");
if (!dma->chan_tx) {
dev_err(dev->dev, "can't get a DMA channel for tx\n");
ret = -EBUSY;
goto error; goto error;
} }
dma->chan_rx = dma_request_slave_channel_compat(mask, filter, pdata, dma->chan_rx = dma_request_slave_channel_reason(dev->dev, "rx");
dev->dev, "rx"); if (IS_ERR(dma->chan_rx)) {
if (!dma->chan_rx) { ret = PTR_ERR(dma->chan_rx);
dev_err(dev->dev, "can't get a DMA channel for rx\n"); dma->chan_rx = NULL;
ret = -EBUSY;
goto error; goto error;
} }
...@@ -697,6 +681,7 @@ static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr) ...@@ -697,6 +681,7 @@ static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr)
sg_init_table(&dma->sg, 1); sg_init_table(&dma->sg, 1);
dma->buf_mapped = false; dma->buf_mapped = false;
dma->xfer_in_progress = false; dma->xfer_in_progress = false;
dev->use_dma = true;
dev_info(dev->dev, "using %s (tx) and %s (rx) for DMA transfers\n", dev_info(dev->dev, "using %s (tx) and %s (rx) for DMA transfers\n",
dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx)); dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx));
...@@ -704,7 +689,8 @@ static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr) ...@@ -704,7 +689,8 @@ static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr)
return ret; return ret;
error: error:
dev_info(dev->dev, "can't use DMA\n"); if (ret != -EPROBE_DEFER)
dev_info(dev->dev, "can't use DMA, error %d\n", ret);
if (dma->chan_rx) if (dma->chan_rx)
dma_release_channel(dma->chan_rx); dma_release_channel(dma->chan_rx);
if (dma->chan_tx) if (dma->chan_tx)
...@@ -772,9 +758,10 @@ static int at91_twi_probe(struct platform_device *pdev) ...@@ -772,9 +758,10 @@ static int at91_twi_probe(struct platform_device *pdev)
} }
clk_prepare_enable(dev->clk); clk_prepare_enable(dev->clk);
if (dev->pdata->has_dma_support) { if (dev->dev->of_node) {
if (at91_twi_configure_dma(dev, phy_addr) == 0) rc = at91_twi_configure_dma(dev, phy_addr);
dev->use_dma = true; if (rc == -EPROBE_DEFER)
return rc;
} }
rc = of_property_read_u32(dev->dev->of_node, "clock-frequency", rc = of_property_read_u32(dev->dev->of_node, "clock-frequency",
...@@ -795,11 +782,20 @@ static int at91_twi_probe(struct platform_device *pdev) ...@@ -795,11 +782,20 @@ static int at91_twi_probe(struct platform_device *pdev)
dev->adapter.timeout = AT91_I2C_TIMEOUT; dev->adapter.timeout = AT91_I2C_TIMEOUT;
dev->adapter.dev.of_node = pdev->dev.of_node; dev->adapter.dev.of_node = pdev->dev.of_node;
pm_runtime_set_autosuspend_delay(dev->dev, AUTOSUSPEND_TIMEOUT);
pm_runtime_use_autosuspend(dev->dev);
pm_runtime_set_active(dev->dev);
pm_runtime_enable(dev->dev);
rc = i2c_add_numbered_adapter(&dev->adapter); rc = i2c_add_numbered_adapter(&dev->adapter);
if (rc) { if (rc) {
dev_err(dev->dev, "Adapter %s registration failed\n", dev_err(dev->dev, "Adapter %s registration failed\n",
dev->adapter.name); dev->adapter.name);
clk_disable_unprepare(dev->clk); clk_disable_unprepare(dev->clk);
pm_runtime_disable(dev->dev);
pm_runtime_set_suspended(dev->dev);
return rc; return rc;
} }
...@@ -814,6 +810,9 @@ static int at91_twi_remove(struct platform_device *pdev) ...@@ -814,6 +810,9 @@ static int at91_twi_remove(struct platform_device *pdev)
i2c_del_adapter(&dev->adapter); i2c_del_adapter(&dev->adapter);
clk_disable_unprepare(dev->clk); clk_disable_unprepare(dev->clk);
pm_runtime_disable(dev->dev);
pm_runtime_set_suspended(dev->dev);
return 0; return 0;
} }
...@@ -823,7 +822,9 @@ static int at91_twi_runtime_suspend(struct device *dev) ...@@ -823,7 +822,9 @@ static int at91_twi_runtime_suspend(struct device *dev)
{ {
struct at91_twi_dev *twi_dev = dev_get_drvdata(dev); struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
clk_disable(twi_dev->clk); clk_disable_unprepare(twi_dev->clk);
pinctrl_pm_select_sleep_state(dev);
return 0; return 0;
} }
...@@ -832,10 +833,38 @@ static int at91_twi_runtime_resume(struct device *dev) ...@@ -832,10 +833,38 @@ static int at91_twi_runtime_resume(struct device *dev)
{ {
struct at91_twi_dev *twi_dev = dev_get_drvdata(dev); struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
return clk_enable(twi_dev->clk); pinctrl_pm_select_default_state(dev);
return clk_prepare_enable(twi_dev->clk);
}
static int at91_twi_suspend_noirq(struct device *dev)
{
if (!pm_runtime_status_suspended(dev))
at91_twi_runtime_suspend(dev);
return 0;
}
static int at91_twi_resume_noirq(struct device *dev)
{
int ret;
if (!pm_runtime_status_suspended(dev)) {
ret = at91_twi_runtime_resume(dev);
if (ret)
return ret;
}
pm_runtime_mark_last_busy(dev);
pm_request_autosuspend(dev);
return 0;
} }
static const struct dev_pm_ops at91_twi_pm = { static const struct dev_pm_ops at91_twi_pm = {
.suspend_noirq = at91_twi_suspend_noirq,
.resume_noirq = at91_twi_resume_noirq,
.runtime_suspend = at91_twi_runtime_suspend, .runtime_suspend = at91_twi_runtime_suspend,
.runtime_resume = at91_twi_runtime_resume, .runtime_resume = at91_twi_runtime_resume,
}; };
......
...@@ -368,8 +368,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) ...@@ -368,8 +368,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
flag |= DAVINCI_I2C_MDR_STP; flag |= DAVINCI_I2C_MDR_STP;
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag); davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
r = wait_for_completion_interruptible_timeout(&dev->cmd_complete, r = wait_for_completion_timeout(&dev->cmd_complete, dev->adapter.timeout);
dev->adapter.timeout);
if (r == 0) { if (r == 0) {
dev_err(dev->dev, "controller timed out\n"); dev_err(dev->dev, "controller timed out\n");
davinci_i2c_recover_bus(dev); davinci_i2c_recover_bus(dev);
...@@ -380,7 +379,6 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) ...@@ -380,7 +379,6 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
if (dev->buf_len) { if (dev->buf_len) {
/* This should be 0 if all bytes were transferred /* This should be 0 if all bytes were transferred
* or dev->cmd_err denotes an error. * or dev->cmd_err denotes an error.
* A signal may have aborted the transfer.
*/ */
if (r >= 0) { if (r >= 0) {
dev_err(dev->dev, "abnormal termination buf_len=%i\n", dev_err(dev->dev, "abnormal termination buf_len=%i\n",
...@@ -634,13 +632,17 @@ static int davinci_i2c_probe(struct platform_device *pdev) ...@@ -634,13 +632,17 @@ static int davinci_i2c_probe(struct platform_device *pdev)
{ {
struct davinci_i2c_dev *dev; struct davinci_i2c_dev *dev;
struct i2c_adapter *adap; struct i2c_adapter *adap;
struct resource *mem, *irq; struct resource *mem;
int r; int r, irq;
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); irq = platform_get_irq(pdev, 0);
if (!irq) { if (irq <= 0) {
dev_err(&pdev->dev, "no irq resource?\n"); if (!irq)
return -ENODEV; irq = -ENXIO;
if (irq != -EPROBE_DEFER)
dev_err(&pdev->dev,
"can't get irq resource ret=%d\n", irq);
return irq;
} }
dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_i2c_dev), dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_i2c_dev),
...@@ -655,7 +657,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) ...@@ -655,7 +657,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
init_completion(&dev->xfr_complete); init_completion(&dev->xfr_complete);
#endif #endif
dev->dev = &pdev->dev; dev->dev = &pdev->dev;
dev->irq = irq->start; dev->irq = irq;
dev->pdata = dev_get_platdata(&pdev->dev); dev->pdata = dev_get_platdata(&pdev->dev);
platform_set_drvdata(pdev, dev); platform_set_drvdata(pdev, dev);
......
...@@ -457,7 +457,7 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) ...@@ -457,7 +457,7 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id)
goto stop; goto stop;
} else if (int_status & HSI2C_INT_TIMEOUT) { } else if (int_status & HSI2C_INT_TIMEOUT) {
dev_dbg(i2c->dev, "Accessing device timed out\n"); dev_dbg(i2c->dev, "Accessing device timed out\n");
i2c->state = -EAGAIN; i2c->state = -ETIMEDOUT;
goto stop; goto stop;
} }
} else if (int_status & HSI2C_INT_I2C) { } else if (int_status & HSI2C_INT_I2C) {
...@@ -476,7 +476,7 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) ...@@ -476,7 +476,7 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id)
goto stop; goto stop;
} else if (trans_status & HSI2C_TIMEOUT_AUTO) { } else if (trans_status & HSI2C_TIMEOUT_AUTO) {
dev_dbg(i2c->dev, "Accessing device timed out\n"); dev_dbg(i2c->dev, "Accessing device timed out\n");
i2c->state = -EAGAIN; i2c->state = -ETIMEDOUT;
goto stop; goto stop;
} else if (trans_status & HSI2C_TRANS_DONE) { } else if (trans_status & HSI2C_TRANS_DONE) {
i2c->trans_done = 1; i2c->trans_done = 1;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
<mdsxyz123@yahoo.com> <mdsxyz123@yahoo.com>
Copyright (C) 2007 - 2012 Jean Delvare <jdelvare@suse.de> Copyright (C) 2007 - 2014 Jean Delvare <jdelvare@suse.de>
Copyright (C) 2010 Intel Corporation, Copyright (C) 2010 Intel Corporation,
David Woodhouse <dwmw2@infradead.org> David Woodhouse <dwmw2@infradead.org>
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
* Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes * Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes
* BayTrail (SOC) 0x0f12 32 hard yes yes yes * BayTrail (SOC) 0x0f12 32 hard yes yes yes
* Sunrise Point-H (PCH) 0xa123 32 hard yes yes yes * Sunrise Point-H (PCH) 0xa123 32 hard yes yes yes
* Sunrise Point-LP (PCH) 0x9d23 32 hard yes yes yes
* *
* Features supported by this driver: * Features supported by this driver:
* Software PEC no * Software PEC no
...@@ -109,12 +110,16 @@ ...@@ -109,12 +110,16 @@
/* PCI Address Constants */ /* PCI Address Constants */
#define SMBBAR 4 #define SMBBAR 4
#define SMBPCICTL 0x004
#define SMBPCISTS 0x006 #define SMBPCISTS 0x006
#define SMBHSTCFG 0x040 #define SMBHSTCFG 0x040
/* Host status bits for SMBPCISTS */ /* Host status bits for SMBPCISTS */
#define SMBPCISTS_INTS 0x08 #define SMBPCISTS_INTS 0x08
/* Control bits for SMBPCICTL */
#define SMBPCICTL_INTDIS 0x0400
/* Host configuration bits for SMBHSTCFG */ /* Host configuration bits for SMBHSTCFG */
#define SMBHSTCFG_HST_EN 1 #define SMBHSTCFG_HST_EN 1
#define SMBHSTCFG_SMB_SMI_EN 2 #define SMBHSTCFG_SMB_SMI_EN 2
...@@ -182,6 +187,7 @@ ...@@ -182,6 +187,7 @@
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS 0x9ca2 #define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS 0x9ca2
#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS 0xa123 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS 0xa123
#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS 0x9d23
struct i801_mux_config { struct i801_mux_config {
char *gpio_chip; char *gpio_chip;
...@@ -371,6 +377,7 @@ static int i801_transaction(struct i801_priv *priv, int xact) ...@@ -371,6 +377,7 @@ static int i801_transaction(struct i801_priv *priv, int xact)
{ {
int status; int status;
int result; int result;
const struct i2c_adapter *adap = &priv->adapter;
result = i801_check_pre(priv); result = i801_check_pre(priv);
if (result < 0) if (result < 0)
...@@ -379,7 +386,14 @@ static int i801_transaction(struct i801_priv *priv, int xact) ...@@ -379,7 +386,14 @@ static int i801_transaction(struct i801_priv *priv, int xact)
if (priv->features & FEATURE_IRQ) { if (priv->features & FEATURE_IRQ) {
outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START, outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START,
SMBHSTCNT(priv)); SMBHSTCNT(priv));
wait_event(priv->waitq, (status = priv->status)); result = wait_event_timeout(priv->waitq,
(status = priv->status),
adap->timeout);
if (!result) {
status = -ETIMEDOUT;
dev_warn(&priv->pci_dev->dev,
"Timeout waiting for interrupt!\n");
}
priv->status = 0; priv->status = 0;
return i801_check_post(priv, status); return i801_check_post(priv, status);
} }
...@@ -493,9 +507,6 @@ static irqreturn_t i801_isr(int irq, void *dev_id) ...@@ -493,9 +507,6 @@ static irqreturn_t i801_isr(int irq, void *dev_id)
return IRQ_NONE; return IRQ_NONE;
status = inb_p(SMBHSTSTS(priv)); status = inb_p(SMBHSTSTS(priv));
if (status != 0x42)
dev_dbg(&priv->pci_dev->dev, "irq: status = %02x\n", status);
if (status & SMBHSTSTS_BYTE_DONE) if (status & SMBHSTSTS_BYTE_DONE)
i801_isr_byte_done(priv); i801_isr_byte_done(priv);
...@@ -527,6 +538,7 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, ...@@ -527,6 +538,7 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
int smbcmd; int smbcmd;
int status; int status;
int result; int result;
const struct i2c_adapter *adap = &priv->adapter;
result = i801_check_pre(priv); result = i801_check_pre(priv);
if (result < 0) if (result < 0)
...@@ -555,7 +567,14 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, ...@@ -555,7 +567,14 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
priv->data = &data->block[1]; priv->data = &data->block[1];
outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv)); outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv));
wait_event(priv->waitq, (status = priv->status)); result = wait_event_timeout(priv->waitq,
(status = priv->status),
adap->timeout);
if (!result) {
status = -ETIMEDOUT;
dev_warn(&priv->pci_dev->dev,
"Timeout waiting for interrupt!\n");
}
priv->status = 0; priv->status = 0;
return i801_check_post(priv, status); return i801_check_post(priv, status);
} }
...@@ -829,6 +848,7 @@ static const struct pci_device_id i801_ids[] = { ...@@ -829,6 +848,7 @@ static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS) },
{ 0, } { 0, }
}; };
...@@ -1212,6 +1232,25 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -1212,6 +1232,25 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
outb_p(inb_p(SMBAUXCTL(priv)) & outb_p(inb_p(SMBAUXCTL(priv)) &
~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
/* Default timeout in interrupt mode: 200 ms */
priv->adapter.timeout = HZ / 5;
if (priv->features & FEATURE_IRQ) {
u16 pcictl, pcists;
/* Complain if an interrupt is already pending */
pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists);
if (pcists & SMBPCISTS_INTS)
dev_warn(&dev->dev, "An interrupt is pending!\n");
/* Check if interrupts have been disabled */
pci_read_config_word(priv->pci_dev, SMBPCICTL, &pcictl);
if (pcictl & SMBPCICTL_INTDIS) {
dev_info(&dev->dev, "Interrupts are disabled\n");
priv->features &= ~FEATURE_IRQ;
}
}
if (priv->features & FEATURE_IRQ) { if (priv->features & FEATURE_IRQ) {
init_waitqueue_head(&priv->waitq); init_waitqueue_head(&priv->waitq);
...@@ -1220,10 +1259,11 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -1220,10 +1259,11 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (err) { if (err) {
dev_err(&dev->dev, "Failed to allocate irq %d: %d\n", dev_err(&dev->dev, "Failed to allocate irq %d: %d\n",
dev->irq, err); dev->irq, err);
goto exit_release; priv->features &= ~FEATURE_IRQ;
} }
dev_info(&dev->dev, "SMBus using PCI Interrupt\n");
} }
dev_info(&dev->dev, "SMBus using %s\n",
priv->features & FEATURE_IRQ ? "PCI interrupt" : "polling");
/* set up the sysfs linkage to our parent device */ /* set up the sysfs linkage to our parent device */
priv->adapter.dev.parent = &dev->dev; priv->adapter.dev.parent = &dev->dev;
...@@ -1250,7 +1290,6 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -1250,7 +1290,6 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
exit_free_irq: exit_free_irq:
if (priv->features & FEATURE_IRQ) if (priv->features & FEATURE_IRQ)
free_irq(dev->irq, priv); free_irq(dev->irq, priv);
exit_release:
pci_release_region(dev, SMBBAR); pci_release_region(dev, SMBBAR);
exit: exit:
kfree(priv); kfree(priv);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -124,7 +124,7 @@ static void mpc_i2c_fixup(struct mpc_i2c *i2c) ...@@ -124,7 +124,7 @@ static void mpc_i2c_fixup(struct mpc_i2c *i2c)
static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing) static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
{ {
unsigned long orig_jiffies = jiffies; unsigned long orig_jiffies = jiffies;
u32 x; u32 cmd_err;
int result = 0; int result = 0;
if (!i2c->irq) { if (!i2c->irq) {
...@@ -133,11 +133,11 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing) ...@@ -133,11 +133,11 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
if (time_after(jiffies, orig_jiffies + timeout)) { if (time_after(jiffies, orig_jiffies + timeout)) {
dev_dbg(i2c->dev, "timeout\n"); dev_dbg(i2c->dev, "timeout\n");
writeccr(i2c, 0); writeccr(i2c, 0);
result = -EIO; result = -ETIMEDOUT;
break; break;
} }
} }
x = readb(i2c->base + MPC_I2C_SR); cmd_err = readb(i2c->base + MPC_I2C_SR);
writeb(0, i2c->base + MPC_I2C_SR); writeb(0, i2c->base + MPC_I2C_SR);
} else { } else {
/* Interrupt mode */ /* Interrupt mode */
...@@ -150,28 +150,28 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing) ...@@ -150,28 +150,28 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
result = -ETIMEDOUT; result = -ETIMEDOUT;
} }
x = i2c->interrupt; cmd_err = i2c->interrupt;
i2c->interrupt = 0; i2c->interrupt = 0;
} }
if (result < 0) if (result < 0)
return result; return result;
if (!(x & CSR_MCF)) { if (!(cmd_err & CSR_MCF)) {
dev_dbg(i2c->dev, "unfinished\n"); dev_dbg(i2c->dev, "unfinished\n");
return -EIO; return -EIO;
} }
if (x & CSR_MAL) { if (cmd_err & CSR_MAL) {
dev_dbg(i2c->dev, "MAL\n"); dev_dbg(i2c->dev, "MAL\n");
return -EIO; return -EAGAIN;
} }
if (writing && (x & CSR_RXAK)) { if (writing && (cmd_err & CSR_RXAK)) {
dev_dbg(i2c->dev, "No RXAK\n"); dev_dbg(i2c->dev, "No RXAK\n");
/* generate stop */ /* generate stop */
writeccr(i2c, CCR_MEN); writeccr(i2c, CCR_MEN);
return -EIO; return -ENXIO;
} }
return 0; return 0;
} }
......
...@@ -811,7 +811,7 @@ static int mxs_i2c_probe(struct platform_device *pdev) ...@@ -811,7 +811,7 @@ static int mxs_i2c_probe(struct platform_device *pdev)
struct resource *res; struct resource *res;
int err, irq; int err, irq;
i2c = devm_kzalloc(dev, sizeof(struct mxs_i2c_dev), GFP_KERNEL); i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c) if (!i2c)
return -ENOMEM; return -ENOMEM;
......
...@@ -54,6 +54,9 @@ ...@@ -54,6 +54,9 @@
/* timeout for pm runtime autosuspend */ /* timeout for pm runtime autosuspend */
#define OMAP_I2C_PM_TIMEOUT 1000 /* ms */ #define OMAP_I2C_PM_TIMEOUT 1000 /* ms */
/* timeout for making decision on bus free status */
#define OMAP_I2C_BUS_FREE_TIMEOUT (msecs_to_jiffies(10))
/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */ /* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */
enum { enum {
OMAP_I2C_REV_REG = 0, OMAP_I2C_REV_REG = 0,
...@@ -98,7 +101,7 @@ enum { ...@@ -98,7 +101,7 @@ enum {
#define OMAP_I2C_STAT_ROVR (1 << 11) /* Receive overrun */ #define OMAP_I2C_STAT_ROVR (1 << 11) /* Receive overrun */
#define OMAP_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */ #define OMAP_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
#define OMAP_I2C_STAT_AAS (1 << 9) /* Address as slave */ #define OMAP_I2C_STAT_AAS (1 << 9) /* Address as slave */
#define OMAP_I2C_STAT_AD0 (1 << 8) /* Address zero */ #define OMAP_I2C_STAT_BF (1 << 8) /* Bus Free */
#define OMAP_I2C_STAT_XRDY (1 << 4) /* Transmit data ready */ #define OMAP_I2C_STAT_XRDY (1 << 4) /* Transmit data ready */
#define OMAP_I2C_STAT_RRDY (1 << 3) /* Receive data ready */ #define OMAP_I2C_STAT_RRDY (1 << 3) /* Receive data ready */
#define OMAP_I2C_STAT_ARDY (1 << 2) /* Register access ready */ #define OMAP_I2C_STAT_ARDY (1 << 2) /* Register access ready */
...@@ -146,16 +149,20 @@ enum { ...@@ -146,16 +149,20 @@ enum {
#define OMAP_I2C_SCLH_HSSCLH 8 #define OMAP_I2C_SCLH_HSSCLH 8
/* I2C System Test Register (OMAP_I2C_SYSTEST): */ /* I2C System Test Register (OMAP_I2C_SYSTEST): */
#ifdef DEBUG
#define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */ #define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */
#define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode */ #define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode */
#define OMAP_I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */ #define OMAP_I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */
#define OMAP_I2C_SYSTEST_TMODE_SHIFT (12) /* Test mode select */ #define OMAP_I2C_SYSTEST_TMODE_SHIFT (12) /* Test mode select */
/* Functional mode */
#define OMAP_I2C_SYSTEST_SCL_I_FUNC (1 << 8) /* SCL line input value */
#define OMAP_I2C_SYSTEST_SCL_O_FUNC (1 << 7) /* SCL line output value */
#define OMAP_I2C_SYSTEST_SDA_I_FUNC (1 << 6) /* SDA line input value */
#define OMAP_I2C_SYSTEST_SDA_O_FUNC (1 << 5) /* SDA line output value */
/* SDA/SCL IO mode */
#define OMAP_I2C_SYSTEST_SCL_I (1 << 3) /* SCL line sense in */ #define OMAP_I2C_SYSTEST_SCL_I (1 << 3) /* SCL line sense in */
#define OMAP_I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive out */ #define OMAP_I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive out */
#define OMAP_I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense in */ #define OMAP_I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense in */
#define OMAP_I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive out */ #define OMAP_I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive out */
#endif
/* OCP_SYSSTATUS bit definitions */ /* OCP_SYSSTATUS bit definitions */
#define SYSS_RESETDONE_MASK (1 << 0) #define SYSS_RESETDONE_MASK (1 << 0)
...@@ -202,6 +209,9 @@ struct omap_i2c_dev { ...@@ -202,6 +209,9 @@ struct omap_i2c_dev {
*/ */
u32 rev; u32 rev;
unsigned b_hw:1; /* bad h/w fixes */ unsigned b_hw:1; /* bad h/w fixes */
unsigned bb_valid:1; /* true when BB-bit reflects
* the I2C bus state
*/
unsigned receiver:1; /* true when we're in receiver mode */ unsigned receiver:1; /* true when we're in receiver mode */
u16 iestate; /* Saved interrupt register */ u16 iestate; /* Saved interrupt register */
u16 pscstate; u16 pscstate;
...@@ -289,6 +299,12 @@ static void __omap_i2c_init(struct omap_i2c_dev *dev) ...@@ -289,6 +299,12 @@ static void __omap_i2c_init(struct omap_i2c_dev *dev)
/* Take the I2C module out of reset: */ /* Take the I2C module out of reset: */
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
/*
* NOTE: right after setting CON_EN, STAT_BB could be 0 while the
* bus is busy. It will be changed to 1 on the next IP FCLK clock.
* udelay(1) will be enough to fix that.
*/
/* /*
* Don't write to this register if the IE state is 0 as it can * Don't write to this register if the IE state is 0 as it can
* cause deadlock. * cause deadlock.
...@@ -328,7 +344,12 @@ static int omap_i2c_reset(struct omap_i2c_dev *dev) ...@@ -328,7 +344,12 @@ static int omap_i2c_reset(struct omap_i2c_dev *dev)
/* SYSC register is cleared by the reset; rewrite it */ /* SYSC register is cleared by the reset; rewrite it */
omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, sysc); omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, sysc);
if (dev->rev > OMAP_I2C_REV_ON_3430_3530) {
/* Schedule I2C-bus monitoring on the next transfer */
dev->bb_valid = 0;
}
} }
return 0; return 0;
} }
...@@ -441,6 +462,11 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) ...@@ -441,6 +462,11 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
dev->scllstate = scll; dev->scllstate = scll;
dev->sclhstate = sclh; dev->sclhstate = sclh;
if (dev->rev <= OMAP_I2C_REV_ON_3430_3530) {
/* Not implemented */
dev->bb_valid = 1;
}
__omap_i2c_init(dev); __omap_i2c_init(dev);
return 0; return 0;
...@@ -465,6 +491,91 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev) ...@@ -465,6 +491,91 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
return 0; return 0;
} }
/*
* Wait while BB-bit doesn't reflect the I2C bus state
*
* In a multimaster environment, after IP software reset, BB-bit value doesn't
* correspond to the current bus state. It may happen what BB-bit will be 0,
* while the bus is busy due to another I2C master activity.
* Here are BB-bit values after reset:
* SDA SCL BB NOTES
* 0 0 0 1, 2
* 1 0 0 1, 2
* 0 1 1
* 1 1 0 3
* Later, if IP detect SDA=0 and SCL=1 (ACK) or SDA 1->0 while SCL=1 (START)
* combinations on the bus, it set BB-bit to 1.
* If IP detect SDA 0->1 while SCL=1 (STOP) combination on the bus,
* it set BB-bit to 0 and BF to 1.
* BB and BF bits correctly tracks the bus state while IP is suspended
* BB bit became valid on the next FCLK clock after CON_EN bit set
*
* NOTES:
* 1. Any transfer started when BB=0 and bus is busy wouldn't be
* completed by IP and results in controller timeout.
* 2. Any transfer started when BB=0 and SCL=0 results in IP
* starting to drive SDA low. In that case IP corrupt data
* on the bus.
* 3. Any transfer started in the middle of another master's transfer
* results in unpredictable results and data corruption
*/
static int omap_i2c_wait_for_bb_valid(struct omap_i2c_dev *dev)
{
unsigned long bus_free_timeout = 0;
unsigned long timeout;
int bus_free = 0;
u16 stat, systest;
if (dev->bb_valid)
return 0;
timeout = jiffies + OMAP_I2C_TIMEOUT;
while (1) {
stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
/*
* We will see BB or BF event in a case IP had detected any
* activity on the I2C bus. Now IP correctly tracks the bus
* state. BB-bit value is valid.
*/
if (stat & (OMAP_I2C_STAT_BB | OMAP_I2C_STAT_BF))
break;
/*
* Otherwise, we must look signals on the bus to make
* the right decision.
*/
systest = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
if ((systest & OMAP_I2C_SYSTEST_SCL_I_FUNC) &&
(systest & OMAP_I2C_SYSTEST_SDA_I_FUNC)) {
if (!bus_free) {
bus_free_timeout = jiffies +
OMAP_I2C_BUS_FREE_TIMEOUT;
bus_free = 1;
}
/*
* SDA and SCL lines was high for 10 ms without bus
* activity detected. The bus is free. Consider
* BB-bit value is valid.
*/
if (time_after(jiffies, bus_free_timeout))
break;
} else {
bus_free = 0;
}
if (time_after(jiffies, timeout)) {
dev_warn(dev->dev, "timeout waiting for bus ready\n");
return -ETIMEDOUT;
}
msleep(1);
}
dev->bb_valid = 1;
return 0;
}
static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx)
{ {
u16 buf; u16 buf;
...@@ -557,7 +668,11 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, ...@@ -557,7 +668,11 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
if (!dev->b_hw && stop) if (!dev->b_hw && stop)
w |= OMAP_I2C_CON_STP; w |= OMAP_I2C_CON_STP;
/*
* NOTE: STAT_BB bit could became 1 here if another master occupy
* the bus. IP successfully complete transfer when the bus will be
* free again (BB reset to 0).
*/
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w); omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
/* /*
...@@ -600,13 +715,15 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, ...@@ -600,13 +715,15 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
return 0; return 0;
/* We have an error */ /* We have an error */
if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR | if (dev->cmd_err & (OMAP_I2C_STAT_ROVR | OMAP_I2C_STAT_XUDF)) {
OMAP_I2C_STAT_XUDF)) {
omap_i2c_reset(dev); omap_i2c_reset(dev);
__omap_i2c_init(dev); __omap_i2c_init(dev);
return -EIO; return -EIO;
} }
if (dev->cmd_err & OMAP_I2C_STAT_AL)
return -EAGAIN;
if (dev->cmd_err & OMAP_I2C_STAT_NACK) { if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
if (msg->flags & I2C_M_IGNORE_NAK) if (msg->flags & I2C_M_IGNORE_NAK)
return 0; return 0;
...@@ -635,6 +752,10 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ...@@ -635,6 +752,10 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
if (r < 0) if (r < 0)
goto out; goto out;
r = omap_i2c_wait_for_bb_valid(dev);
if (r < 0)
goto out;
r = omap_i2c_wait_for_bb(dev); r = omap_i2c_wait_for_bb(dev);
if (r < 0) if (r < 0)
goto out; goto out;
......
...@@ -885,7 +885,9 @@ static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr) ...@@ -885,7 +885,9 @@ static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr)
return; /* ignore */ return; /* ignore */
} }
if (isr & ISR_BED) { if ((isr & ISR_BED) &&
(!((i2c->msg->flags & I2C_M_IGNORE_NAK) &&
(isr & ISR_ACKNAK)))) {
int ret = BUS_ERROR; int ret = BUS_ERROR;
/* /*
...@@ -919,12 +921,14 @@ static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr) ...@@ -919,12 +921,14 @@ static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr)
icr |= ICR_ALDIE | ICR_TB; icr |= ICR_ALDIE | ICR_TB;
/* /*
* If this is the last byte of the last message, send * If this is the last byte of the last message or last byte
* a STOP. * of any message with I2C_M_STOP (e.g. SCCB), send a STOP.
*/ */
if (i2c->msg_ptr == i2c->msg->len && if ((i2c->msg_ptr == i2c->msg->len) &&
i2c->msg_idx == i2c->msg_num - 1) ((i2c->msg->flags & I2C_M_STOP) ||
icr |= ICR_STOP; (i2c->msg_idx == i2c->msg_num - 1)))
icr |= ICR_STOP;
} else if (i2c->msg_idx < i2c->msg_num - 1) { } else if (i2c->msg_idx < i2c->msg_num - 1) {
/* /*
* Next segment of the message. * Next segment of the message.
...@@ -1071,7 +1075,8 @@ static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num ...@@ -1071,7 +1075,8 @@ static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num
static u32 i2c_pxa_functionality(struct i2c_adapter *adap) static u32 i2c_pxa_functionality(struct i2c_adapter *adap)
{ {
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_NOSTART;
} }
static const struct i2c_algorithm i2c_pxa_algorithm = { static const struct i2c_algorithm i2c_pxa_algorithm = {
......
...@@ -48,6 +48,12 @@ ...@@ -48,6 +48,12 @@
#define ICMAR 0x20 /* master address */ #define ICMAR 0x20 /* master address */
#define ICRXTX 0x24 /* data port */ #define ICRXTX 0x24 /* data port */
/* ICSCR */
#define SDBS (1 << 3) /* slave data buffer select */
#define SIE (1 << 2) /* slave interface enable */
#define GCAE (1 << 1) /* general call address enable */
#define FNA (1 << 0) /* forced non acknowledgment */
/* ICMCR */ /* ICMCR */
#define MDBS (1 << 7) /* non-fifo mode switch */ #define MDBS (1 << 7) /* non-fifo mode switch */
#define FSCL (1 << 6) /* override SCL pin */ #define FSCL (1 << 6) /* override SCL pin */
...@@ -58,6 +64,15 @@ ...@@ -58,6 +64,15 @@
#define FSB (1 << 1) /* force stop bit */ #define FSB (1 << 1) /* force stop bit */
#define ESG (1 << 0) /* en startbit gen */ #define ESG (1 << 0) /* en startbit gen */
/* ICSSR (also for ICSIER) */
#define GCAR (1 << 6) /* general call received */
#define STM (1 << 5) /* slave transmit mode */
#define SSR (1 << 4) /* stop received */
#define SDE (1 << 3) /* slave data empty */
#define SDT (1 << 2) /* slave data transmitted */
#define SDR (1 << 1) /* slave data received */
#define SAR (1 << 0) /* slave addr received */
/* ICMSR (also for ICMIE) */ /* ICMSR (also for ICMIE) */
#define MNR (1 << 6) /* nack received */ #define MNR (1 << 6) /* nack received */
#define MAL (1 << 5) /* arbitration lost */ #define MAL (1 << 5) /* arbitration lost */
...@@ -103,6 +118,7 @@ struct rcar_i2c_priv { ...@@ -103,6 +118,7 @@ struct rcar_i2c_priv {
u32 icccr; u32 icccr;
u32 flags; u32 flags;
enum rcar_i2c_type devtype; enum rcar_i2c_type devtype;
struct i2c_client *slave;
}; };
#define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent) #define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent)
...@@ -126,15 +142,6 @@ static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg) ...@@ -126,15 +142,6 @@ static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg)
static void rcar_i2c_init(struct rcar_i2c_priv *priv) static void rcar_i2c_init(struct rcar_i2c_priv *priv)
{ {
/*
* reset slave mode.
* slave mode is not used on this driver
*/
rcar_i2c_write(priv, ICSIER, 0);
rcar_i2c_write(priv, ICSAR, 0);
rcar_i2c_write(priv, ICSCR, 0);
rcar_i2c_write(priv, ICSSR, 0);
/* reset master mode */ /* reset master mode */
rcar_i2c_write(priv, ICMIER, 0); rcar_i2c_write(priv, ICMIER, 0);
rcar_i2c_write(priv, ICMCR, 0); rcar_i2c_write(priv, ICMCR, 0);
...@@ -360,6 +367,63 @@ static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr) ...@@ -360,6 +367,63 @@ static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
return 0; return 0;
} }
static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
{
u32 ssr_raw, ssr_filtered;
u8 value;
ssr_raw = rcar_i2c_read(priv, ICSSR) & 0xff;
ssr_filtered = ssr_raw & rcar_i2c_read(priv, ICSIER);
if (!ssr_filtered)
return false;
/* address detected */
if (ssr_filtered & SAR) {
/* read or write request */
if (ssr_raw & STM) {
i2c_slave_event(priv->slave, I2C_SLAVE_REQ_READ_START, &value);
rcar_i2c_write(priv, ICRXTX, value);
rcar_i2c_write(priv, ICSIER, SDE | SSR | SAR);
} else {
i2c_slave_event(priv->slave, I2C_SLAVE_REQ_WRITE_START, &value);
rcar_i2c_read(priv, ICRXTX); /* dummy read */
rcar_i2c_write(priv, ICSIER, SDR | SSR | SAR);
}
rcar_i2c_write(priv, ICSSR, ~SAR & 0xff);
}
/* master sent stop */
if (ssr_filtered & SSR) {
i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value);
rcar_i2c_write(priv, ICSIER, SAR | SSR);
rcar_i2c_write(priv, ICSSR, ~SSR & 0xff);
}
/* master wants to write to us */
if (ssr_filtered & SDR) {
int ret;
value = rcar_i2c_read(priv, ICRXTX);
ret = i2c_slave_event(priv->slave, I2C_SLAVE_REQ_WRITE_END, &value);
/* Send NACK in case of error */
rcar_i2c_write(priv, ICSCR, SIE | SDBS | (ret < 0 ? FNA : 0));
i2c_slave_event(priv->slave, I2C_SLAVE_REQ_WRITE_START, &value);
rcar_i2c_write(priv, ICSSR, ~SDR & 0xff);
}
/* master wants to read from us */
if (ssr_filtered & SDE) {
i2c_slave_event(priv->slave, I2C_SLAVE_REQ_READ_END, &value);
i2c_slave_event(priv->slave, I2C_SLAVE_REQ_READ_START, &value);
rcar_i2c_write(priv, ICRXTX, value);
rcar_i2c_write(priv, ICSSR, ~SDE & 0xff);
}
return true;
}
static irqreturn_t rcar_i2c_irq(int irq, void *ptr) static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
{ {
struct rcar_i2c_priv *priv = ptr; struct rcar_i2c_priv *priv = ptr;
...@@ -369,6 +433,9 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) ...@@ -369,6 +433,9 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
/*-------------- spin lock -----------------*/ /*-------------- spin lock -----------------*/
spin_lock(&priv->lock); spin_lock(&priv->lock);
if (rcar_i2c_slave_irq(priv))
goto exit;
msr = rcar_i2c_read(priv, ICMSR); msr = rcar_i2c_read(priv, ICMSR);
/* Only handle interrupts that are currently enabled */ /* Only handle interrupts that are currently enabled */
...@@ -499,6 +566,43 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, ...@@ -499,6 +566,43 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
return ret; return ret;
} }
static int rcar_reg_slave(struct i2c_client *slave)
{
struct rcar_i2c_priv *priv = i2c_get_adapdata(slave->adapter);
if (priv->slave)
return -EBUSY;
if (slave->flags & I2C_CLIENT_TEN)
return -EAFNOSUPPORT;
pm_runtime_forbid(rcar_i2c_priv_to_dev(priv));
priv->slave = slave;
rcar_i2c_write(priv, ICSAR, slave->addr);
rcar_i2c_write(priv, ICSSR, 0);
rcar_i2c_write(priv, ICSIER, SAR | SSR);
rcar_i2c_write(priv, ICSCR, SIE | SDBS);
return 0;
}
static int rcar_unreg_slave(struct i2c_client *slave)
{
struct rcar_i2c_priv *priv = i2c_get_adapdata(slave->adapter);
WARN_ON(!priv->slave);
rcar_i2c_write(priv, ICSIER, 0);
rcar_i2c_write(priv, ICSCR, 0);
priv->slave = NULL;
pm_runtime_allow(rcar_i2c_priv_to_dev(priv));
return 0;
}
static u32 rcar_i2c_func(struct i2c_adapter *adap) static u32 rcar_i2c_func(struct i2c_adapter *adap)
{ {
/* This HW can't do SMBUS_QUICK and NOSTART */ /* This HW can't do SMBUS_QUICK and NOSTART */
...@@ -508,6 +612,8 @@ static u32 rcar_i2c_func(struct i2c_adapter *adap) ...@@ -508,6 +612,8 @@ static u32 rcar_i2c_func(struct i2c_adapter *adap)
static const struct i2c_algorithm rcar_i2c_algo = { static const struct i2c_algorithm rcar_i2c_algo = {
.master_xfer = rcar_i2c_master_xfer, .master_xfer = rcar_i2c_master_xfer,
.functionality = rcar_i2c_func, .functionality = rcar_i2c_func,
.reg_slave = rcar_reg_slave,
.unreg_slave = rcar_unreg_slave,
}; };
static const struct of_device_id rcar_i2c_dt_ids[] = { static const struct of_device_id rcar_i2c_dt_ids[] = {
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/math64.h>
/* Register Map */ /* Register Map */
...@@ -97,6 +98,7 @@ struct rk3x_i2c { ...@@ -97,6 +98,7 @@ struct rk3x_i2c {
/* Hardware resources */ /* Hardware resources */
void __iomem *regs; void __iomem *regs;
struct clk *clk; struct clk *clk;
struct notifier_block clk_rate_nb;
/* Settings */ /* Settings */
unsigned int scl_frequency; unsigned int scl_frequency;
...@@ -428,18 +430,231 @@ static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id) ...@@ -428,18 +430,231 @@ static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void rk3x_i2c_set_scl_rate(struct rk3x_i2c *i2c, unsigned long scl_rate) /**
* Calculate divider values for desired SCL frequency
*
* @clk_rate: I2C input clock rate
* @scl_rate: Desired SCL rate
* @div_low: Divider output for low
* @div_high: Divider output for high
*
* Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
* a best-effort divider value is returned in divs. If the target rate is
* too high, we silently use the highest possible rate.
*/
static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
unsigned long *div_low, unsigned long *div_high)
{ {
unsigned long i2c_rate = clk_get_rate(i2c->clk); unsigned long min_low_ns, min_high_ns;
unsigned int div; unsigned long max_data_hold_ns;
unsigned long data_hold_buffer_ns;
unsigned long max_low_ns, min_total_ns;
unsigned long clk_rate_khz, scl_rate_khz;
unsigned long min_low_div, min_high_div;
unsigned long max_low_div;
unsigned long min_div_for_hold, min_total_div;
unsigned long extra_div, extra_low_div, ideal_low_div;
int ret = 0;
/* Only support standard-mode and fast-mode */
if (WARN_ON(scl_rate > 400000))
scl_rate = 400000;
/* prevent scl_rate_khz from becoming 0 */
if (WARN_ON(scl_rate < 1000))
scl_rate = 1000;
/*
* min_low_ns: The minimum number of ns we need to hold low
* to meet i2c spec
* min_high_ns: The minimum number of ns we need to hold high
* to meet i2c spec
* max_low_ns: The maximum number of ns we can hold low
* to meet i2c spec
*
* Note: max_low_ns should be (max data hold time * 2 - buffer)
* This is because the i2c host on Rockchip holds the data line
* for half the low time.
*/
if (scl_rate <= 100000) {
min_low_ns = 4700;
min_high_ns = 4000;
max_data_hold_ns = 3450;
data_hold_buffer_ns = 50;
} else {
min_low_ns = 1300;
min_high_ns = 600;
max_data_hold_ns = 900;
data_hold_buffer_ns = 50;
}
max_low_ns = max_data_hold_ns * 2 - data_hold_buffer_ns;
min_total_ns = min_low_ns + min_high_ns;
/* Adjust to avoid overflow */
clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000);
scl_rate_khz = scl_rate / 1000;
/*
* We need the total div to be >= this number
* so we don't clock too fast.
*/
min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8);
/* These are the min dividers needed for min hold times. */
min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000);
min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000);
min_div_for_hold = (min_low_div + min_high_div);
/*
* This is the maximum divider so we don't go over the max.
* We don't round up here (we round down) since this is a max.
*/
max_low_div = clk_rate_khz * max_low_ns / (8 * 1000000);
if (min_low_div > max_low_div) {
WARN_ONCE(true,
"Conflicting, min_low_div %lu, max_low_div %lu\n",
min_low_div, max_low_div);
max_low_div = min_low_div;
}
if (min_div_for_hold > min_total_div) {
/*
* Time needed to meet hold requirements is important.
* Just use that.
*/
*div_low = min_low_div;
*div_high = min_high_div;
} else {
/*
* We've got to distribute some time among the low and high
* so we don't run too fast.
*/
extra_div = min_total_div - min_div_for_hold;
/*
* We'll try to split things up perfectly evenly,
* biasing slightly towards having a higher div
* for low (spend more time low).
*/
ideal_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns,
scl_rate_khz * 8 * min_total_ns);
/* Don't allow it to go over the max */
if (ideal_low_div > max_low_div)
ideal_low_div = max_low_div;
/*
* Handle when the ideal low div is going to take up
* more than we have.
*/
if (ideal_low_div > min_low_div + extra_div)
ideal_low_div = min_low_div + extra_div;
/* set DIV = DIVH = DIVL /* Give low the "ideal" and give high whatever extra is left */
* SCL rate = (clk rate) / (8 * (DIVH + 1 + DIVL + 1)) extra_low_div = ideal_low_div - min_low_div;
* = (clk rate) / (16 * (DIV + 1)) *div_low = ideal_low_div;
*div_high = min_high_div + (extra_div - extra_low_div);
}
/*
* Adjust to the fact that the hardware has an implicit "+1".
* NOTE: Above calculations always produce div_low > 0 and div_high > 0.
*/ */
div = DIV_ROUND_UP(i2c_rate, scl_rate * 16) - 1; *div_low = *div_low - 1;
*div_high = *div_high - 1;
/* Maximum divider supported by hw is 0xffff */
if (*div_low > 0xffff) {
*div_low = 0xffff;
ret = -EINVAL;
}
if (*div_high > 0xffff) {
*div_high = 0xffff;
ret = -EINVAL;
}
return ret;
}
static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
{
unsigned long div_low, div_high;
u64 t_low_ns, t_high_ns;
int ret;
ret = rk3x_i2c_calc_divs(clk_rate, i2c->scl_frequency, &div_low,
&div_high);
WARN_ONCE(ret != 0, "Could not reach SCL freq %u", i2c->scl_frequency);
clk_enable(i2c->clk);
i2c_writel(i2c, (div_high << 16) | (div_low & 0xffff), REG_CLKDIV);
clk_disable(i2c->clk);
i2c_writel(i2c, (div << 16) | (div & 0xffff), REG_CLKDIV); t_low_ns = div_u64(((u64)div_low + 1) * 8 * 1000000000, clk_rate);
t_high_ns = div_u64(((u64)div_high + 1) * 8 * 1000000000, clk_rate);
dev_dbg(i2c->dev,
"CLK %lukhz, Req %uns, Act low %lluns high %lluns\n",
clk_rate / 1000,
1000000000 / i2c->scl_frequency,
t_low_ns, t_high_ns);
}
/**
* rk3x_i2c_clk_notifier_cb - Clock rate change callback
* @nb: Pointer to notifier block
* @event: Notification reason
* @data: Pointer to notification data object
*
* The callback checks whether a valid bus frequency can be generated after the
* change. If so, the change is acknowledged, otherwise the change is aborted.
* New dividers are written to the HW in the pre- or post change notification
* depending on the scaling direction.
*
* Code adapted from i2c-cadence.c.
*
* Return: NOTIFY_STOP if the rate change should be aborted, NOTIFY_OK
* to acknowedge the change, NOTIFY_DONE if the notification is
* considered irrelevant.
*/
static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
event, void *data)
{
struct clk_notifier_data *ndata = data;
struct rk3x_i2c *i2c = container_of(nb, struct rk3x_i2c, clk_rate_nb);
unsigned long div_low, div_high;
switch (event) {
case PRE_RATE_CHANGE:
if (rk3x_i2c_calc_divs(ndata->new_rate, i2c->scl_frequency,
&div_low, &div_high) != 0) {
return NOTIFY_STOP;
}
/* scale up */
if (ndata->new_rate > ndata->old_rate)
rk3x_i2c_adapt_div(i2c, ndata->new_rate);
return NOTIFY_OK;
case POST_RATE_CHANGE:
/* scale down */
if (ndata->new_rate < ndata->old_rate)
rk3x_i2c_adapt_div(i2c, ndata->new_rate);
return NOTIFY_OK;
case ABORT_RATE_CHANGE:
/* scale up */
if (ndata->new_rate > ndata->old_rate)
rk3x_i2c_adapt_div(i2c, ndata->old_rate);
return NOTIFY_OK;
default:
return NOTIFY_DONE;
}
} }
/** /**
...@@ -536,9 +751,6 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap, ...@@ -536,9 +751,6 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
clk_enable(i2c->clk); clk_enable(i2c->clk);
/* The clock rate might have changed, so setup the divider again */
rk3x_i2c_set_scl_rate(i2c, i2c->scl_frequency);
i2c->is_last_msg = false; i2c->is_last_msg = false;
/* /*
...@@ -624,6 +836,7 @@ static int rk3x_i2c_probe(struct platform_device *pdev) ...@@ -624,6 +836,7 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
int bus_nr; int bus_nr;
u32 value; u32 value;
int irq; int irq;
unsigned long clk_rate;
i2c = devm_kzalloc(&pdev->dev, sizeof(struct rk3x_i2c), GFP_KERNEL); i2c = devm_kzalloc(&pdev->dev, sizeof(struct rk3x_i2c), GFP_KERNEL);
if (!i2c) if (!i2c)
...@@ -724,16 +937,28 @@ static int rk3x_i2c_probe(struct platform_device *pdev) ...@@ -724,16 +937,28 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
return ret; return ret;
} }
i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb;
ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb);
if (ret != 0) {
dev_err(&pdev->dev, "Unable to register clock notifier\n");
goto err_clk;
}
clk_rate = clk_get_rate(i2c->clk);
rk3x_i2c_adapt_div(i2c, clk_rate);
ret = i2c_add_adapter(&i2c->adap); ret = i2c_add_adapter(&i2c->adap);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "Could not register adapter\n"); dev_err(&pdev->dev, "Could not register adapter\n");
goto err_clk; goto err_clk_notifier;
} }
dev_info(&pdev->dev, "Initialized RK3xxx I2C bus at %p\n", i2c->regs); dev_info(&pdev->dev, "Initialized RK3xxx I2C bus at %p\n", i2c->regs);
return 0; return 0;
err_clk_notifier:
clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
err_clk: err_clk:
clk_unprepare(i2c->clk); clk_unprepare(i2c->clk);
return ret; return ret;
...@@ -744,6 +969,8 @@ static int rk3x_i2c_remove(struct platform_device *pdev) ...@@ -744,6 +969,8 @@ static int rk3x_i2c_remove(struct platform_device *pdev)
struct rk3x_i2c *i2c = platform_get_drvdata(pdev); struct rk3x_i2c *i2c = platform_get_drvdata(pdev);
i2c_del_adapter(&i2c->adap); i2c_del_adapter(&i2c->adap);
clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
clk_unprepare(i2c->clk); clk_unprepare(i2c->clk);
return 0; return 0;
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -87,6 +89,9 @@ ...@@ -87,6 +89,9 @@
/* Max time to wait for bus to become idle after a xfer (in us) */ /* Max time to wait for bus to become idle after a xfer (in us) */
#define S3C2410_IDLE_TIMEOUT 5000 #define S3C2410_IDLE_TIMEOUT 5000
/* Exynos5 Sysreg offset */
#define EXYNOS5_SYS_I2C_CFG 0x0234
/* i2c controller state */ /* i2c controller state */
enum s3c24xx_i2c_state { enum s3c24xx_i2c_state {
STATE_IDLE, STATE_IDLE,
...@@ -123,6 +128,8 @@ struct s3c24xx_i2c { ...@@ -123,6 +128,8 @@ struct s3c24xx_i2c {
#if defined(CONFIG_ARM_S3C24XX_CPUFREQ) #if defined(CONFIG_ARM_S3C24XX_CPUFREQ)
struct notifier_block freq_transition; struct notifier_block freq_transition;
#endif #endif
struct regmap *sysreg;
unsigned int sys_i2c_cfg;
}; };
static struct platform_device_id s3c24xx_driver_ids[] = { static struct platform_device_id s3c24xx_driver_ids[] = {
...@@ -1071,6 +1078,7 @@ static void ...@@ -1071,6 +1078,7 @@ static void
s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c) s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
{ {
struct s3c2410_platform_i2c *pdata = i2c->pdata; struct s3c2410_platform_i2c *pdata = i2c->pdata;
int id;
if (!np) if (!np)
return; return;
...@@ -1080,6 +1088,21 @@ s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c) ...@@ -1080,6 +1088,21 @@ s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
of_property_read_u32(np, "samsung,i2c-slave-addr", &pdata->slave_addr); of_property_read_u32(np, "samsung,i2c-slave-addr", &pdata->slave_addr);
of_property_read_u32(np, "samsung,i2c-max-bus-freq", of_property_read_u32(np, "samsung,i2c-max-bus-freq",
(u32 *)&pdata->frequency); (u32 *)&pdata->frequency);
/*
* Exynos5's legacy i2c controller and new high speed i2c
* controller have muxed interrupt sources. By default the
* interrupts for 4-channel HS-I2C controller are enabled.
* If nodes for first four channels of legacy i2c controller
* are available then re-configure the interrupts via the
* system register.
*/
id = of_alias_get_id(np, "i2c");
i2c->sysreg = syscon_regmap_lookup_by_phandle(np,
"samsung,sysreg-phandle");
if (IS_ERR(i2c->sysreg))
return;
regmap_update_bits(i2c->sysreg, EXYNOS5_SYS_I2C_CFG, BIT(id), 0);
} }
#else #else
static void static void
...@@ -1260,6 +1283,9 @@ static int s3c24xx_i2c_suspend_noirq(struct device *dev) ...@@ -1260,6 +1283,9 @@ static int s3c24xx_i2c_suspend_noirq(struct device *dev)
i2c->suspended = 1; i2c->suspended = 1;
if (!IS_ERR(i2c->sysreg))
regmap_read(i2c->sysreg, EXYNOS5_SYS_I2C_CFG, &i2c->sys_i2c_cfg);
return 0; return 0;
} }
...@@ -1268,6 +1294,9 @@ static int s3c24xx_i2c_resume_noirq(struct device *dev) ...@@ -1268,6 +1294,9 @@ static int s3c24xx_i2c_resume_noirq(struct device *dev)
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
if (!IS_ERR(i2c->sysreg))
regmap_write(i2c->sysreg, EXYNOS5_SYS_I2C_CFG, i2c->sys_i2c_cfg);
clk_prepare_enable(i2c->clk); clk_prepare_enable(i2c->clk);
s3c24xx_i2c_init(i2c); s3c24xx_i2c_init(i2c);
clk_disable_unprepare(i2c->clk); clk_disable_unprepare(i2c->clk);
......
This diff is collapsed.
...@@ -46,6 +46,11 @@ enum xilinx_i2c_state { ...@@ -46,6 +46,11 @@ enum xilinx_i2c_state {
STATE_START STATE_START
}; };
enum xiic_endian {
LITTLE,
BIG
};
/** /**
* struct xiic_i2c - Internal representation of the XIIC I2C bus * struct xiic_i2c - Internal representation of the XIIC I2C bus
* @base: Memory base of the HW registers * @base: Memory base of the HW registers
...@@ -70,6 +75,7 @@ struct xiic_i2c { ...@@ -70,6 +75,7 @@ struct xiic_i2c {
enum xilinx_i2c_state state; enum xilinx_i2c_state state;
struct i2c_msg *rx_msg; struct i2c_msg *rx_msg;
int rx_pos; int rx_pos;
enum xiic_endian endianness;
}; };
...@@ -170,29 +176,58 @@ struct xiic_i2c { ...@@ -170,29 +176,58 @@ struct xiic_i2c {
static void xiic_start_xfer(struct xiic_i2c *i2c); static void xiic_start_xfer(struct xiic_i2c *i2c);
static void __xiic_start_xfer(struct xiic_i2c *i2c); static void __xiic_start_xfer(struct xiic_i2c *i2c);
/*
* For the register read and write functions, a little-endian and big-endian
* version are necessary. Endianness is detected during the probe function.
* Only the least significant byte [doublet] of the register are ever
* accessed. This requires an offset of 3 [2] from the base address for
* big-endian systems.
*/
static inline void xiic_setreg8(struct xiic_i2c *i2c, int reg, u8 value) static inline void xiic_setreg8(struct xiic_i2c *i2c, int reg, u8 value)
{ {
iowrite8(value, i2c->base + reg); if (i2c->endianness == LITTLE)
iowrite8(value, i2c->base + reg);
else
iowrite8(value, i2c->base + reg + 3);
} }
static inline u8 xiic_getreg8(struct xiic_i2c *i2c, int reg) static inline u8 xiic_getreg8(struct xiic_i2c *i2c, int reg)
{ {
return ioread8(i2c->base + reg); u8 ret;
if (i2c->endianness == LITTLE)
ret = ioread8(i2c->base + reg);
else
ret = ioread8(i2c->base + reg + 3);
return ret;
} }
static inline void xiic_setreg16(struct xiic_i2c *i2c, int reg, u16 value) static inline void xiic_setreg16(struct xiic_i2c *i2c, int reg, u16 value)
{ {
iowrite16(value, i2c->base + reg); if (i2c->endianness == LITTLE)
iowrite16(value, i2c->base + reg);
else
iowrite16be(value, i2c->base + reg + 2);
} }
static inline void xiic_setreg32(struct xiic_i2c *i2c, int reg, int value) static inline void xiic_setreg32(struct xiic_i2c *i2c, int reg, int value)
{ {
iowrite32(value, i2c->base + reg); if (i2c->endianness == LITTLE)
iowrite32(value, i2c->base + reg);
else
iowrite32be(value, i2c->base + reg);
} }
static inline int xiic_getreg32(struct xiic_i2c *i2c, int reg) static inline int xiic_getreg32(struct xiic_i2c *i2c, int reg)
{ {
return ioread32(i2c->base + reg); u32 ret;
if (i2c->endianness == LITTLE)
ret = ioread32(i2c->base + reg);
else
ret = ioread32be(i2c->base + reg);
return ret;
} }
static inline void xiic_irq_dis(struct xiic_i2c *i2c, u32 mask) static inline void xiic_irq_dis(struct xiic_i2c *i2c, u32 mask)
...@@ -692,6 +727,7 @@ static int xiic_i2c_probe(struct platform_device *pdev) ...@@ -692,6 +727,7 @@ static int xiic_i2c_probe(struct platform_device *pdev)
struct resource *res; struct resource *res;
int ret, irq; int ret, irq;
u8 i; u8 i;
u32 sr;
i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c) if (!i2c)
...@@ -724,6 +760,18 @@ static int xiic_i2c_probe(struct platform_device *pdev) ...@@ -724,6 +760,18 @@ static int xiic_i2c_probe(struct platform_device *pdev)
return ret; return ret;
} }
/*
* Detect endianness
* Try to reset the TX FIFO. Then check the EMPTY flag. If it is not
* set, assume that the endianness was wrong and swap.
*/
i2c->endianness = LITTLE;
xiic_setreg32(i2c, XIIC_CR_REG_OFFSET, XIIC_CR_TX_FIFO_RESET_MASK);
/* Reset is cleared in xiic_reinit */
sr = xiic_getreg32(i2c, XIIC_SR_REG_OFFSET);
if (!(sr & XIIC_SR_TX_FIFO_EMPTY_MASK))
i2c->endianness = BIG;
xiic_reinit(i2c); xiic_reinit(i2c);
/* add i2c adapter to i2c tree */ /* add i2c adapter to i2c tree */
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
(c) 2013 Wolfram Sang <wsa@the-dreams.de> (c) 2013 Wolfram Sang <wsa@the-dreams.de>
I2C ACPI code Copyright (C) 2014 Intel Corp I2C ACPI code Copyright (C) 2014 Intel Corp
Author: Lan Tianyu <tianyu.lan@intel.com> Author: Lan Tianyu <tianyu.lan@intel.com>
I2C slave support (c) 2014 by Wolfram Sang <wsa@sang-engineering.com>
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -261,7 +262,7 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command, ...@@ -261,7 +262,7 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command,
struct acpi_resource *ares; struct acpi_resource *ares;
u32 accessor_type = function >> 16; u32 accessor_type = function >> 16;
u8 action = function & ACPI_IO_MASK; u8 action = function & ACPI_IO_MASK;
acpi_status ret = AE_OK; acpi_status ret;
int status; int status;
ret = acpi_buffer_to_resource(info->connection, info->length, &ares); ret = acpi_buffer_to_resource(info->connection, info->length, &ares);
...@@ -628,6 +629,17 @@ static int i2c_device_probe(struct device *dev) ...@@ -628,6 +629,17 @@ static int i2c_device_probe(struct device *dev)
if (!client) if (!client)
return 0; return 0;
if (!client->irq && dev->of_node) {
int irq = of_irq_get(dev->of_node, 0);
if (irq == -EPROBE_DEFER)
return irq;
if (irq < 0)
irq = 0;
client->irq = irq;
}
driver = to_i2c_driver(dev->driver); driver = to_i2c_driver(dev->driver);
if (!driver->probe || !driver->id_table) if (!driver->probe || !driver->id_table)
return -ENODEV; return -ENODEV;
...@@ -1401,7 +1413,6 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, ...@@ -1401,7 +1413,6 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
info.irq = irq_of_parse_and_map(node, 0);
info.of_node = of_node_get(node); info.of_node = of_node_get(node);
info.archdata = &dev_ad; info.archdata = &dev_ad;
...@@ -1415,7 +1426,6 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, ...@@ -1415,7 +1426,6 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
dev_err(&adap->dev, "of_i2c: Failure registering %s\n", dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
node->full_name); node->full_name);
of_node_put(node); of_node_put(node);
irq_dispose_mapping(info.irq);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
return result; return result;
...@@ -2962,6 +2972,54 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, ...@@ -2962,6 +2972,54 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
} }
EXPORT_SYMBOL(i2c_smbus_xfer); EXPORT_SYMBOL(i2c_smbus_xfer);
int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb)
{
int ret;
if (!client || !slave_cb)
return -EINVAL;
if (!(client->flags & I2C_CLIENT_TEN)) {
/* Enforce stricter address checking */
ret = i2c_check_addr_validity(client->addr);
if (ret)
return ret;
}
if (!client->adapter->algo->reg_slave)
return -EOPNOTSUPP;
client->slave_cb = slave_cb;
i2c_lock_adapter(client->adapter);
ret = client->adapter->algo->reg_slave(client);
i2c_unlock_adapter(client->adapter);
if (ret)
client->slave_cb = NULL;
return ret;
}
EXPORT_SYMBOL_GPL(i2c_slave_register);
int i2c_slave_unregister(struct i2c_client *client)
{
int ret;
if (!client->adapter->algo->unreg_slave)
return -EOPNOTSUPP;
i2c_lock_adapter(client->adapter);
ret = client->adapter->algo->unreg_slave(client);
i2c_unlock_adapter(client->adapter);
if (ret == 0)
client->slave_cb = NULL;
return ret;
}
EXPORT_SYMBOL_GPL(i2c_slave_unregister);
MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>"); MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
MODULE_DESCRIPTION("I2C-Bus main module"); MODULE_DESCRIPTION("I2C-Bus main module");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -110,6 +110,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent, ...@@ -110,6 +110,7 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
void *, u32)) void *, u32))
{ {
struct i2c_mux_priv *priv; struct i2c_mux_priv *priv;
char symlink_name[20];
int ret; int ret;
priv = kzalloc(sizeof(struct i2c_mux_priv), GFP_KERNEL); priv = kzalloc(sizeof(struct i2c_mux_priv), GFP_KERNEL);
...@@ -183,6 +184,12 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent, ...@@ -183,6 +184,12 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
return NULL; return NULL;
} }
WARN(sysfs_create_link(&priv->adap.dev.kobj, &mux_dev->kobj, "mux_device"),
"can't create symlink to mux device\n");
snprintf(symlink_name, sizeof(symlink_name), "channel-%u", chan_id);
WARN(sysfs_create_link(&mux_dev->kobj, &priv->adap.dev.kobj, symlink_name),
"can't create symlink for channel %u\n", chan_id);
dev_info(&parent->dev, "Added multiplexed i2c bus %d\n", dev_info(&parent->dev, "Added multiplexed i2c bus %d\n",
i2c_adapter_id(&priv->adap)); i2c_adapter_id(&priv->adap));
...@@ -193,7 +200,12 @@ EXPORT_SYMBOL_GPL(i2c_add_mux_adapter); ...@@ -193,7 +200,12 @@ EXPORT_SYMBOL_GPL(i2c_add_mux_adapter);
void i2c_del_mux_adapter(struct i2c_adapter *adap) void i2c_del_mux_adapter(struct i2c_adapter *adap)
{ {
struct i2c_mux_priv *priv = adap->algo_data; struct i2c_mux_priv *priv = adap->algo_data;
char symlink_name[20];
snprintf(symlink_name, sizeof(symlink_name), "channel-%u", priv->chan_id);
sysfs_remove_link(&adap->dev.parent->kobj, symlink_name);
sysfs_remove_link(&priv->adap.dev.kobj, "mux_device");
i2c_del_adapter(adap); i2c_del_adapter(adap);
kfree(priv); kfree(priv);
} }
......
/*
* I2C slave mode EEPROM simulator
*
* Copyright (C) 2014 by Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>
* Copyright (C) 2014 by Renesas Electronics Corporation
*
* 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 of the License.
*
* Because most IP blocks can only detect one I2C slave address anyhow, this
* driver does not support simulating EEPROM types which take more than one
* address. It is prepared to simulate bigger EEPROMs with an internal 16 bit
* pointer, yet implementation is deferred until the need actually arises.
*/
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/sysfs.h>
struct eeprom_data {
struct bin_attribute bin;
bool first_write;
spinlock_t buffer_lock;
u8 buffer_idx;
u8 buffer[];
};
static int i2c_slave_eeprom_slave_cb(struct i2c_client *client,
enum i2c_slave_event event, u8 *val)
{
struct eeprom_data *eeprom = i2c_get_clientdata(client);
switch (event) {
case I2C_SLAVE_REQ_WRITE_END:
if (eeprom->first_write) {
eeprom->buffer_idx = *val;
eeprom->first_write = false;
} else {
spin_lock(&eeprom->buffer_lock);
eeprom->buffer[eeprom->buffer_idx++] = *val;
spin_unlock(&eeprom->buffer_lock);
}
break;
case I2C_SLAVE_REQ_READ_START:
spin_lock(&eeprom->buffer_lock);
*val = eeprom->buffer[eeprom->buffer_idx];
spin_unlock(&eeprom->buffer_lock);
break;
case I2C_SLAVE_REQ_READ_END:
eeprom->buffer_idx++;
break;
case I2C_SLAVE_STOP:
eeprom->first_write = true;
break;
default:
break;
}
return 0;
}
static ssize_t i2c_slave_eeprom_bin_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr, char *buf, loff_t off, size_t count)
{
struct eeprom_data *eeprom;
unsigned long flags;
if (off + count >= attr->size)
return -EFBIG;
eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj));
spin_lock_irqsave(&eeprom->buffer_lock, flags);
memcpy(buf, &eeprom->buffer[off], count);
spin_unlock_irqrestore(&eeprom->buffer_lock, flags);
return count;
}
static ssize_t i2c_slave_eeprom_bin_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr, char *buf, loff_t off, size_t count)
{
struct eeprom_data *eeprom;
unsigned long flags;
if (off + count >= attr->size)
return -EFBIG;
eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj));
spin_lock_irqsave(&eeprom->buffer_lock, flags);
memcpy(&eeprom->buffer[off], buf, count);
spin_unlock_irqrestore(&eeprom->buffer_lock, flags);
return count;
}
static int i2c_slave_eeprom_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct eeprom_data *eeprom;
int ret;
unsigned size = id->driver_data;
eeprom = devm_kzalloc(&client->dev, sizeof(struct eeprom_data) + size, GFP_KERNEL);
if (!eeprom)
return -ENOMEM;
eeprom->first_write = true;
spin_lock_init(&eeprom->buffer_lock);
i2c_set_clientdata(client, eeprom);
sysfs_bin_attr_init(&eeprom->bin);
eeprom->bin.attr.name = "slave-eeprom";
eeprom->bin.attr.mode = S_IRUSR | S_IWUSR;
eeprom->bin.read = i2c_slave_eeprom_bin_read;
eeprom->bin.write = i2c_slave_eeprom_bin_write;
eeprom->bin.size = size;
ret = sysfs_create_bin_file(&client->dev.kobj, &eeprom->bin);
if (ret)
return ret;
ret = i2c_slave_register(client, i2c_slave_eeprom_slave_cb);
if (ret) {
sysfs_remove_bin_file(&client->dev.kobj, &eeprom->bin);
return ret;
}
return 0;
};
static int i2c_slave_eeprom_remove(struct i2c_client *client)
{
struct eeprom_data *eeprom = i2c_get_clientdata(client);
i2c_slave_unregister(client);
sysfs_remove_bin_file(&client->dev.kobj, &eeprom->bin);
return 0;
}
static const struct i2c_device_id i2c_slave_eeprom_id[] = {
{ "slave-24c02", 2048 / 8 },
{ }
};
MODULE_DEVICE_TABLE(i2c, i2c_slave_eeprom_id);
static struct i2c_driver i2c_slave_eeprom_driver = {
.driver = {
.name = "i2c-slave-eeprom",
.owner = THIS_MODULE,
},
.probe = i2c_slave_eeprom_probe,
.remove = i2c_slave_eeprom_remove,
.id_table = i2c_slave_eeprom_id,
};
module_i2c_driver(i2c_slave_eeprom_driver);
MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>");
MODULE_DESCRIPTION("I2C slave mode EEPROM simulator");
MODULE_LICENSE("GPL v2");
...@@ -56,6 +56,7 @@ struct at24_data { ...@@ -56,6 +56,7 @@ struct at24_data {
struct at24_platform_data chip; struct at24_platform_data chip;
struct memory_accessor macc; struct memory_accessor macc;
int use_smbus; int use_smbus;
int use_smbus_write;
/* /*
* Lock protects against activities from other Linux tasks, * Lock protects against activities from other Linux tasks,
...@@ -324,7 +325,7 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf, ...@@ -324,7 +325,7 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
{ {
struct i2c_client *client; struct i2c_client *client;
struct i2c_msg msg; struct i2c_msg msg;
ssize_t status; ssize_t status = 0;
unsigned long timeout, write_time; unsigned long timeout, write_time;
unsigned next_page; unsigned next_page;
...@@ -365,9 +366,18 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf, ...@@ -365,9 +366,18 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
timeout = jiffies + msecs_to_jiffies(write_timeout); timeout = jiffies + msecs_to_jiffies(write_timeout);
do { do {
write_time = jiffies; write_time = jiffies;
if (at24->use_smbus) { if (at24->use_smbus_write) {
status = i2c_smbus_write_i2c_block_data(client, switch (at24->use_smbus_write) {
offset, count, buf); case I2C_SMBUS_I2C_BLOCK_DATA:
status = i2c_smbus_write_i2c_block_data(client,
offset, count, buf);
break;
case I2C_SMBUS_BYTE_DATA:
status = i2c_smbus_write_byte_data(client,
offset, buf[0]);
break;
}
if (status == 0) if (status == 0)
status = count; status = count;
} else { } else {
...@@ -487,6 +497,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -487,6 +497,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
struct at24_platform_data chip; struct at24_platform_data chip;
bool writable; bool writable;
int use_smbus = 0; int use_smbus = 0;
int use_smbus_write = 0;
struct at24_data *at24; struct at24_data *at24;
int err; int err;
unsigned i, num_addresses; unsigned i, num_addresses;
...@@ -546,6 +557,18 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -546,6 +557,18 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
} }
} }
/* Use I2C operations unless we're stuck with SMBus extensions. */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
if (i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
use_smbus_write = I2C_SMBUS_I2C_BLOCK_DATA;
} else if (i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
use_smbus_write = I2C_SMBUS_BYTE_DATA;
chip.page_size = 1;
}
}
if (chip.flags & AT24_FLAG_TAKE8ADDR) if (chip.flags & AT24_FLAG_TAKE8ADDR)
num_addresses = 8; num_addresses = 8;
else else
...@@ -559,6 +582,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -559,6 +582,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
mutex_init(&at24->lock); mutex_init(&at24->lock);
at24->use_smbus = use_smbus; at24->use_smbus = use_smbus;
at24->use_smbus_write = use_smbus_write;
at24->chip = chip; at24->chip = chip;
at24->num_addresses = num_addresses; at24->num_addresses = num_addresses;
...@@ -576,8 +600,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -576,8 +600,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
writable = !(chip.flags & AT24_FLAG_READONLY); writable = !(chip.flags & AT24_FLAG_READONLY);
if (writable) { if (writable) {
if (!use_smbus || i2c_check_functionality(client->adapter, if (!use_smbus || use_smbus_write) {
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
unsigned write_max = chip.page_size; unsigned write_max = chip.page_size;
......
...@@ -405,6 +405,7 @@ int of_irq_get(struct device_node *dev, int index) ...@@ -405,6 +405,7 @@ int of_irq_get(struct device_node *dev, int index)
return irq_create_of_mapping(&oirq); return irq_create_of_mapping(&oirq);
} }
EXPORT_SYMBOL_GPL(of_irq_get);
/** /**
* of_irq_get_byname - Decode a node's IRQ and return it as a Linux irq number * of_irq_get_byname - Decode a node's IRQ and return it as a Linux irq number
......
...@@ -46,6 +46,8 @@ struct i2c_client; ...@@ -46,6 +46,8 @@ struct i2c_client;
struct i2c_driver; struct i2c_driver;
union i2c_smbus_data; union i2c_smbus_data;
struct i2c_board_info; struct i2c_board_info;
enum i2c_slave_event;
typedef int (*i2c_slave_cb_t)(struct i2c_client *, enum i2c_slave_event, u8 *);
struct module; struct module;
...@@ -209,6 +211,8 @@ struct i2c_driver { ...@@ -209,6 +211,8 @@ struct i2c_driver {
* @irq: indicates the IRQ generated by this device (if any) * @irq: indicates the IRQ generated by this device (if any)
* @detected: member of an i2c_driver.clients list or i2c-core's * @detected: member of an i2c_driver.clients list or i2c-core's
* userspace_devices list * userspace_devices list
* @slave_cb: Callback when I2C slave mode of an adapter is used. The adapter
* calls it to pass on slave events to the slave driver.
* *
* An i2c_client identifies a single device (i.e. chip) connected to an * An i2c_client identifies a single device (i.e. chip) connected to an
* i2c bus. The behaviour exposed to Linux is defined by the driver * i2c bus. The behaviour exposed to Linux is defined by the driver
...@@ -224,6 +228,7 @@ struct i2c_client { ...@@ -224,6 +228,7 @@ struct i2c_client {
struct device dev; /* the device structure */ struct device dev; /* the device structure */
int irq; /* irq issued by device */ int irq; /* irq issued by device */
struct list_head detected; struct list_head detected;
i2c_slave_cb_t slave_cb; /* callback for slave mode */
}; };
#define to_i2c_client(d) container_of(d, struct i2c_client, dev) #define to_i2c_client(d) container_of(d, struct i2c_client, dev)
...@@ -246,6 +251,25 @@ static inline void i2c_set_clientdata(struct i2c_client *dev, void *data) ...@@ -246,6 +251,25 @@ static inline void i2c_set_clientdata(struct i2c_client *dev, void *data)
dev_set_drvdata(&dev->dev, data); dev_set_drvdata(&dev->dev, data);
} }
/* I2C slave support */
enum i2c_slave_event {
I2C_SLAVE_REQ_READ_START,
I2C_SLAVE_REQ_READ_END,
I2C_SLAVE_REQ_WRITE_START,
I2C_SLAVE_REQ_WRITE_END,
I2C_SLAVE_STOP,
};
extern int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb);
extern int i2c_slave_unregister(struct i2c_client *client);
static inline int i2c_slave_event(struct i2c_client *client,
enum i2c_slave_event event, u8 *val)
{
return client->slave_cb(client, event, val);
}
/** /**
* struct i2c_board_info - template for device creation * struct i2c_board_info - template for device creation
* @type: chip type, to initialize i2c_client.name * @type: chip type, to initialize i2c_client.name
...@@ -352,6 +376,8 @@ i2c_register_board_info(int busnum, struct i2c_board_info const *info, ...@@ -352,6 +376,8 @@ i2c_register_board_info(int busnum, struct i2c_board_info const *info,
* into I2C transfers instead. * into I2C transfers instead.
* @functionality: Return the flags that this algorithm/adapter pair supports * @functionality: Return the flags that this algorithm/adapter pair supports
* from the I2C_FUNC_* flags. * from the I2C_FUNC_* flags.
* @reg_slave: Register given client to I2C slave mode of this adapter
* @unreg_slave: Unregister given client from I2C slave mode of this adapter
* *
* The following structs are for those who like to implement new bus drivers: * The following structs are for those who like to implement new bus drivers:
* i2c_algorithm is the interface to a class of hardware solutions which can * i2c_algorithm is the interface to a class of hardware solutions which can
...@@ -377,6 +403,9 @@ struct i2c_algorithm { ...@@ -377,6 +403,9 @@ struct i2c_algorithm {
/* To determine what the adapter supports */ /* To determine what the adapter supports */
u32 (*functionality) (struct i2c_adapter *); u32 (*functionality) (struct i2c_adapter *);
int (*reg_slave)(struct i2c_client *client);
int (*unreg_slave)(struct i2c_client *client);
}; };
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment