Commit 32250e4a authored by Linus Torvalds's avatar Linus Torvalds

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

Pull i2c updates from Wolfram Sang:
 "Quite some driver updates:
   - piix4 can now handle multiplexed adapters
   - brcmstb, xlr, eg20t, designware drivers support more SoCs
   - emev2 gained i2c slave support
   - img-scb and rcar got bigger refactoring to remove issues
   - lots of common driver updates

  i2c core changes:
   - new quirk flag when an adapter does not support clock stretching,
     so clients can be configured to avoid that if possible
   - added a helper function to retrieve timing parameters from firmware
     (with rcar being the first user)
   - "multi-master" DT binding added so drivers can adapt to this
     setting (like disabling PM to keep arbitration working)
   - RuntimePM for the logical adapter device is now always enabled by
     the core to ensure propagation from childs to the parent (the HW
     device)
   - new macro builtin_i2c_driver to reduce boilerplate"

* 'i2c/for-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (70 commits)
  i2c: create builtin_i2c_driver to avoid registration boilerplate
  i2c: imx: fix i2c resource leak with dma transfer
  dt-bindings: i2c: eeprom: add another EEPROM device
  dt-bindings: move I2C eeprom descriptions to the proper file
  i2c: designware: Do not require clock when SSCN and FFCN are provided
  DT: i2c: trivial-devices: Add Epson RX8010 and MPL3115
  i2c: s3c2410: remove superfluous runtime PM calls
  i2c: always enable RuntimePM for the adapter device
  i2c: designware: retry transfer on transient failure
  i2c: ibm_iic: rename i2c_timings struct due to clash with generic version
  i2c: designware: Add support for AMD Seattle I2C
  i2c: imx: Remove unneeded comments
  i2c: st: use to_platform_device()
  i2c: designware: use to_pci_dev()
  i2c: brcmstb: Adding support for CM and DSL SoCs
  i2c: mediatek: fix i2c multi transfer issue in high speed mode
  i2c: imx: improve code readability
  i2c: imx: Improve message log when DMA is not used
  i2c: imx: add runtime pm support to improve the performance
  i2c: imx: init bus recovery info before adding i2c adapter
  ...
parents 5339f9d4 c698d639
...@@ -2,11 +2,22 @@ EEPROMs (I2C) ...@@ -2,11 +2,22 @@ EEPROMs (I2C)
Required properties: Required properties:
- compatible : should be "<manufacturer>,<type>" - compatible : should be "<manufacturer>,<type>", like these:
"atmel,24c00", "atmel,24c01", "atmel,24c02", "atmel,24c04",
"atmel,24c08", "atmel,24c16", "atmel,24c32", "atmel,24c64",
"atmel,24c128", "atmel,24c256", "atmel,24c512", "atmel,24c1024"
"catalyst,24c32"
"ramtron,24c64"
"renesas,r1ex24002"
If there is no specific driver for <manufacturer>, a generic If there is no specific driver for <manufacturer>, a generic
driver based on <type> is selected. Possible types are: driver based on <type> is selected. Possible types are:
24c00, 24c01, 24c02, 24c04, 24c08, 24c16, 24c32, 24c64, "24c00", "24c01", "24c02", "24c04", "24c08", "24c16", "24c32", "24c64",
24c128, 24c256, 24c512, 24c1024, spd "24c128", "24c256", "24c512", "24c1024", "spd"
- reg : the I2C address of the EEPROM - reg : the I2C address of the EEPROM
......
...@@ -3,7 +3,7 @@ I2C for Atmel platforms ...@@ -3,7 +3,7 @@ I2C for Atmel platforms
Required properties : Required properties :
- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c", - compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c",
"atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c", "atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c",
"atmel,at91sam9x5-i2c" or "atmel,sama5d2-i2c" "atmel,at91sam9x5-i2c", "atmel,sama5d4-i2c" or "atmel,sama5d2-i2c"
- reg: physical base address of the controller and length of memory mapped - reg: physical base address of the controller and length of memory mapped
region. region.
- interrupts: interrupt number to the cpu. - interrupts: interrupt number to the cpu.
...@@ -17,6 +17,8 @@ Optional properties: ...@@ -17,6 +17,8 @@ Optional properties:
- dma-names: should contain "tx" and "rx". - dma-names: should contain "tx" and "rx".
- atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO - atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO
capable I2C controllers. capable I2C controllers.
- i2c-sda-hold-time-ns: TWD hold time, only available for "atmel,sama5d4-i2c"
and "atmel,sama5d2-i2c".
- Child nodes conforming to i2c bus binding - Child nodes conforming to i2c bus binding
Examples : Examples :
...@@ -52,6 +54,7 @@ i2c0: i2c@f8034600 { ...@@ -52,6 +54,7 @@ i2c0: i2c@f8034600 {
#size-cells = <0>; #size-cells = <0>;
clocks = <&flx0>; clocks = <&flx0>;
atmel,fifo-size = <16>; atmel,fifo-size = <16>;
i2c-sda-hold-time-ns = <336>;
wm8731: wm8731@1a { wm8731: wm8731@1a {
compatible = "wm8731"; compatible = "wm8731";
......
...@@ -2,7 +2,7 @@ Broadcom stb bsc iic master controller ...@@ -2,7 +2,7 @@ Broadcom stb bsc iic master controller
Required properties: Required properties:
- compatible: should be "brcm,brcmstb-i2c" - compatible: should be "brcm,brcmstb-i2c" or "brcm,brcmper-i2c"
- clock-frequency: 32-bit decimal value of iic master clock freqency in Hz - clock-frequency: 32-bit decimal value of iic master clock freqency in Hz
valid values are 375000, 390000, 187500, 200000 valid values are 375000, 390000, 187500, 200000
93750, 97500, 46875 and 50000 93750, 97500, 46875 and 50000
......
...@@ -20,6 +20,10 @@ Optional properties: ...@@ -20,6 +20,10 @@ Optional properties:
propoerty indicates the default frequency 100 kHz. propoerty indicates the default frequency 100 kHz.
- clocks: clock specifier. - clocks: clock specifier.
- i2c-scl-falling-time-ns: see i2c.txt
- i2c-scl-internal-delay-ns: see i2c.txt
- i2c-scl-rising-time-ns: see i2c.txt
Examples : Examples :
i2c0: i2c@e6508000 { i2c0: i2c@e6508000 {
......
...@@ -29,12 +29,38 @@ Optional properties ...@@ -29,12 +29,38 @@ Optional properties
These properties may not be supported by all drivers. However, if a driver These properties may not be supported by all drivers. However, if a driver
wants to support one of the below features, it should adapt the bindings below. wants to support one of the below features, it should adapt the bindings below.
- clock-frequency - frequency of bus clock in Hz. - clock-frequency
- wakeup-source - device can be used as a wakeup source. frequency of bus clock in Hz.
- interrupts - interrupts used by the device. - i2c-scl-falling-time-ns
- interrupt-names - "irq" and "wakeup" names are recognized by I2C core, Number of nanoseconds the SCL signal takes to fall; t(f) in the I2C
other names are left to individual drivers. specification.
- i2c-scl-internal-delay-ns
Number of nanoseconds the IP core additionally needs to setup SCL.
- i2c-scl-rising-time-ns
Number of nanoseconds the SCL signal takes to rise; t(r) in the I2C
specification.
- i2c-sda-falling-time-ns
Number of nanoseconds the SDA signal takes to fall; t(f) in the I2C
specification.
- interrupts
interrupts used by the device.
- interrupt-names
"irq" and "wakeup" names are recognized by I2C core, other names are
left to individual drivers.
- multi-master
states that there is another master active on this bus. The OS can use
this information to adapt power management to keep the arbitration awake
all the time, for example.
- wakeup-source
device can be used as a wakeup source.
Binding may contain optional "interrupts" property, describing interrupts Binding may contain optional "interrupts" property, describing interrupts
used by the device. I2C core will assign "irq" interrupt (or the very first used by the device. I2C core will assign "irq" interrupt (or the very first
......
...@@ -22,21 +22,9 @@ adi,adxl345 Three-Axis Digital Accelerometer ...@@ -22,21 +22,9 @@ adi,adxl345 Three-Axis Digital Accelerometer
adi,adxl346 Three-Axis Digital Accelerometer (backward-compatibility value "adi,adxl345" must be listed too) adi,adxl346 Three-Axis Digital Accelerometer (backward-compatibility value "adi,adxl345" must be listed too)
ams,iaq-core AMS iAQ-Core VOC Sensor ams,iaq-core AMS iAQ-Core VOC Sensor
at,24c08 i2c serial eeprom (24cxx) at,24c08 i2c serial eeprom (24cxx)
atmel,24c00 i2c serial eeprom (24cxx)
atmel,24c01 i2c serial eeprom (24cxx)
atmel,24c02 i2c serial eeprom (24cxx)
atmel,24c04 i2c serial eeprom (24cxx)
atmel,24c16 i2c serial eeprom (24cxx)
atmel,24c32 i2c serial eeprom (24cxx)
atmel,24c64 i2c serial eeprom (24cxx)
atmel,24c128 i2c serial eeprom (24cxx)
atmel,24c256 i2c serial eeprom (24cxx)
atmel,24c512 i2c serial eeprom (24cxx)
atmel,24c1024 i2c serial eeprom (24cxx)
atmel,at97sc3204t i2c trusted platform module (TPM) atmel,at97sc3204t i2c trusted platform module (TPM)
capella,cm32181 CM32181: Ambient Light Sensor capella,cm32181 CM32181: Ambient Light Sensor
capella,cm3232 CM3232: Ambient Light Sensor capella,cm3232 CM3232: Ambient Light Sensor
catalyst,24c32 i2c serial eeprom
cirrus,cs42l51 Cirrus Logic CS42L51 audio codec cirrus,cs42l51 Cirrus Logic CS42L51 audio codec
dallas,ds1307 64 x 8, Serial, I2C Real-Time Clock dallas,ds1307 64 x 8, Serial, I2C Real-Time Clock
dallas,ds1338 I2C RTC with 56-Byte NV RAM dallas,ds1338 I2C RTC with 56-Byte NV RAM
...@@ -50,11 +38,13 @@ dallas,ds4510 CPU Supervisor with Nonvolatile Memory and Programmable I/O ...@@ -50,11 +38,13 @@ dallas,ds4510 CPU Supervisor with Nonvolatile Memory and Programmable I/O
dallas,ds75 Digital Thermometer and Thermostat dallas,ds75 Digital Thermometer and Thermostat
dlg,da9053 DA9053: flexible system level PMIC with multicore support dlg,da9053 DA9053: flexible system level PMIC with multicore support
dlg,da9063 DA9063: system PMIC for quad-core application processors dlg,da9063 DA9063: system PMIC for quad-core application processors
epson,rx8010 I2C-BUS INTERFACE REAL TIME CLOCK MODULE
epson,rx8025 High-Stability. I2C-Bus INTERFACE REAL TIME CLOCK MODULE epson,rx8025 High-Stability. I2C-Bus INTERFACE REAL TIME CLOCK MODULE
epson,rx8581 I2C-BUS INTERFACE REAL TIME CLOCK MODULE epson,rx8581 I2C-BUS INTERFACE REAL TIME CLOCK MODULE
fsl,mag3110 MAG3110: Xtrinsic High Accuracy, 3D Magnetometer fsl,mag3110 MAG3110: Xtrinsic High Accuracy, 3D Magnetometer
fsl,mc13892 MC13892: Power Management Integrated Circuit (PMIC) for i.MX35/51 fsl,mc13892 MC13892: Power Management Integrated Circuit (PMIC) for i.MX35/51
fsl,mma8450 MMA8450Q: Xtrinsic Low-power, 3-axis Xtrinsic Accelerometer fsl,mma8450 MMA8450Q: Xtrinsic Low-power, 3-axis Xtrinsic Accelerometer
fsl,mpl3115 MPL3115: Absolute Digital Pressure Sensor
fsl,mpr121 MPR121: Proximity Capacitive Touch Sensor Controller fsl,mpr121 MPR121: Proximity Capacitive Touch Sensor Controller
fsl,sgtl5000 SGTL5000: Ultra Low-Power Audio Codec fsl,sgtl5000 SGTL5000: Ultra Low-Power Audio Codec
gmt,g751 G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface gmt,g751 G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface
...@@ -81,7 +71,6 @@ ovti,ov5642 OV5642: Color CMOS QSXGA (5-megapixel) Image Sensor with OmniBSI an ...@@ -81,7 +71,6 @@ 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
pulsedlight,lidar-lite-v2 Pulsedlight LIDAR range-finding sensor pulsedlight,lidar-lite-v2 Pulsedlight LIDAR range-finding sensor
ramtron,24c64 i2c serial eeprom (24cxx)
ricoh,r2025sd I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC ricoh,r2025sd I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
ricoh,r2221tl 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
......
...@@ -617,6 +617,10 @@ const struct i2c_algorithm i2c_bit_algo = { ...@@ -617,6 +617,10 @@ const struct i2c_algorithm i2c_bit_algo = {
}; };
EXPORT_SYMBOL(i2c_bit_algo); EXPORT_SYMBOL(i2c_bit_algo);
const struct i2c_adapter_quirks i2c_bit_quirk_no_clk_stretch = {
.flags = I2C_AQ_NO_CLK_STRETCH,
};
/* /*
* registering functions to load algorithms at runtime * registering functions to load algorithms at runtime
*/ */
...@@ -635,6 +639,8 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap, ...@@ -635,6 +639,8 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap,
/* register new adapter to i2c module... */ /* register new adapter to i2c module... */
adap->algo = &i2c_bit_algo; adap->algo = &i2c_bit_algo;
adap->retries = 3; adap->retries = 3;
if (bit_adap->getscl == NULL)
adap->quirks = &i2c_bit_quirk_no_clk_stretch;
ret = add_adapter(adap); ret = add_adapter(adap);
if (ret < 0) if (ret < 0)
......
...@@ -516,7 +516,7 @@ config I2C_EFM32 ...@@ -516,7 +516,7 @@ config I2C_EFM32
config I2C_EG20T config I2C_EG20T
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C" tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C"
depends on PCI && (X86_32 || COMPILE_TEST) depends on PCI && (X86_32 || MIPS || COMPILE_TEST)
help help
This driver is for PCH(Platform controller Hub) I2C of EG20T which This driver is for PCH(Platform controller Hub) I2C of EG20T which
is an IOH(Input/Output Hub) for x86 embedded processor. is an IOH(Input/Output Hub) for x86 embedded processor.
...@@ -532,6 +532,7 @@ config I2C_EG20T ...@@ -532,6 +532,7 @@ config I2C_EG20T
config I2C_EMEV2 config I2C_EMEV2
tristate "EMMA Mobile series I2C adapter" tristate "EMMA Mobile series I2C adapter"
depends on HAVE_CLK depends on HAVE_CLK
select I2C_SLAVE
help help
If you say yes to this option, support will be included for the If you say yes to this option, support will be included for the
I2C interface on the Renesas Electronics EM/EV family of processors. I2C interface on the Renesas Electronics EM/EV family of processors.
...@@ -963,11 +964,11 @@ config I2C_XILINX ...@@ -963,11 +964,11 @@ config I2C_XILINX
will be called xilinx_i2c. will be called xilinx_i2c.
config I2C_XLR config I2C_XLR
tristate "XLR I2C support" tristate "Netlogic XLR and Sigma Designs I2C support"
depends on CPU_XLR depends on CPU_XLR || ARCH_TANGOX
help help
This driver enables support for the on-chip I2C interface of This driver enables support for the on-chip I2C interface of
the Netlogic XLR/XLS MIPS processors. the Netlogic XLR/XLS MIPS processors and Sigma Designs SOCs.
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-xlr. will be called i2c-xlr.
......
...@@ -64,6 +64,8 @@ ...@@ -64,6 +64,8 @@
#define AT91_TWI_IADR 0x000c /* Internal Address Register */ #define AT91_TWI_IADR 0x000c /* Internal Address Register */
#define AT91_TWI_CWGR 0x0010 /* Clock Waveform Generator Reg */ #define AT91_TWI_CWGR 0x0010 /* Clock Waveform Generator Reg */
#define AT91_TWI_CWGR_HOLD_MAX 0x1f
#define AT91_TWI_CWGR_HOLD(x) (((x) & AT91_TWI_CWGR_HOLD_MAX) << 24)
#define AT91_TWI_SR 0x0020 /* Status Register */ #define AT91_TWI_SR 0x0020 /* Status Register */
#define AT91_TWI_TXCOMP BIT(0) /* Transmission Complete */ #define AT91_TWI_TXCOMP BIT(0) /* Transmission Complete */
...@@ -110,6 +112,7 @@ struct at91_twi_pdata { ...@@ -110,6 +112,7 @@ struct at91_twi_pdata {
unsigned clk_offset; unsigned clk_offset;
bool has_unre_flag; bool has_unre_flag;
bool has_alt_cmd; bool has_alt_cmd;
bool has_hold_field;
struct at_dma_slave dma_slave; struct at_dma_slave dma_slave;
}; };
...@@ -187,10 +190,11 @@ static void at91_init_twi_bus(struct at91_twi_dev *dev) ...@@ -187,10 +190,11 @@ static void at91_init_twi_bus(struct at91_twi_dev *dev)
*/ */
static void at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk) static void at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
{ {
int ckdiv, cdiv, div; int ckdiv, cdiv, div, hold = 0;
struct at91_twi_pdata *pdata = dev->pdata; struct at91_twi_pdata *pdata = dev->pdata;
int offset = pdata->clk_offset; int offset = pdata->clk_offset;
int max_ckdiv = pdata->clk_max_div; int max_ckdiv = pdata->clk_max_div;
u32 twd_hold_time_ns = 0;
div = max(0, (int)DIV_ROUND_UP(clk_get_rate(dev->clk), div = max(0, (int)DIV_ROUND_UP(clk_get_rate(dev->clk),
2 * twi_clk) - offset); 2 * twi_clk) - offset);
...@@ -204,8 +208,33 @@ static void at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk) ...@@ -204,8 +208,33 @@ static void at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
cdiv = 255; cdiv = 255;
} }
dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv; if (pdata->has_hold_field) {
dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv); of_property_read_u32(dev->dev->of_node, "i2c-sda-hold-time-ns",
&twd_hold_time_ns);
/*
* hold time = HOLD + 3 x T_peripheral_clock
* Use clk rate in kHz to prevent overflows when computing
* hold.
*/
hold = DIV_ROUND_UP(twd_hold_time_ns
* (clk_get_rate(dev->clk) / 1000), 1000000);
hold -= 3;
if (hold < 0)
hold = 0;
if (hold > AT91_TWI_CWGR_HOLD_MAX) {
dev_warn(dev->dev,
"HOLD field set to its maximum value (%d instead of %d)\n",
AT91_TWI_CWGR_HOLD_MAX, hold);
hold = AT91_TWI_CWGR_HOLD_MAX;
}
}
dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv
| AT91_TWI_CWGR_HOLD(hold);
dev_dbg(dev->dev, "cdiv %d ckdiv %d hold %d (%d ns)\n",
cdiv, ckdiv, hold, twd_hold_time_ns);
} }
static void at91_twi_dma_cleanup(struct at91_twi_dev *dev) static void at91_twi_dma_cleanup(struct at91_twi_dev *dev)
...@@ -797,6 +826,7 @@ static struct at91_twi_pdata at91rm9200_config = { ...@@ -797,6 +826,7 @@ static struct at91_twi_pdata at91rm9200_config = {
.clk_offset = 3, .clk_offset = 3,
.has_unre_flag = true, .has_unre_flag = true,
.has_alt_cmd = false, .has_alt_cmd = false,
.has_hold_field = false,
}; };
static struct at91_twi_pdata at91sam9261_config = { static struct at91_twi_pdata at91sam9261_config = {
...@@ -804,6 +834,7 @@ static struct at91_twi_pdata at91sam9261_config = { ...@@ -804,6 +834,7 @@ static struct at91_twi_pdata at91sam9261_config = {
.clk_offset = 4, .clk_offset = 4,
.has_unre_flag = false, .has_unre_flag = false,
.has_alt_cmd = false, .has_alt_cmd = false,
.has_hold_field = false,
}; };
static struct at91_twi_pdata at91sam9260_config = { static struct at91_twi_pdata at91sam9260_config = {
...@@ -811,6 +842,7 @@ static struct at91_twi_pdata at91sam9260_config = { ...@@ -811,6 +842,7 @@ static struct at91_twi_pdata at91sam9260_config = {
.clk_offset = 4, .clk_offset = 4,
.has_unre_flag = false, .has_unre_flag = false,
.has_alt_cmd = false, .has_alt_cmd = false,
.has_hold_field = false,
}; };
static struct at91_twi_pdata at91sam9g20_config = { static struct at91_twi_pdata at91sam9g20_config = {
...@@ -818,6 +850,7 @@ static struct at91_twi_pdata at91sam9g20_config = { ...@@ -818,6 +850,7 @@ static struct at91_twi_pdata at91sam9g20_config = {
.clk_offset = 4, .clk_offset = 4,
.has_unre_flag = false, .has_unre_flag = false,
.has_alt_cmd = false, .has_alt_cmd = false,
.has_hold_field = false,
}; };
static struct at91_twi_pdata at91sam9g10_config = { static struct at91_twi_pdata at91sam9g10_config = {
...@@ -825,6 +858,7 @@ static struct at91_twi_pdata at91sam9g10_config = { ...@@ -825,6 +858,7 @@ static struct at91_twi_pdata at91sam9g10_config = {
.clk_offset = 4, .clk_offset = 4,
.has_unre_flag = false, .has_unre_flag = false,
.has_alt_cmd = false, .has_alt_cmd = false,
.has_hold_field = false,
}; };
static const struct platform_device_id at91_twi_devtypes[] = { static const struct platform_device_id at91_twi_devtypes[] = {
...@@ -854,6 +888,15 @@ static struct at91_twi_pdata at91sam9x5_config = { ...@@ -854,6 +888,15 @@ static struct at91_twi_pdata at91sam9x5_config = {
.clk_offset = 4, .clk_offset = 4,
.has_unre_flag = false, .has_unre_flag = false,
.has_alt_cmd = false, .has_alt_cmd = false,
.has_hold_field = false,
};
static struct at91_twi_pdata sama5d4_config = {
.clk_max_div = 7,
.clk_offset = 4,
.has_unre_flag = false,
.has_alt_cmd = false,
.has_hold_field = true,
}; };
static struct at91_twi_pdata sama5d2_config = { static struct at91_twi_pdata sama5d2_config = {
...@@ -861,6 +904,7 @@ static struct at91_twi_pdata sama5d2_config = { ...@@ -861,6 +904,7 @@ static struct at91_twi_pdata sama5d2_config = {
.clk_offset = 4, .clk_offset = 4,
.has_unre_flag = true, .has_unre_flag = true,
.has_alt_cmd = true, .has_alt_cmd = true,
.has_hold_field = true,
}; };
static const struct of_device_id atmel_twi_dt_ids[] = { static const struct of_device_id atmel_twi_dt_ids[] = {
...@@ -882,6 +926,9 @@ static const struct of_device_id atmel_twi_dt_ids[] = { ...@@ -882,6 +926,9 @@ static const struct of_device_id atmel_twi_dt_ids[] = {
}, { }, {
.compatible = "atmel,at91sam9x5-i2c", .compatible = "atmel,at91sam9x5-i2c",
.data = &at91sam9x5_config, .data = &at91sam9x5_config,
}, {
.compatible = "atmel,sama5d4-i2c",
.data = &sama5d4_config,
}, { }, {
.compatible = "atmel,sama5d2-i2c", .compatible = "atmel,sama5d2-i2c",
.data = &sama5d2_config, .data = &sama5d2_config,
......
...@@ -222,6 +222,15 @@ static const struct i2c_algorithm bcm2835_i2c_algo = { ...@@ -222,6 +222,15 @@ static const struct i2c_algorithm bcm2835_i2c_algo = {
.functionality = bcm2835_i2c_func, .functionality = bcm2835_i2c_func,
}; };
/*
* This HW was reported to have problems with clock stretching:
* http://www.advamation.com/knowhow/raspberrypi/rpi-i2c-bug.html
* https://www.raspberrypi.org/forums/viewtopic.php?p=146272
*/
static const struct i2c_adapter_quirks bcm2835_i2c_quirks = {
.flags = I2C_AQ_NO_CLK_STRETCH,
};
static int bcm2835_i2c_probe(struct platform_device *pdev) static int bcm2835_i2c_probe(struct platform_device *pdev)
{ {
struct bcm2835_i2c_dev *i2c_dev; struct bcm2835_i2c_dev *i2c_dev;
...@@ -293,6 +302,7 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) ...@@ -293,6 +302,7 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
adap->algo = &bcm2835_i2c_algo; adap->algo = &bcm2835_i2c_algo;
adap->dev.parent = &pdev->dev; adap->dev.parent = &pdev->dev;
adap->dev.of_node = pdev->dev.of_node; adap->dev.of_node = pdev->dev.of_node;
adap->quirks = &bcm2835_i2c_quirks;
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, 0); bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, 0);
......
...@@ -25,13 +25,16 @@ ...@@ -25,13 +25,16 @@
#include <linux/version.h> #include <linux/version.h>
#define N_DATA_REGS 8 #define N_DATA_REGS 8
#define N_DATA_BYTES (N_DATA_REGS * 4)
/* BSC count register field definitions */ /*
#define BSC_CNT_REG1_MASK 0x0000003f * PER_I2C/BSC count register mask depends on 1 byte/4 byte data register
* size. Cable modem and DSL SoCs with Peripheral i2c cores use 1 byte per
* data register whereas STB SoCs use 4 byte per data register transfer,
* account for this difference in total count per transaction and mask to
* use.
*/
#define BSC_CNT_REG1_MASK(nb) (nb == 1 ? GENMASK(3, 0) : GENMASK(5, 0))
#define BSC_CNT_REG1_SHIFT 0 #define BSC_CNT_REG1_SHIFT 0
#define BSC_CNT_REG2_MASK 0x00000fc0
#define BSC_CNT_REG2_SHIFT 6
/* BSC CTL register field definitions */ /* BSC CTL register field definitions */
#define BSC_CTL_REG_DTF_MASK 0x00000003 #define BSC_CTL_REG_DTF_MASK 0x00000003
...@@ -41,7 +44,7 @@ ...@@ -41,7 +44,7 @@
#define BSC_CTL_REG_INT_EN_SHIFT 6 #define BSC_CTL_REG_INT_EN_SHIFT 6
#define BSC_CTL_REG_DIV_CLK_MASK 0x00000080 #define BSC_CTL_REG_DIV_CLK_MASK 0x00000080
/* BSC_IIC_ENABLE r/w enable and interrupt field defintions */ /* BSC_IIC_ENABLE r/w enable and interrupt field definitions */
#define BSC_IIC_EN_RESTART_MASK 0x00000040 #define BSC_IIC_EN_RESTART_MASK 0x00000040
#define BSC_IIC_EN_NOSTART_MASK 0x00000020 #define BSC_IIC_EN_NOSTART_MASK 0x00000020
#define BSC_IIC_EN_NOSTOP_MASK 0x00000010 #define BSC_IIC_EN_NOSTOP_MASK 0x00000010
...@@ -169,6 +172,7 @@ struct brcmstb_i2c_dev { ...@@ -169,6 +172,7 @@ struct brcmstb_i2c_dev {
struct completion done; struct completion done;
bool is_suspended; bool is_suspended;
u32 clk_freq_hz; u32 clk_freq_hz;
int data_regsz;
}; };
/* register accessors for both be and le cpu arch */ /* register accessors for both be and le cpu arch */
...@@ -186,6 +190,16 @@ struct brcmstb_i2c_dev { ...@@ -186,6 +190,16 @@ struct brcmstb_i2c_dev {
#define bsc_writel(_dev, _val, _reg) \ #define bsc_writel(_dev, _val, _reg) \
__bsc_writel(_val, _dev->base + offsetof(struct bsc_regs, _reg)) __bsc_writel(_val, _dev->base + offsetof(struct bsc_regs, _reg))
static inline int brcmstb_i2c_get_xfersz(struct brcmstb_i2c_dev *dev)
{
return (N_DATA_REGS * dev->data_regsz);
}
static inline int brcmstb_i2c_get_data_regsz(struct brcmstb_i2c_dev *dev)
{
return dev->data_regsz;
}
static void brcmstb_i2c_enable_disable_irq(struct brcmstb_i2c_dev *dev, static void brcmstb_i2c_enable_disable_irq(struct brcmstb_i2c_dev *dev,
bool int_en) bool int_en)
{ {
...@@ -323,14 +337,16 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev, ...@@ -323,14 +337,16 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev,
u8 *buf, unsigned int len, u8 *buf, unsigned int len,
struct i2c_msg *pmsg) struct i2c_msg *pmsg)
{ {
int cnt, byte, rc; int cnt, byte, i, rc;
enum bsc_xfer_cmd cmd; enum bsc_xfer_cmd cmd;
u32 ctl_reg; u32 ctl_reg;
struct bsc_regs *pi2creg = dev->bsc_regmap; struct bsc_regs *pi2creg = dev->bsc_regmap;
int no_ack = pmsg->flags & I2C_M_IGNORE_NAK; int no_ack = pmsg->flags & I2C_M_IGNORE_NAK;
int data_regsz = brcmstb_i2c_get_data_regsz(dev);
int xfersz = brcmstb_i2c_get_xfersz(dev);
/* see if the transaction needs to check NACK conditions */ /* see if the transaction needs to check NACK conditions */
if (no_ack || len <= N_DATA_BYTES) { if (no_ack || len <= xfersz) {
cmd = (pmsg->flags & I2C_M_RD) ? CMD_RD_NOACK cmd = (pmsg->flags & I2C_M_RD) ? CMD_RD_NOACK
: CMD_WR_NOACK; : CMD_WR_NOACK;
pi2creg->ctlhi_reg |= BSC_CTLHI_REG_IGNORE_ACK_MASK; pi2creg->ctlhi_reg |= BSC_CTLHI_REG_IGNORE_ACK_MASK;
...@@ -348,20 +364,22 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev, ...@@ -348,20 +364,22 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev,
pi2creg->ctl_reg = ctl_reg | DTF_RD_MASK; pi2creg->ctl_reg = ctl_reg | DTF_RD_MASK;
/* set the read/write length */ /* set the read/write length */
bsc_writel(dev, BSC_CNT_REG1_MASK & (len << BSC_CNT_REG1_SHIFT), bsc_writel(dev, BSC_CNT_REG1_MASK(data_regsz) &
cnt_reg); (len << BSC_CNT_REG1_SHIFT), cnt_reg);
/* Write data into data_in register */ /* Write data into data_in register */
if (cmd == CMD_WR || cmd == CMD_WR_NOACK) { if (cmd == CMD_WR || cmd == CMD_WR_NOACK) {
for (cnt = 0; cnt < len; cnt += 4) { for (cnt = 0, i = 0; cnt < len; cnt += data_regsz, i++) {
u32 word = 0; u32 word = 0;
for (byte = 0; byte < 4; byte++) { for (byte = 0; byte < data_regsz; byte++) {
word >>= 8; word >>= BITS_PER_BYTE;
if ((cnt + byte) < len) if ((cnt + byte) < len)
word |= buf[cnt + byte] << 24; word |= buf[cnt + byte] <<
(BITS_PER_BYTE * (data_regsz - 1));
} }
bsc_writel(dev, word, data_in[cnt >> 2]); bsc_writel(dev, word, data_in[i]);
} }
} }
...@@ -373,14 +391,15 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev, ...@@ -373,14 +391,15 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev,
return rc; return rc;
} }
/* Read data from data_out register */
if (cmd == CMD_RD || cmd == CMD_RD_NOACK) { if (cmd == CMD_RD || cmd == CMD_RD_NOACK) {
for (cnt = 0; cnt < len; cnt += 4) { for (cnt = 0, i = 0; cnt < len; cnt += data_regsz, i++) {
u32 data = bsc_readl(dev, data_out[cnt >> 2]); u32 data = bsc_readl(dev, data_out[i]);
for (byte = 0; byte < 4 && for (byte = 0; byte < data_regsz &&
(byte + cnt) < len; byte++) { (byte + cnt) < len; byte++) {
buf[cnt + byte] = data & 0xff; buf[cnt + byte] = data & 0xff;
data >>= 8; data >>= BITS_PER_BYTE;
} }
} }
} }
...@@ -448,6 +467,7 @@ static int brcmstb_i2c_xfer(struct i2c_adapter *adapter, ...@@ -448,6 +467,7 @@ static int brcmstb_i2c_xfer(struct i2c_adapter *adapter,
int bytes_to_xfer; int bytes_to_xfer;
u8 *tmp_buf; u8 *tmp_buf;
int len = 0; int len = 0;
int xfersz = brcmstb_i2c_get_xfersz(dev);
if (dev->is_suspended) if (dev->is_suspended)
return -EBUSY; return -EBUSY;
...@@ -482,9 +502,9 @@ static int brcmstb_i2c_xfer(struct i2c_adapter *adapter, ...@@ -482,9 +502,9 @@ static int brcmstb_i2c_xfer(struct i2c_adapter *adapter,
/* Perform data transfer */ /* Perform data transfer */
while (len) { while (len) {
bytes_to_xfer = min(len, N_DATA_BYTES); bytes_to_xfer = min(len, xfersz);
if (len <= N_DATA_BYTES && i == (num - 1)) if (len <= xfersz && i == (num - 1))
brcmstb_set_i2c_start_stop(dev, brcmstb_set_i2c_start_stop(dev,
~(COND_START_STOP)); ~(COND_START_STOP));
...@@ -542,8 +562,12 @@ static void brcmstb_i2c_set_bus_speed(struct brcmstb_i2c_dev *dev) ...@@ -542,8 +562,12 @@ static void brcmstb_i2c_set_bus_speed(struct brcmstb_i2c_dev *dev)
static void brcmstb_i2c_set_bsc_reg_defaults(struct brcmstb_i2c_dev *dev) static void brcmstb_i2c_set_bsc_reg_defaults(struct brcmstb_i2c_dev *dev)
{ {
/* 4 byte data register */ if (brcmstb_i2c_get_data_regsz(dev) == sizeof(u32))
/* set 4 byte data in/out xfers */
dev->bsc_regmap->ctlhi_reg = BSC_CTLHI_REG_DATAREG_SIZE_MASK; dev->bsc_regmap->ctlhi_reg = BSC_CTLHI_REG_DATAREG_SIZE_MASK;
else
dev->bsc_regmap->ctlhi_reg &= ~BSC_CTLHI_REG_DATAREG_SIZE_MASK;
bsc_writel(dev, dev->bsc_regmap->ctlhi_reg, ctlhi_reg); bsc_writel(dev, dev->bsc_regmap->ctlhi_reg, ctlhi_reg);
/* set bus speed */ /* set bus speed */
brcmstb_i2c_set_bus_speed(dev); brcmstb_i2c_set_bus_speed(dev);
...@@ -608,6 +632,13 @@ static int brcmstb_i2c_probe(struct platform_device *pdev) ...@@ -608,6 +632,13 @@ static int brcmstb_i2c_probe(struct platform_device *pdev)
dev->clk_freq_hz = bsc_clk[0].hz; dev->clk_freq_hz = bsc_clk[0].hz;
} }
/* set the data in/out register size for compatible SoCs */
if (of_device_is_compatible(dev->device->of_node,
"brcmstb,brcmper-i2c"))
dev->data_regsz = sizeof(u8);
else
dev->data_regsz = sizeof(u32);
brcmstb_i2c_set_bsc_reg_defaults(dev); brcmstb_i2c_set_bsc_reg_defaults(dev);
/* Add the i2c adapter */ /* Add the i2c adapter */
...@@ -674,6 +705,7 @@ static SIMPLE_DEV_PM_OPS(brcmstb_i2c_pm, brcmstb_i2c_suspend, ...@@ -674,6 +705,7 @@ static SIMPLE_DEV_PM_OPS(brcmstb_i2c_pm, brcmstb_i2c_suspend,
static const struct of_device_id brcmstb_i2c_of_match[] = { static const struct of_device_id brcmstb_i2c_of_match[] = {
{.compatible = "brcm,brcmstb-i2c"}, {.compatible = "brcm,brcmstb-i2c"},
{.compatible = "brcm,brcmper-i2c"},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, brcmstb_i2c_of_match); MODULE_DEVICE_TABLE(of, brcmstb_i2c_of_match);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/pm_runtime.h>
/* Register offsets for the I2C device. */ /* Register offsets for the I2C device. */
#define CDNS_I2C_CR_OFFSET 0x00 /* Control Register, RW */ #define CDNS_I2C_CR_OFFSET 0x00 /* Control Register, RW */
...@@ -96,6 +97,8 @@ ...@@ -96,6 +97,8 @@
CDNS_I2C_IXR_COMP) CDNS_I2C_IXR_COMP)
#define CDNS_I2C_TIMEOUT msecs_to_jiffies(1000) #define CDNS_I2C_TIMEOUT msecs_to_jiffies(1000)
/* timeout for pm runtime autosuspend */
#define CNDS_I2C_PM_TIMEOUT 1000 /* ms */
#define CDNS_I2C_FIFO_DEPTH 16 #define CDNS_I2C_FIFO_DEPTH 16
/* FIFO depth at which the DATA interrupt occurs */ /* FIFO depth at which the DATA interrupt occurs */
...@@ -128,7 +131,6 @@ ...@@ -128,7 +131,6 @@
* @xfer_done: Transfer complete status * @xfer_done: Transfer complete status
* @p_send_buf: Pointer to transmit buffer * @p_send_buf: Pointer to transmit buffer
* @p_recv_buf: Pointer to receive buffer * @p_recv_buf: Pointer to receive buffer
* @suspended: Flag holding the device's PM status
* @send_count: Number of bytes still expected to send * @send_count: Number of bytes still expected to send
* @recv_count: Number of bytes still expected to receive * @recv_count: Number of bytes still expected to receive
* @curr_recv_count: Number of bytes to be received in current transfer * @curr_recv_count: Number of bytes to be received in current transfer
...@@ -141,6 +143,7 @@ ...@@ -141,6 +143,7 @@
* @quirks: flag for broken hold bit usage in r1p10 * @quirks: flag for broken hold bit usage in r1p10
*/ */
struct cdns_i2c { struct cdns_i2c {
struct device *dev;
void __iomem *membase; void __iomem *membase;
struct i2c_adapter adap; struct i2c_adapter adap;
struct i2c_msg *p_msg; struct i2c_msg *p_msg;
...@@ -148,7 +151,6 @@ struct cdns_i2c { ...@@ -148,7 +151,6 @@ struct cdns_i2c {
struct completion xfer_done; struct completion xfer_done;
unsigned char *p_send_buf; unsigned char *p_send_buf;
unsigned char *p_recv_buf; unsigned char *p_recv_buf;
u8 suspended;
unsigned int send_count; unsigned int send_count;
unsigned int recv_count; unsigned int recv_count;
unsigned int curr_recv_count; unsigned int curr_recv_count;
...@@ -569,9 +571,14 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, ...@@ -569,9 +571,14 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
struct cdns_i2c *id = adap->algo_data; struct cdns_i2c *id = adap->algo_data;
bool hold_quirk; bool hold_quirk;
ret = pm_runtime_get_sync(id->dev);
if (ret < 0)
return ret;
/* Check if the bus is free */ /* Check if the bus is free */
if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA) if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA) {
return -EAGAIN; ret = -EAGAIN;
goto out;
}
hold_quirk = !!(id->quirks & CDNS_I2C_BROKEN_HOLD_BIT); hold_quirk = !!(id->quirks & CDNS_I2C_BROKEN_HOLD_BIT);
/* /*
...@@ -590,7 +597,8 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, ...@@ -590,7 +597,8 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
if (msgs[count].flags & I2C_M_RD) { if (msgs[count].flags & I2C_M_RD) {
dev_warn(adap->dev.parent, dev_warn(adap->dev.parent,
"Can't do repeated start after a receive message\n"); "Can't do repeated start after a receive message\n");
return -EOPNOTSUPP; ret = -EOPNOTSUPP;
goto out;
} }
} }
id->bus_hold_flag = 1; id->bus_hold_flag = 1;
...@@ -608,20 +616,26 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, ...@@ -608,20 +616,26 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
ret = cdns_i2c_process_msg(id, msgs, adap); ret = cdns_i2c_process_msg(id, msgs, adap);
if (ret) if (ret)
return ret; goto out;
/* Report the other error interrupts to application */ /* Report the other error interrupts to application */
if (id->err_status) { if (id->err_status) {
cdns_i2c_master_reset(adap); cdns_i2c_master_reset(adap);
if (id->err_status & CDNS_I2C_IXR_NACK) if (id->err_status & CDNS_I2C_IXR_NACK) {
return -ENXIO; ret = -ENXIO;
goto out;
return -EIO; }
ret = -EIO;
goto out;
} }
} }
return num; ret = num;
out:
pm_runtime_mark_last_busy(id->dev);
pm_runtime_put_autosuspend(id->dev);
return ret;
} }
/** /**
...@@ -760,7 +774,7 @@ static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long ...@@ -760,7 +774,7 @@ static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
struct clk_notifier_data *ndata = data; struct clk_notifier_data *ndata = data;
struct cdns_i2c *id = to_cdns_i2c(nb); struct cdns_i2c *id = to_cdns_i2c(nb);
if (id->suspended) if (pm_runtime_suspended(id->dev))
return NOTIFY_OK; return NOTIFY_OK;
switch (event) { switch (event) {
...@@ -808,14 +822,12 @@ static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long ...@@ -808,14 +822,12 @@ static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
* *
* Return: 0 always * Return: 0 always
*/ */
static int __maybe_unused cdns_i2c_suspend(struct device *_dev) static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
{ {
struct platform_device *pdev = container_of(_dev, struct platform_device *pdev = to_platform_device(dev);
struct platform_device, dev);
struct cdns_i2c *xi2c = platform_get_drvdata(pdev); struct cdns_i2c *xi2c = platform_get_drvdata(pdev);
clk_disable(xi2c->clk); clk_disable(xi2c->clk);
xi2c->suspended = 1;
return 0; return 0;
} }
...@@ -828,26 +840,25 @@ static int __maybe_unused cdns_i2c_suspend(struct device *_dev) ...@@ -828,26 +840,25 @@ static int __maybe_unused cdns_i2c_suspend(struct device *_dev)
* *
* Return: 0 on success and error value on error * Return: 0 on success and error value on error
*/ */
static int __maybe_unused cdns_i2c_resume(struct device *_dev) static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev)
{ {
struct platform_device *pdev = container_of(_dev, struct platform_device *pdev = to_platform_device(dev);
struct platform_device, dev);
struct cdns_i2c *xi2c = platform_get_drvdata(pdev); struct cdns_i2c *xi2c = platform_get_drvdata(pdev);
int ret; int ret;
ret = clk_enable(xi2c->clk); ret = clk_enable(xi2c->clk);
if (ret) { if (ret) {
dev_err(_dev, "Cannot enable clock.\n"); dev_err(dev, "Cannot enable clock.\n");
return ret; return ret;
} }
xi2c->suspended = 0;
return 0; return 0;
} }
static SIMPLE_DEV_PM_OPS(cdns_i2c_dev_pm_ops, cdns_i2c_suspend, static const struct dev_pm_ops cdns_i2c_dev_pm_ops = {
cdns_i2c_resume); SET_RUNTIME_PM_OPS(cdns_i2c_runtime_suspend,
cdns_i2c_runtime_resume, NULL)
};
static const struct cdns_platform_data r1p10_i2c_def = { static const struct cdns_platform_data r1p10_i2c_def = {
.quirks = CDNS_I2C_BROKEN_HOLD_BIT, .quirks = CDNS_I2C_BROKEN_HOLD_BIT,
...@@ -881,6 +892,7 @@ static int cdns_i2c_probe(struct platform_device *pdev) ...@@ -881,6 +892,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
if (!id) if (!id)
return -ENOMEM; return -ENOMEM;
id->dev = &pdev->dev;
platform_set_drvdata(pdev, id); platform_set_drvdata(pdev, id);
match = of_match_node(cdns_i2c_of_match, pdev->dev.of_node); match = of_match_node(cdns_i2c_of_match, pdev->dev.of_node);
...@@ -913,10 +925,14 @@ static int cdns_i2c_probe(struct platform_device *pdev) ...@@ -913,10 +925,14 @@ static int cdns_i2c_probe(struct platform_device *pdev)
return PTR_ERR(id->clk); return PTR_ERR(id->clk);
} }
ret = clk_prepare_enable(id->clk); ret = clk_prepare_enable(id->clk);
if (ret) { if (ret)
dev_err(&pdev->dev, "Unable to enable clock.\n"); dev_err(&pdev->dev, "Unable to enable clock.\n");
return ret;
} pm_runtime_enable(id->dev);
pm_runtime_set_autosuspend_delay(id->dev, CNDS_I2C_PM_TIMEOUT);
pm_runtime_use_autosuspend(id->dev);
pm_runtime_set_active(id->dev);
id->clk_rate_change_nb.notifier_call = cdns_i2c_clk_notifier_cb; id->clk_rate_change_nb.notifier_call = cdns_i2c_clk_notifier_cb;
if (clk_notifier_register(id->clk, &id->clk_rate_change_nb)) if (clk_notifier_register(id->clk, &id->clk_rate_change_nb))
dev_warn(&pdev->dev, "Unable to register clock notifier.\n"); dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
...@@ -966,6 +982,8 @@ static int cdns_i2c_probe(struct platform_device *pdev) ...@@ -966,6 +982,8 @@ static int cdns_i2c_probe(struct platform_device *pdev)
err_clk_dis: err_clk_dis:
clk_disable_unprepare(id->clk); clk_disable_unprepare(id->clk);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return ret; return ret;
} }
...@@ -984,6 +1002,7 @@ static int cdns_i2c_remove(struct platform_device *pdev) ...@@ -984,6 +1002,7 @@ static int cdns_i2c_remove(struct platform_device *pdev)
i2c_del_adapter(&id->adap); i2c_del_adapter(&id->adap);
clk_notifier_unregister(id->clk, &id->clk_rate_change_nb); clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
clk_disable_unprepare(id->clk); clk_disable_unprepare(id->clk);
pm_runtime_disable(&pdev->dev);
return 0; return 0;
} }
......
...@@ -271,6 +271,17 @@ static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable) ...@@ -271,6 +271,17 @@ static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable)
enable ? "en" : "dis"); enable ? "en" : "dis");
} }
static unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev)
{
/*
* Clock is not necessary if we got LCNT/HCNT values directly from
* the platform code.
*/
if (WARN_ON_ONCE(!dev->get_clk_rate_khz))
return 0;
return dev->get_clk_rate_khz(dev);
}
/** /**
* i2c_dw_init() - initialize the designware i2c master hardware * i2c_dw_init() - initialize the designware i2c master hardware
* @dev: device private data * @dev: device private data
...@@ -281,7 +292,6 @@ static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable) ...@@ -281,7 +292,6 @@ static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable)
*/ */
int i2c_dw_init(struct dw_i2c_dev *dev) int i2c_dw_init(struct dw_i2c_dev *dev)
{ {
u32 input_clock_khz;
u32 hcnt, lcnt; u32 hcnt, lcnt;
u32 reg; u32 reg;
u32 sda_falling_time, scl_falling_time; u32 sda_falling_time, scl_falling_time;
...@@ -295,8 +305,6 @@ int i2c_dw_init(struct dw_i2c_dev *dev) ...@@ -295,8 +305,6 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
} }
} }
input_clock_khz = dev->get_clk_rate_khz(dev);
reg = dw_readl(dev, DW_IC_COMP_TYPE); reg = dw_readl(dev, DW_IC_COMP_TYPE);
if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) { if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) {
/* Configure register endianess access */ /* Configure register endianess access */
...@@ -325,12 +333,12 @@ int i2c_dw_init(struct dw_i2c_dev *dev) ...@@ -325,12 +333,12 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
hcnt = dev->ss_hcnt; hcnt = dev->ss_hcnt;
lcnt = dev->ss_lcnt; lcnt = dev->ss_lcnt;
} else { } else {
hcnt = i2c_dw_scl_hcnt(input_clock_khz, hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev),
4000, /* tHD;STA = tHIGH = 4.0 us */ 4000, /* tHD;STA = tHIGH = 4.0 us */
sda_falling_time, sda_falling_time,
0, /* 0: DW default, 1: Ideal */ 0, /* 0: DW default, 1: Ideal */
0); /* No offset */ 0); /* No offset */
lcnt = i2c_dw_scl_lcnt(input_clock_khz, lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev),
4700, /* tLOW = 4.7 us */ 4700, /* tLOW = 4.7 us */
scl_falling_time, scl_falling_time,
0); /* No offset */ 0); /* No offset */
...@@ -344,12 +352,12 @@ int i2c_dw_init(struct dw_i2c_dev *dev) ...@@ -344,12 +352,12 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
hcnt = dev->fs_hcnt; hcnt = dev->fs_hcnt;
lcnt = dev->fs_lcnt; lcnt = dev->fs_lcnt;
} else { } else {
hcnt = i2c_dw_scl_hcnt(input_clock_khz, hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev),
600, /* tHD;STA = tHIGH = 0.6 us */ 600, /* tHD;STA = tHIGH = 0.6 us */
sda_falling_time, sda_falling_time,
0, /* 0: DW default, 1: Ideal */ 0, /* 0: DW default, 1: Ideal */
0); /* No offset */ 0); /* No offset */
lcnt = i2c_dw_scl_lcnt(input_clock_khz, lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev),
1300, /* tLOW = 1.3 us */ 1300, /* tLOW = 1.3 us */
scl_falling_time, scl_falling_time,
0); /* No offset */ 0); /* No offset */
...@@ -860,6 +868,7 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) ...@@ -860,6 +868,7 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
snprintf(adap->name, sizeof(adap->name), snprintf(adap->name, sizeof(adap->name),
"Synopsys DesignWare I2C adapter"); "Synopsys DesignWare I2C adapter");
adap->retries = 3;
adap->algo = &i2c_dw_algo; adap->algo = &i2c_dw_algo;
adap->dev.parent = dev->dev; adap->dev.parent = dev->dev;
i2c_set_adapdata(adap, dev); i2c_set_adapdata(adap, dev);
......
...@@ -162,7 +162,7 @@ static struct dw_pci_controller dw_pci_controllers[] = { ...@@ -162,7 +162,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int i2c_dw_pci_suspend(struct device *dev) static int i2c_dw_pci_suspend(struct device *dev)
{ {
struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); struct pci_dev *pdev = to_pci_dev(dev);
i2c_dw_disable(pci_get_drvdata(pdev)); i2c_dw_disable(pci_get_drvdata(pdev));
return 0; return 0;
...@@ -170,7 +170,7 @@ static int i2c_dw_pci_suspend(struct device *dev) ...@@ -170,7 +170,7 @@ static int i2c_dw_pci_suspend(struct device *dev)
static int i2c_dw_pci_resume(struct device *dev) static int i2c_dw_pci_resume(struct device *dev)
{ {
struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); struct pci_dev *pdev = to_pci_dev(dev);
return i2c_dw_init(pci_get_drvdata(pdev)); return i2c_dw_init(pci_get_drvdata(pdev));
} }
......
...@@ -123,6 +123,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = { ...@@ -123,6 +123,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "80860F41", 0 }, { "80860F41", 0 },
{ "808622C1", 0 }, { "808622C1", 0 },
{ "AMD0010", ACCESS_INTR_MASK }, { "AMD0010", ACCESS_INTR_MASK },
{ "AMDI0510", 0 },
{ "APMC0D0F", 0 }, { "APMC0D0F", 0 },
{ } { }
}; };
...@@ -134,6 +135,18 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev) ...@@ -134,6 +135,18 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
} }
#endif #endif
static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare)
{
if (IS_ERR(i_dev->clk))
return PTR_ERR(i_dev->clk);
if (prepare)
return clk_prepare_enable(i_dev->clk);
clk_disable_unprepare(i_dev->clk);
return 0;
}
static int dw_i2c_plat_probe(struct platform_device *pdev) static int dw_i2c_plat_probe(struct platform_device *pdev)
{ {
struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev); struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
...@@ -206,15 +219,12 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) ...@@ -206,15 +219,12 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST; DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
dev->clk = devm_clk_get(&pdev->dev, NULL); dev->clk = devm_clk_get(&pdev->dev, NULL);
if (!i2c_dw_plat_prepare_clk(dev, true)) {
dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
if (IS_ERR(dev->clk))
return PTR_ERR(dev->clk);
clk_prepare_enable(dev->clk);
if (!dev->sda_hold_time && ht) { if (!dev->sda_hold_time && ht)
u32 ic_clk = dev->get_clk_rate_khz(dev); dev->sda_hold_time = div_u64(
(u64)dev->get_clk_rate_khz(dev) * ht + 500000,
dev->sda_hold_time = div_u64((u64)ic_clk * ht + 500000,
1000000); 1000000);
} }
...@@ -297,7 +307,7 @@ static int dw_i2c_plat_suspend(struct device *dev) ...@@ -297,7 +307,7 @@ static int dw_i2c_plat_suspend(struct device *dev)
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev); struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
i2c_dw_disable(i_dev); i2c_dw_disable(i_dev);
clk_disable_unprepare(i_dev->clk); i2c_dw_plat_prepare_clk(i_dev, false);
return 0; return 0;
} }
...@@ -307,7 +317,7 @@ static int dw_i2c_plat_resume(struct device *dev) ...@@ -307,7 +317,7 @@ static int dw_i2c_plat_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev); struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
clk_prepare_enable(i_dev->clk); i2c_dw_plat_prepare_clk(i_dev, true);
if (!i_dev->pm_runtime_disabled) if (!i_dev->pm_runtime_disabled)
i2c_dw_init(i_dev); i2c_dw_init(i_dev);
......
...@@ -795,6 +795,7 @@ static int pch_i2c_probe(struct pci_dev *pdev, ...@@ -795,6 +795,7 @@ static int pch_i2c_probe(struct pci_dev *pdev,
/* base_addr + offset; */ /* base_addr + offset; */
adap_info->pch_data[i].pch_base_address = base_addr + 0x100 * i; adap_info->pch_data[i].pch_base_address = base_addr + 0x100 * i;
pch_adap->dev.of_node = pdev->dev.of_node;
pch_adap->dev.parent = &pdev->dev; pch_adap->dev.parent = &pdev->dev;
pch_i2c_init(&adap_info->pch_data[i]); pch_i2c_init(&adap_info->pch_data[i]);
......
...@@ -71,6 +71,7 @@ struct em_i2c_device { ...@@ -71,6 +71,7 @@ struct em_i2c_device {
struct i2c_adapter adap; struct i2c_adapter adap;
struct completion msg_done; struct completion msg_done;
struct clk *sclk; struct clk *sclk;
struct i2c_client *slave;
}; };
static inline void em_clear_set_bit(struct em_i2c_device *priv, u8 clear, u8 set, u8 reg) static inline void em_clear_set_bit(struct em_i2c_device *priv, u8 clear, u8 set, u8 reg)
...@@ -226,22 +227,131 @@ static int em_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, ...@@ -226,22 +227,131 @@ static int em_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
return num; return num;
} }
static bool em_i2c_slave_irq(struct em_i2c_device *priv)
{
u8 status, value;
enum i2c_slave_event event;
int ret;
if (!priv->slave)
return false;
status = readb(priv->base + I2C_OFS_IICSE0);
/* Extension code, do not participate */
if (status & I2C_BIT_EXC0) {
em_clear_set_bit(priv, 0, I2C_BIT_LREL0, I2C_OFS_IICC0);
return true;
}
/* Stop detected, we don't know if it's for slave or master */
if (status & I2C_BIT_SPD0) {
/* Notify slave device */
i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value);
/* Pretend we did not handle the interrupt */
return false;
}
/* Only handle interrupts addressed to us */
if (!(status & I2C_BIT_COI0))
return false;
/* Enable stop interrupts */
em_clear_set_bit(priv, 0, I2C_BIT_SPIE0, I2C_OFS_IICC0);
/* Transmission or Reception */
if (status & I2C_BIT_TRC0) {
if (status & I2C_BIT_ACKD0) {
/* 9 bit interrupt mode */
em_clear_set_bit(priv, 0, I2C_BIT_WTIM0, I2C_OFS_IICC0);
/* Send data */
event = status & I2C_BIT_STD0 ?
I2C_SLAVE_READ_REQUESTED :
I2C_SLAVE_READ_PROCESSED;
i2c_slave_event(priv->slave, event, &value);
writeb(value, priv->base + I2C_OFS_IIC0);
} else {
/* NACK, stop transmitting */
em_clear_set_bit(priv, 0, I2C_BIT_LREL0, I2C_OFS_IICC0);
}
} else {
/* 8 bit interrupt mode */
em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_ACKE0,
I2C_OFS_IICC0);
em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_WREL0,
I2C_OFS_IICC0);
if (status & I2C_BIT_STD0) {
i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED,
&value);
} else {
/* Recv data */
value = readb(priv->base + I2C_OFS_IIC0);
ret = i2c_slave_event(priv->slave,
I2C_SLAVE_WRITE_RECEIVED, &value);
if (ret < 0)
em_clear_set_bit(priv, I2C_BIT_ACKE0, 0,
I2C_OFS_IICC0);
}
}
return true;
}
static irqreturn_t em_i2c_irq_handler(int this_irq, void *dev_id) static irqreturn_t em_i2c_irq_handler(int this_irq, void *dev_id)
{ {
struct em_i2c_device *priv = dev_id; struct em_i2c_device *priv = dev_id;
if (em_i2c_slave_irq(priv))
return IRQ_HANDLED;
complete(&priv->msg_done); complete(&priv->msg_done);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static u32 em_i2c_func(struct i2c_adapter *adap) static u32 em_i2c_func(struct i2c_adapter *adap)
{ {
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SLAVE;
}
static int em_i2c_reg_slave(struct i2c_client *slave)
{
struct em_i2c_device *priv = i2c_get_adapdata(slave->adapter);
if (priv->slave)
return -EBUSY;
if (slave->flags & I2C_CLIENT_TEN)
return -EAFNOSUPPORT;
priv->slave = slave;
/* Set slave address */
writeb(slave->addr << 1, priv->base + I2C_OFS_SVA0);
return 0;
}
static int em_i2c_unreg_slave(struct i2c_client *slave)
{
struct em_i2c_device *priv = i2c_get_adapdata(slave->adapter);
WARN_ON(!priv->slave);
writeb(0, priv->base + I2C_OFS_SVA0);
priv->slave = NULL;
return 0;
} }
static struct i2c_algorithm em_i2c_algo = { static struct i2c_algorithm em_i2c_algo = {
.master_xfer = em_i2c_xfer, .master_xfer = em_i2c_xfer,
.functionality = em_i2c_func, .functionality = em_i2c_func,
.reg_slave = em_i2c_reg_slave,
.unreg_slave = em_i2c_unreg_slave,
}; };
static int em_i2c_probe(struct platform_device *pdev) static int em_i2c_probe(struct platform_device *pdev)
......
...@@ -99,7 +99,7 @@ static void dump_iic_regs(const char* header, struct ibm_iic_private* dev) ...@@ -99,7 +99,7 @@ static void dump_iic_regs(const char* header, struct ibm_iic_private* dev)
#endif #endif
/* Bus timings (in ns) for bit-banging */ /* Bus timings (in ns) for bit-banging */
static struct i2c_timings { static struct ibm_iic_timings {
unsigned int hd_sta; unsigned int hd_sta;
unsigned int su_sto; unsigned int su_sto;
unsigned int low; unsigned int low;
...@@ -241,7 +241,7 @@ static int iic_dc_wait(volatile struct iic_regs __iomem *iic, u8 mask) ...@@ -241,7 +241,7 @@ static int iic_dc_wait(volatile struct iic_regs __iomem *iic, u8 mask)
static int iic_smbus_quick(struct ibm_iic_private* dev, const struct i2c_msg* p) static int iic_smbus_quick(struct ibm_iic_private* dev, const struct i2c_msg* p)
{ {
volatile struct iic_regs __iomem *iic = dev->vaddr; volatile struct iic_regs __iomem *iic = dev->vaddr;
const struct i2c_timings* t = &timings[dev->fast_mode ? 1 : 0]; const struct ibm_iic_timings *t = &timings[dev->fast_mode ? 1 : 0];
u8 mask, v, sda; u8 mask, v, sda;
int i, res; int i, res;
......
...@@ -151,10 +151,11 @@ ...@@ -151,10 +151,11 @@
#define INT_FIFO_EMPTYING BIT(12) #define INT_FIFO_EMPTYING BIT(12)
#define INT_TRANSACTION_DONE BIT(15) #define INT_TRANSACTION_DONE BIT(15)
#define INT_SLAVE_EVENT BIT(16) #define INT_SLAVE_EVENT BIT(16)
#define INT_MASTER_HALTED BIT(17)
#define INT_TIMING BIT(18) #define INT_TIMING BIT(18)
#define INT_STOP_DETECTED BIT(19)
#define INT_FIFO_FULL_FILLING (INT_FIFO_FULL | INT_FIFO_FILLING) #define INT_FIFO_FULL_FILLING (INT_FIFO_FULL | INT_FIFO_FILLING)
#define INT_FIFO_EMPTY_EMPTYING (INT_FIFO_EMPTY | INT_FIFO_EMPTYING)
/* Level interrupts need clearing after handling instead of before */ /* Level interrupts need clearing after handling instead of before */
#define INT_LEVEL 0x01e00 #define INT_LEVEL 0x01e00
...@@ -177,7 +178,8 @@ ...@@ -177,7 +178,8 @@
INT_FIFO_FULL | \ INT_FIFO_FULL | \
INT_FIFO_FILLING | \ INT_FIFO_FILLING | \
INT_FIFO_EMPTY | \ INT_FIFO_EMPTY | \
INT_FIFO_EMPTYING) INT_MASTER_HALTED | \
INT_STOP_DETECTED)
#define INT_ENABLE_MASK_WAITSTOP (INT_SLAVE_EVENT | \ #define INT_ENABLE_MASK_WAITSTOP (INT_SLAVE_EVENT | \
INT_ADDR_ACK_ERR | \ INT_ADDR_ACK_ERR | \
...@@ -511,7 +513,17 @@ static void img_i2c_soft_reset(struct img_i2c *i2c) ...@@ -511,7 +513,17 @@ static void img_i2c_soft_reset(struct img_i2c *i2c)
SCB_CONTROL_CLK_ENABLE | SCB_CONTROL_SOFT_RESET); SCB_CONTROL_CLK_ENABLE | SCB_CONTROL_SOFT_RESET);
} }
/* enable or release transaction halt for control of repeated starts */ /*
* Enable or release transaction halt for control of repeated starts.
* In version 3.3 of the IP when transaction halt is set, an interrupt
* will be generated after each byte of a transfer instead of after
* every transfer but before the stop bit.
* Due to this behaviour we have to be careful that every time we
* release the transaction halt we have to re-enable it straight away
* so that we only process a single byte, not doing so will result in
* all remaining bytes been processed and a stop bit being issued,
* which will prevent us having a repeated start.
*/
static void img_i2c_transaction_halt(struct img_i2c *i2c, bool t_halt) static void img_i2c_transaction_halt(struct img_i2c *i2c, bool t_halt)
{ {
u32 val; u32 val;
...@@ -580,7 +592,6 @@ static void img_i2c_read(struct img_i2c *i2c) ...@@ -580,7 +592,6 @@ static void img_i2c_read(struct img_i2c *i2c)
img_i2c_writel(i2c, SCB_READ_ADDR_REG, i2c->msg.addr); img_i2c_writel(i2c, SCB_READ_ADDR_REG, i2c->msg.addr);
img_i2c_writel(i2c, SCB_READ_COUNT_REG, i2c->msg.len); img_i2c_writel(i2c, SCB_READ_COUNT_REG, i2c->msg.len);
img_i2c_transaction_halt(i2c, false);
mod_timer(&i2c->check_timer, jiffies + msecs_to_jiffies(1)); mod_timer(&i2c->check_timer, jiffies + msecs_to_jiffies(1));
} }
...@@ -594,7 +605,6 @@ static void img_i2c_write(struct img_i2c *i2c) ...@@ -594,7 +605,6 @@ static void img_i2c_write(struct img_i2c *i2c)
img_i2c_writel(i2c, SCB_WRITE_ADDR_REG, i2c->msg.addr); img_i2c_writel(i2c, SCB_WRITE_ADDR_REG, i2c->msg.addr);
img_i2c_writel(i2c, SCB_WRITE_COUNT_REG, i2c->msg.len); img_i2c_writel(i2c, SCB_WRITE_COUNT_REG, i2c->msg.len);
img_i2c_transaction_halt(i2c, false);
mod_timer(&i2c->check_timer, jiffies + msecs_to_jiffies(1)); mod_timer(&i2c->check_timer, jiffies + msecs_to_jiffies(1));
img_i2c_write_fifo(i2c); img_i2c_write_fifo(i2c);
...@@ -750,7 +760,9 @@ static unsigned int img_i2c_atomic(struct img_i2c *i2c, ...@@ -750,7 +760,9 @@ static unsigned int img_i2c_atomic(struct img_i2c *i2c,
next_cmd = CMD_RET_ACK; next_cmd = CMD_RET_ACK;
break; break;
case CMD_RET_ACK: case CMD_RET_ACK:
if (i2c->line_status & LINESTAT_ACK_DET) { if (i2c->line_status & LINESTAT_ACK_DET ||
(i2c->line_status & LINESTAT_NACK_DET &&
i2c->msg.flags & I2C_M_IGNORE_NAK)) {
if (i2c->msg.len == 0) { if (i2c->msg.len == 0) {
next_cmd = CMD_GEN_STOP; next_cmd = CMD_GEN_STOP;
} else if (i2c->msg.flags & I2C_M_RD) { } else if (i2c->msg.flags & I2C_M_RD) {
...@@ -858,34 +870,42 @@ static unsigned int img_i2c_auto(struct img_i2c *i2c, ...@@ -858,34 +870,42 @@ static unsigned int img_i2c_auto(struct img_i2c *i2c,
/* Enable transaction halt on start bit */ /* Enable transaction halt on start bit */
if (!i2c->last_msg && line_status & LINESTAT_START_BIT_DET) { if (!i2c->last_msg && line_status & LINESTAT_START_BIT_DET) {
img_i2c_transaction_halt(i2c, true); img_i2c_transaction_halt(i2c, !i2c->last_msg);
/* we're no longer interested in the slave event */ /* we're no longer interested in the slave event */
i2c->int_enable &= ~INT_SLAVE_EVENT; i2c->int_enable &= ~INT_SLAVE_EVENT;
} }
mod_timer(&i2c->check_timer, jiffies + msecs_to_jiffies(1)); mod_timer(&i2c->check_timer, jiffies + msecs_to_jiffies(1));
if (int_status & INT_STOP_DETECTED) {
/* Drain remaining data in FIFO and complete transaction */
if (i2c->msg.flags & I2C_M_RD)
img_i2c_read_fifo(i2c);
return ISR_COMPLETE(0);
}
if (i2c->msg.flags & I2C_M_RD) { if (i2c->msg.flags & I2C_M_RD) {
if (int_status & INT_FIFO_FULL_FILLING) { if (int_status & (INT_FIFO_FULL_FILLING | INT_MASTER_HALTED)) {
img_i2c_read_fifo(i2c); img_i2c_read_fifo(i2c);
if (i2c->msg.len == 0) if (i2c->msg.len == 0)
return ISR_WAITSTOP; return ISR_WAITSTOP;
} }
} else { } else {
if (int_status & INT_FIFO_EMPTY_EMPTYING) { if (int_status & (INT_FIFO_EMPTY | INT_MASTER_HALTED)) {
/*
* The write fifo empty indicates that we're in the
* last byte so it's safe to start a new write
* transaction without losing any bytes from the
* previous one.
* see 2.3.7 Repeated Start Transactions.
*/
if ((int_status & INT_FIFO_EMPTY) && if ((int_status & INT_FIFO_EMPTY) &&
i2c->msg.len == 0) i2c->msg.len == 0)
return ISR_WAITSTOP; return ISR_WAITSTOP;
img_i2c_write_fifo(i2c); img_i2c_write_fifo(i2c);
} }
} }
if (int_status & INT_MASTER_HALTED) {
/*
* Release and then enable transaction halt, to
* allow only a single byte to proceed.
*/
img_i2c_transaction_halt(i2c, false);
img_i2c_transaction_halt(i2c, !i2c->last_msg);
}
return 0; return 0;
} }
...@@ -1017,19 +1037,22 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, ...@@ -1017,19 +1037,22 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
return -EIO; return -EIO;
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
if (likely(msgs[i].len))
continue;
/* /*
* 0 byte reads are not possible because the slave could try * 0 byte reads are not possible because the slave could try
* and pull the data line low, preventing a stop bit. * and pull the data line low, preventing a stop bit.
*/ */
if (unlikely(msgs[i].flags & I2C_M_RD)) if (!msgs[i].len && msgs[i].flags & I2C_M_RD)
return -EIO; return -EIO;
/* /*
* 0 byte writes are possible and used for probing, but we * 0 byte writes are possible and used for probing, but we
* cannot do them in automatic mode, so use atomic mode * cannot do them in automatic mode, so use atomic mode
* instead. * instead.
*
* Also, the I2C_M_IGNORE_NAK mode can only be implemented
* in atomic mode.
*/ */
if (!msgs[i].len ||
(msgs[i].flags & I2C_M_IGNORE_NAK))
atomic = true; atomic = true;
} }
...@@ -1069,12 +1092,31 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, ...@@ -1069,12 +1092,31 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
img_i2c_writel(i2c, SCB_INT_CLEAR_REG, ~0); img_i2c_writel(i2c, SCB_INT_CLEAR_REG, ~0);
img_i2c_writel(i2c, SCB_CLEAR_REG, ~0); img_i2c_writel(i2c, SCB_CLEAR_REG, ~0);
if (atomic) if (atomic) {
img_i2c_atomic_start(i2c); img_i2c_atomic_start(i2c);
else if (msg->flags & I2C_M_RD) } else {
/*
* Enable transaction halt if not the last message in
* the queue so that we can control repeated starts.
*/
img_i2c_transaction_halt(i2c, !i2c->last_msg);
if (msg->flags & I2C_M_RD)
img_i2c_read(i2c); img_i2c_read(i2c);
else else
img_i2c_write(i2c); img_i2c_write(i2c);
/*
* Release and then enable transaction halt, to
* allow only a single byte to proceed.
* This doesn't have an effect on the initial transfer
* but will allow the following transfers to start
* processing if the previous transfer was marked as
* complete while the i2c block was halted.
*/
img_i2c_transaction_halt(i2c, false);
img_i2c_transaction_halt(i2c, !i2c->last_msg);
}
spin_unlock_irqrestore(&i2c->lock, flags); spin_unlock_irqrestore(&i2c->lock, flags);
time_left = wait_for_completion_timeout(&i2c->msg_complete, time_left = wait_for_completion_timeout(&i2c->msg_complete,
......
...@@ -29,9 +29,6 @@ ...@@ -29,9 +29,6 @@
* *
*/ */
/** Includes *******************************************************************
*******************************************************************************/
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -53,12 +50,10 @@ ...@@ -53,12 +50,10 @@
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/platform_data/i2c-imx.h> #include <linux/platform_data/i2c-imx.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
/** Defines ********************************************************************
*******************************************************************************/
/* This will be the driver name the kernel reports */ /* This will be the driver name the kernel reports */
#define DRIVER_NAME "imx-i2c" #define DRIVER_NAME "imx-i2c"
...@@ -120,8 +115,7 @@ ...@@ -120,8 +115,7 @@
#define I2CR_IEN_OPCODE_0 0x0 #define I2CR_IEN_OPCODE_0 0x0
#define I2CR_IEN_OPCODE_1 I2CR_IEN #define I2CR_IEN_OPCODE_1 I2CR_IEN
/** Variables ****************************************************************** #define I2C_PM_TIMEOUT 10 /* ms */
*******************************************************************************/
/* /*
* sorted list of clock divider, register value pairs * sorted list of clock divider, register value pairs
...@@ -346,7 +340,7 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, ...@@ -346,7 +340,7 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
dma_release_channel(dma->chan_tx); dma_release_channel(dma->chan_tx);
fail_al: fail_al:
devm_kfree(dev, dma); devm_kfree(dev, dma);
dev_info(dev, "can't use DMA\n"); dev_info(dev, "can't use DMA, using PIO instead.\n");
} }
static void i2c_imx_dma_callback(void *arg) static void i2c_imx_dma_callback(void *arg)
...@@ -393,6 +387,7 @@ static int i2c_imx_dma_xfer(struct imx_i2c_struct *i2c_imx, ...@@ -393,6 +387,7 @@ static int i2c_imx_dma_xfer(struct imx_i2c_struct *i2c_imx,
return 0; return 0;
err_submit: err_submit:
dmaengine_terminate_all(dma->chan_using);
err_desc: err_desc:
dma_unmap_single(chan_dev, dma->dma_buf, dma_unmap_single(chan_dev, dma->dma_buf,
dma->dma_len, dma->dma_data_dir); dma->dma_len, dma->dma_data_dir);
...@@ -416,9 +411,6 @@ static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx) ...@@ -416,9 +411,6 @@ static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx)
dma->chan_using = NULL; dma->chan_using = NULL;
} }
/** Functions for IMX I2C adapter driver ***************************************
*******************************************************************************/
static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy) static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)
{ {
unsigned long orig_jiffies = jiffies; unsigned long orig_jiffies = jiffies;
...@@ -527,9 +519,6 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) ...@@ -527,9 +519,6 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
i2c_imx_set_clk(i2c_imx); i2c_imx_set_clk(i2c_imx);
result = clk_prepare_enable(i2c_imx->clk);
if (result)
return result;
imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR); imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR);
/* Enable I2C controller */ /* Enable I2C controller */
imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR); imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
...@@ -582,7 +571,6 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx) ...@@ -582,7 +571,6 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
/* Disable I2C controller */ /* Disable I2C controller */
temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
clk_disable_unprepare(i2c_imx->clk);
} }
static irqreturn_t i2c_imx_isr(int irq, void *dev_id) static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
...@@ -901,6 +889,10 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, ...@@ -901,6 +889,10 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
result = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
if (result < 0)
goto out;
/* Start I2C transfer */ /* Start I2C transfer */
result = i2c_imx_start(i2c_imx); result = i2c_imx_start(i2c_imx);
if (result) { if (result) {
...@@ -964,6 +956,10 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, ...@@ -964,6 +956,10 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
/* Stop I2C transfer */ /* Stop I2C transfer */
i2c_imx_stop(i2c_imx); i2c_imx_stop(i2c_imx);
pm_runtime_mark_last_busy(i2c_imx->adapter.dev.parent);
pm_runtime_put_autosuspend(i2c_imx->adapter.dev.parent);
out:
dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__, dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__,
(result < 0) ? "error" : "success msg", (result < 0) ? "error" : "success msg",
(result < 0) ? result : num); (result < 0) ? result : num);
...@@ -997,10 +993,8 @@ static void i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx, ...@@ -997,10 +993,8 @@ static void i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
PINCTRL_STATE_DEFAULT); PINCTRL_STATE_DEFAULT);
i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl,
"gpio"); "gpio");
rinfo->sda_gpio = of_get_named_gpio_flags(pdev->dev.of_node, rinfo->sda_gpio = of_get_named_gpio(pdev->dev.of_node, "sda-gpios", 0);
"sda-gpios", 0, NULL); rinfo->scl_gpio = of_get_named_gpio(pdev->dev.of_node, "scl-gpios", 0);
rinfo->scl_gpio = of_get_named_gpio_flags(pdev->dev.of_node,
"scl-gpios", 0, NULL);
if (!gpio_is_valid(rinfo->sda_gpio) || if (!gpio_is_valid(rinfo->sda_gpio) ||
!gpio_is_valid(rinfo->scl_gpio) || !gpio_is_valid(rinfo->scl_gpio) ||
...@@ -1083,7 +1077,7 @@ static int i2c_imx_probe(struct platform_device *pdev) ...@@ -1083,7 +1077,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
ret = clk_prepare_enable(i2c_imx->clk); ret = clk_prepare_enable(i2c_imx->clk);
if (ret) { if (ret) {
dev_err(&pdev->dev, "can't enable I2C clock\n"); dev_err(&pdev->dev, "can't enable I2C clock, ret=%d\n", ret);
return ret; return ret;
} }
...@@ -1107,6 +1101,18 @@ static int i2c_imx_probe(struct platform_device *pdev) ...@@ -1107,6 +1101,18 @@ static int i2c_imx_probe(struct platform_device *pdev)
/* Set up adapter data */ /* Set up adapter data */
i2c_set_adapdata(&i2c_imx->adapter, i2c_imx); i2c_set_adapdata(&i2c_imx->adapter, i2c_imx);
/* Set up platform driver data */
platform_set_drvdata(pdev, i2c_imx);
pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0)
goto rpm_disable;
/* Set up clock divider */ /* Set up clock divider */
i2c_imx->bitrate = IMX_I2C_BIT_RATE; i2c_imx->bitrate = IMX_I2C_BIT_RATE;
ret = of_property_read_u32(pdev->dev.of_node, ret = of_property_read_u32(pdev->dev.of_node,
...@@ -1125,12 +1131,11 @@ static int i2c_imx_probe(struct platform_device *pdev) ...@@ -1125,12 +1131,11 @@ static int i2c_imx_probe(struct platform_device *pdev)
ret = i2c_add_numbered_adapter(&i2c_imx->adapter); ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "registration failed\n"); dev_err(&pdev->dev, "registration failed\n");
goto clk_disable; goto rpm_disable;
} }
/* Set up platform driver data */ pm_runtime_mark_last_busy(&pdev->dev);
platform_set_drvdata(pdev, i2c_imx); pm_runtime_put_autosuspend(&pdev->dev);
clk_disable_unprepare(i2c_imx->clk);
dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", irq); dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", irq);
dev_dbg(&i2c_imx->adapter.dev, "device resources: %pR\n", res); dev_dbg(&i2c_imx->adapter.dev, "device resources: %pR\n", res);
...@@ -1143,6 +1148,12 @@ static int i2c_imx_probe(struct platform_device *pdev) ...@@ -1143,6 +1148,12 @@ static int i2c_imx_probe(struct platform_device *pdev)
return 0; /* Return OK */ return 0; /* Return OK */
rpm_disable:
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
clk_disable: clk_disable:
clk_disable_unprepare(i2c_imx->clk); clk_disable_unprepare(i2c_imx->clk);
return ret; return ret;
...@@ -1151,6 +1162,11 @@ static int i2c_imx_probe(struct platform_device *pdev) ...@@ -1151,6 +1162,11 @@ static int i2c_imx_probe(struct platform_device *pdev)
static int i2c_imx_remove(struct platform_device *pdev) static int i2c_imx_remove(struct platform_device *pdev)
{ {
struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev); struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
int ret;
ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0)
return ret;
/* remove adapter */ /* remove adapter */
dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n"); dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n");
...@@ -1165,14 +1181,51 @@ static int i2c_imx_remove(struct platform_device *pdev) ...@@ -1165,14 +1181,51 @@ static int i2c_imx_remove(struct platform_device *pdev)
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR); imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR);
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR); imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
clk_disable_unprepare(i2c_imx->clk);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return 0;
}
#ifdef CONFIG_PM
static int i2c_imx_runtime_suspend(struct device *dev)
{
struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
clk_disable_unprepare(i2c_imx->clk);
return 0; return 0;
} }
static int i2c_imx_runtime_resume(struct device *dev)
{
struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
int ret;
ret = clk_prepare_enable(i2c_imx->clk);
if (ret)
dev_err(dev, "can't enable I2C clock, ret=%d\n", ret);
return ret;
}
static const struct dev_pm_ops i2c_imx_pm_ops = {
SET_RUNTIME_PM_OPS(i2c_imx_runtime_suspend,
i2c_imx_runtime_resume, NULL)
};
#define I2C_IMX_PM_OPS (&i2c_imx_pm_ops)
#else
#define I2C_IMX_PM_OPS NULL
#endif /* CONFIG_PM */
static struct platform_driver i2c_imx_driver = { static struct platform_driver i2c_imx_driver = {
.probe = i2c_imx_probe, .probe = i2c_imx_probe,
.remove = i2c_imx_remove, .remove = i2c_imx_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.pm = I2C_IMX_PM_OPS,
.of_match_table = i2c_imx_dt_ids, .of_match_table = i2c_imx_dt_ids,
}, },
.id_table = imx_i2c_devtype, .id_table = imx_i2c_devtype,
......
...@@ -132,6 +132,7 @@ struct mtk_i2c_compatible { ...@@ -132,6 +132,7 @@ struct mtk_i2c_compatible {
unsigned char pmic_i2c: 1; unsigned char pmic_i2c: 1;
unsigned char dcm: 1; unsigned char dcm: 1;
unsigned char auto_restart: 1; unsigned char auto_restart: 1;
unsigned char aux_len_reg: 1;
}; };
struct mtk_i2c { struct mtk_i2c {
...@@ -153,6 +154,8 @@ struct mtk_i2c { ...@@ -153,6 +154,8 @@ struct mtk_i2c {
enum mtk_trans_op op; enum mtk_trans_op op;
u16 timing_reg; u16 timing_reg;
u16 high_speed_reg; u16 high_speed_reg;
unsigned char auto_restart;
bool ignore_restart_irq;
const struct mtk_i2c_compatible *dev_comp; const struct mtk_i2c_compatible *dev_comp;
}; };
...@@ -178,6 +181,7 @@ static const struct mtk_i2c_compatible mt6577_compat = { ...@@ -178,6 +181,7 @@ static const struct mtk_i2c_compatible mt6577_compat = {
.pmic_i2c = 0, .pmic_i2c = 0,
.dcm = 1, .dcm = 1,
.auto_restart = 0, .auto_restart = 0,
.aux_len_reg = 0,
}; };
static const struct mtk_i2c_compatible mt6589_compat = { static const struct mtk_i2c_compatible mt6589_compat = {
...@@ -185,6 +189,7 @@ static const struct mtk_i2c_compatible mt6589_compat = { ...@@ -185,6 +189,7 @@ static const struct mtk_i2c_compatible mt6589_compat = {
.pmic_i2c = 1, .pmic_i2c = 1,
.dcm = 0, .dcm = 0,
.auto_restart = 0, .auto_restart = 0,
.aux_len_reg = 0,
}; };
static const struct mtk_i2c_compatible mt8173_compat = { static const struct mtk_i2c_compatible mt8173_compat = {
...@@ -192,6 +197,7 @@ static const struct mtk_i2c_compatible mt8173_compat = { ...@@ -192,6 +197,7 @@ static const struct mtk_i2c_compatible mt8173_compat = {
.pmic_i2c = 0, .pmic_i2c = 0,
.dcm = 1, .dcm = 1,
.auto_restart = 1, .auto_restart = 1,
.aux_len_reg = 1,
}; };
static const struct of_device_id mtk_i2c_of_match[] = { static const struct of_device_id mtk_i2c_of_match[] = {
...@@ -373,7 +379,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, ...@@ -373,7 +379,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
i2c->irq_stat = 0; i2c->irq_stat = 0;
if (i2c->dev_comp->auto_restart) if (i2c->auto_restart)
restart_flag = I2C_RS_TRANSFER; restart_flag = I2C_RS_TRANSFER;
reinit_completion(&i2c->msg_complete); reinit_completion(&i2c->msg_complete);
...@@ -411,8 +417,14 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, ...@@ -411,8 +417,14 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
/* Set transfer and transaction len */ /* Set transfer and transaction len */
if (i2c->op == I2C_MASTER_WRRD) { if (i2c->op == I2C_MASTER_WRRD) {
if (i2c->dev_comp->aux_len_reg) {
writew(msgs->len, i2c->base + OFFSET_TRANSFER_LEN);
writew((msgs + 1)->len, i2c->base +
OFFSET_TRANSFER_LEN_AUX);
} else {
writew(msgs->len | ((msgs + 1)->len) << 8, writew(msgs->len | ((msgs + 1)->len) << 8,
i2c->base + OFFSET_TRANSFER_LEN); i2c->base + OFFSET_TRANSFER_LEN);
}
writew(I2C_WRRD_TRANAC_VALUE, i2c->base + OFFSET_TRANSAC_LEN); writew(I2C_WRRD_TRANAC_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
} else { } else {
writew(msgs->len, i2c->base + OFFSET_TRANSFER_LEN); writew(msgs->len, i2c->base + OFFSET_TRANSFER_LEN);
...@@ -461,7 +473,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, ...@@ -461,7 +473,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
writel(I2C_DMA_START_EN, i2c->pdmabase + OFFSET_EN); writel(I2C_DMA_START_EN, i2c->pdmabase + OFFSET_EN);
if (!i2c->dev_comp->auto_restart) { if (!i2c->auto_restart) {
start_reg = I2C_TRANSAC_START; start_reg = I2C_TRANSAC_START;
} else { } else {
start_reg = I2C_TRANSAC_START | I2C_RS_MUL_TRIG; start_reg = I2C_TRANSAC_START | I2C_RS_MUL_TRIG;
...@@ -518,6 +530,24 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap, ...@@ -518,6 +530,24 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
if (ret) if (ret)
return ret; return ret;
i2c->auto_restart = i2c->dev_comp->auto_restart;
/* checking if we can skip restart and optimize using WRRD mode */
if (i2c->auto_restart && num == 2) {
if (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) &&
msgs[0].addr == msgs[1].addr) {
i2c->auto_restart = 0;
}
}
if (i2c->auto_restart && num >= 2 && i2c->speed_hz > MAX_FS_MODE_SPEED)
/* ignore the first restart irq after the master code,
* otherwise the first transfer will be discarded.
*/
i2c->ignore_restart_irq = true;
else
i2c->ignore_restart_irq = false;
while (left_num--) { while (left_num--) {
if (!msgs->buf) { if (!msgs->buf) {
dev_dbg(i2c->dev, "data buffer is NULL.\n"); dev_dbg(i2c->dev, "data buffer is NULL.\n");
...@@ -530,7 +560,7 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap, ...@@ -530,7 +560,7 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
else else
i2c->op = I2C_MASTER_WR; i2c->op = I2C_MASTER_WR;
if (!i2c->dev_comp->auto_restart) { if (!i2c->auto_restart) {
if (num > 1) { if (num > 1) {
/* combined two messages into one transaction */ /* combined two messages into one transaction */
i2c->op = I2C_MASTER_WRRD; i2c->op = I2C_MASTER_WRRD;
...@@ -559,7 +589,7 @@ static irqreturn_t mtk_i2c_irq(int irqno, void *dev_id) ...@@ -559,7 +589,7 @@ static irqreturn_t mtk_i2c_irq(int irqno, void *dev_id)
u16 restart_flag = 0; u16 restart_flag = 0;
u16 intr_stat; u16 intr_stat;
if (i2c->dev_comp->auto_restart) if (i2c->auto_restart)
restart_flag = I2C_RS_TRANSFER; restart_flag = I2C_RS_TRANSFER;
intr_stat = readw(i2c->base + OFFSET_INTR_STAT); intr_stat = readw(i2c->base + OFFSET_INTR_STAT);
...@@ -571,8 +601,16 @@ static irqreturn_t mtk_i2c_irq(int irqno, void *dev_id) ...@@ -571,8 +601,16 @@ static irqreturn_t mtk_i2c_irq(int irqno, void *dev_id)
* i2c->irq_stat need keep the two interrupt value. * i2c->irq_stat need keep the two interrupt value.
*/ */
i2c->irq_stat |= intr_stat; i2c->irq_stat |= intr_stat;
if (i2c->ignore_restart_irq && (i2c->irq_stat & restart_flag)) {
i2c->ignore_restart_irq = false;
i2c->irq_stat = 0;
writew(I2C_RS_MUL_CNFG | I2C_RS_MUL_TRIG | I2C_TRANSAC_START,
i2c->base + OFFSET_START);
} else {
if (i2c->irq_stat & (I2C_TRANSAC_COMP | restart_flag)) if (i2c->irq_stat & (I2C_TRANSAC_COMP | restart_flag))
complete(&i2c->msg_complete); complete(&i2c->msg_complete);
}
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
...@@ -23,6 +23,9 @@ ...@@ -23,6 +23,9 @@
Note: we assume there can only be one device, with one or more Note: we assume there can only be one device, with one or more
SMBus interfaces. SMBus interfaces.
The device can register multiple i2c_adapters (up to PIIX4_MAX_ADAPTERS).
For devices supporting multiple ports the i2c_adapter should provide
an i2c_algorithm to access them.
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -37,6 +40,7 @@ ...@@ -37,6 +40,7 @@
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/mutex.h>
/* PIIX4 SMBus address offsets */ /* PIIX4 SMBus address offsets */
...@@ -75,6 +79,16 @@ ...@@ -75,6 +79,16 @@
#define PIIX4_WORD_DATA 0x0C #define PIIX4_WORD_DATA 0x0C
#define PIIX4_BLOCK_DATA 0x14 #define PIIX4_BLOCK_DATA 0x14
/* Multi-port constants */
#define PIIX4_MAX_ADAPTERS 4
/* SB800 constants */
#define SB800_PIIX4_SMB_IDX 0xcd6
/* SB800 port is selected by bits 2:1 of the smb_en register (0x2c) */
#define SB800_PIIX4_PORT_IDX 0x2c
#define SB800_PIIX4_PORT_IDX_MASK 0x06
/* insmod parameters */ /* insmod parameters */
/* If force is set to anything different from 0, we forcibly enable the /* If force is set to anything different from 0, we forcibly enable the
...@@ -122,8 +136,19 @@ static const struct dmi_system_id piix4_dmi_ibm[] = { ...@@ -122,8 +136,19 @@ static const struct dmi_system_id piix4_dmi_ibm[] = {
{ }, { },
}; };
/* SB800 globals */
static const char *piix4_main_port_names_sb800[PIIX4_MAX_ADAPTERS] = {
"SDA0", "SDA2", "SDA3", "SDA4"
};
static const char *piix4_aux_port_name_sb800 = "SDA1";
struct i2c_piix4_adapdata { struct i2c_piix4_adapdata {
unsigned short smba; unsigned short smba;
/* SB800 */
bool sb800_main;
unsigned short port;
struct mutex *mutex;
}; };
static int piix4_setup(struct pci_dev *PIIX4_dev, static int piix4_setup(struct pci_dev *PIIX4_dev,
...@@ -229,7 +254,6 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev, ...@@ -229,7 +254,6 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
const struct pci_device_id *id, u8 aux) const struct pci_device_id *id, u8 aux)
{ {
unsigned short piix4_smba; unsigned short piix4_smba;
unsigned short smba_idx = 0xcd6;
u8 smba_en_lo, smba_en_hi, smb_en, smb_en_status; u8 smba_en_lo, smba_en_hi, smb_en, smb_en_status;
u8 i2ccfg, i2ccfg_offset = 0x10; u8 i2ccfg, i2ccfg_offset = 0x10;
...@@ -251,16 +275,10 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev, ...@@ -251,16 +275,10 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
else else
smb_en = (aux) ? 0x28 : 0x2c; smb_en = (aux) ? 0x28 : 0x2c;
if (!request_region(smba_idx, 2, "smba_idx")) { outb_p(smb_en, SB800_PIIX4_SMB_IDX);
dev_err(&PIIX4_dev->dev, "SMBus base address index region " smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1);
"0x%x already in use!\n", smba_idx); outb_p(smb_en + 1, SB800_PIIX4_SMB_IDX);
return -EBUSY; smba_en_hi = inb_p(SB800_PIIX4_SMB_IDX + 1);
}
outb_p(smb_en, smba_idx);
smba_en_lo = inb_p(smba_idx + 1);
outb_p(smb_en + 1, smba_idx);
smba_en_hi = inb_p(smba_idx + 1);
release_region(smba_idx, 2);
if (!smb_en) { if (!smb_en) {
smb_en_status = smba_en_lo & 0x10; smb_en_status = smba_en_lo & 0x10;
...@@ -483,7 +501,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, ...@@ -483,7 +501,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
return -EINVAL; return -EINVAL;
outb_p(len, SMBHSTDAT0); outb_p(len, SMBHSTDAT0);
i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
for (i = 1; i <= len; i++) for (i = 1; i <= len; i++)
outb_p(data->block[i], SMBBLKDAT); outb_p(data->block[i], SMBBLKDAT);
} }
...@@ -516,7 +534,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, ...@@ -516,7 +534,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
data->block[0] = inb_p(SMBHSTDAT0); data->block[0] = inb_p(SMBHSTDAT0);
if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX) if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
return -EPROTO; return -EPROTO;
i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
for (i = 1; i <= data->block[0]; i++) for (i = 1; i <= data->block[0]; i++)
data->block[i] = inb_p(SMBBLKDAT); data->block[i] = inb_p(SMBBLKDAT);
break; break;
...@@ -524,6 +542,43 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, ...@@ -524,6 +542,43 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
return 0; return 0;
} }
/*
* Handles access to multiple SMBus ports on the SB800.
* The port is selected by bits 2:1 of the smb_en register (0x2c).
* Returns negative errno on error.
*
* Note: The selected port must be returned to the initial selection to avoid
* problems on certain systems.
*/
static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data *data)
{
struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap);
u8 smba_en_lo;
u8 port;
int retval;
mutex_lock(adapdata->mutex);
outb_p(SB800_PIIX4_PORT_IDX, SB800_PIIX4_SMB_IDX);
smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1);
port = adapdata->port;
if ((smba_en_lo & SB800_PIIX4_PORT_IDX_MASK) != (port << 1))
outb_p((smba_en_lo & ~SB800_PIIX4_PORT_IDX_MASK) | (port << 1),
SB800_PIIX4_SMB_IDX + 1);
retval = piix4_access(adap, addr, flags, read_write,
command, size, data);
outb_p(smba_en_lo, SB800_PIIX4_SMB_IDX + 1);
mutex_unlock(adapdata->mutex);
return retval;
}
static u32 piix4_func(struct i2c_adapter *adapter) static u32 piix4_func(struct i2c_adapter *adapter)
{ {
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
...@@ -536,6 +591,11 @@ static const struct i2c_algorithm smbus_algorithm = { ...@@ -536,6 +591,11 @@ static const struct i2c_algorithm smbus_algorithm = {
.functionality = piix4_func, .functionality = piix4_func,
}; };
static const struct i2c_algorithm piix4_smbus_algorithm_sb800 = {
.smbus_xfer = piix4_access_sb800,
.functionality = piix4_func,
};
static const struct pci_device_id piix4_ids[] = { static const struct pci_device_id piix4_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
...@@ -561,11 +621,11 @@ static const struct pci_device_id piix4_ids[] = { ...@@ -561,11 +621,11 @@ static const struct pci_device_id piix4_ids[] = {
MODULE_DEVICE_TABLE (pci, piix4_ids); MODULE_DEVICE_TABLE (pci, piix4_ids);
static struct i2c_adapter *piix4_main_adapter; static struct i2c_adapter *piix4_main_adapters[PIIX4_MAX_ADAPTERS];
static struct i2c_adapter *piix4_aux_adapter; static struct i2c_adapter *piix4_aux_adapter;
static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba, static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
struct i2c_adapter **padap) const char *name, struct i2c_adapter **padap)
{ {
struct i2c_adapter *adap; struct i2c_adapter *adap;
struct i2c_piix4_adapdata *adapdata; struct i2c_piix4_adapdata *adapdata;
...@@ -594,7 +654,7 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba, ...@@ -594,7 +654,7 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
adap->dev.parent = &dev->dev; adap->dev.parent = &dev->dev;
snprintf(adap->name, sizeof(adap->name), snprintf(adap->name, sizeof(adap->name),
"SMBus PIIX4 adapter at %04x", smba); "SMBus PIIX4 adapter %s at %04x", name, smba);
i2c_set_adapdata(adap, adapdata); i2c_set_adapdata(adap, adapdata);
...@@ -611,6 +671,54 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba, ...@@ -611,6 +671,54 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
return 0; return 0;
} }
static int piix4_add_adapters_sb800(struct pci_dev *dev, unsigned short smba)
{
struct mutex *mutex;
struct i2c_piix4_adapdata *adapdata;
int port;
int retval;
mutex = kzalloc(sizeof(*mutex), GFP_KERNEL);
if (mutex == NULL)
return -ENOMEM;
mutex_init(mutex);
for (port = 0; port < PIIX4_MAX_ADAPTERS; port++) {
retval = piix4_add_adapter(dev, smba,
piix4_main_port_names_sb800[port],
&piix4_main_adapters[port]);
if (retval < 0)
goto error;
piix4_main_adapters[port]->algo = &piix4_smbus_algorithm_sb800;
adapdata = i2c_get_adapdata(piix4_main_adapters[port]);
adapdata->sb800_main = true;
adapdata->port = port;
adapdata->mutex = mutex;
}
return retval;
error:
dev_err(&dev->dev,
"Error setting up SB800 adapters. Unregistering!\n");
while (--port >= 0) {
adapdata = i2c_get_adapdata(piix4_main_adapters[port]);
if (adapdata->smba) {
i2c_del_adapter(piix4_main_adapters[port]);
kfree(adapdata);
kfree(piix4_main_adapters[port]);
piix4_main_adapters[port] = NULL;
}
}
kfree(mutex);
return retval;
}
static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
{ {
int retval; int retval;
...@@ -618,20 +726,41 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -618,20 +726,41 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
if ((dev->vendor == PCI_VENDOR_ID_ATI && if ((dev->vendor == PCI_VENDOR_ID_ATI &&
dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS && dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
dev->revision >= 0x40) || dev->revision >= 0x40) ||
dev->vendor == PCI_VENDOR_ID_AMD) dev->vendor == PCI_VENDOR_ID_AMD) {
if (!request_region(SB800_PIIX4_SMB_IDX, 2, "smba_idx")) {
dev_err(&dev->dev,
"SMBus base address index region 0x%x already in use!\n",
SB800_PIIX4_SMB_IDX);
return -EBUSY;
}
/* base address location etc changed in SB800 */ /* base address location etc changed in SB800 */
retval = piix4_setup_sb800(dev, id, 0); retval = piix4_setup_sb800(dev, id, 0);
else if (retval < 0) {
retval = piix4_setup(dev, id); release_region(SB800_PIIX4_SMB_IDX, 2);
return retval;
}
/* If no main SMBus found, give up */ /*
* Try to register multiplexed main SMBus adapter,
* give up if we can't
*/
retval = piix4_add_adapters_sb800(dev, retval);
if (retval < 0) {
release_region(SB800_PIIX4_SMB_IDX, 2);
return retval;
}
} else {
retval = piix4_setup(dev, id);
if (retval < 0) if (retval < 0)
return retval; return retval;
/* Try to register main SMBus adapter, give up if we can't */ /* Try to register main SMBus adapter, give up if we can't */
retval = piix4_add_adapter(dev, retval, &piix4_main_adapter); retval = piix4_add_adapter(dev, retval, "main",
&piix4_main_adapters[0]);
if (retval < 0) if (retval < 0)
return retval; return retval;
}
/* Check for auxiliary SMBus on some AMD chipsets */ /* Check for auxiliary SMBus on some AMD chipsets */
retval = -ENODEV; retval = -ENODEV;
...@@ -654,7 +783,8 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -654,7 +783,8 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (retval > 0) { if (retval > 0) {
/* Try to add the aux adapter if it exists, /* Try to add the aux adapter if it exists,
* piix4_add_adapter will clean up if this fails */ * piix4_add_adapter will clean up if this fails */
piix4_add_adapter(dev, retval, &piix4_aux_adapter); piix4_add_adapter(dev, retval, piix4_aux_port_name_sb800,
&piix4_aux_adapter);
} }
return 0; return 0;
...@@ -666,7 +796,13 @@ static void piix4_adap_remove(struct i2c_adapter *adap) ...@@ -666,7 +796,13 @@ static void piix4_adap_remove(struct i2c_adapter *adap)
if (adapdata->smba) { if (adapdata->smba) {
i2c_del_adapter(adap); i2c_del_adapter(adap);
if (adapdata->port == 0) {
release_region(adapdata->smba, SMBIOSIZE); release_region(adapdata->smba, SMBIOSIZE);
if (adapdata->sb800_main) {
kfree(adapdata->mutex);
release_region(SB800_PIIX4_SMB_IDX, 2);
}
}
kfree(adapdata); kfree(adapdata);
kfree(adap); kfree(adap);
} }
...@@ -674,9 +810,13 @@ static void piix4_adap_remove(struct i2c_adapter *adap) ...@@ -674,9 +810,13 @@ static void piix4_adap_remove(struct i2c_adapter *adap)
static void piix4_remove(struct pci_dev *dev) static void piix4_remove(struct pci_dev *dev)
{ {
if (piix4_main_adapter) { int port = PIIX4_MAX_ADAPTERS;
piix4_adap_remove(piix4_main_adapter);
piix4_main_adapter = NULL; while (--port >= 0) {
if (piix4_main_adapters[port]) {
piix4_adap_remove(piix4_main_adapters[port]);
piix4_main_adapters[port] = NULL;
}
} }
if (piix4_aux_adapter) { if (piix4_aux_adapter) {
......
This diff is collapsed.
...@@ -784,7 +784,6 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, ...@@ -784,7 +784,6 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
int retry; int retry;
int ret; int ret;
pm_runtime_get_sync(&adap->dev);
ret = clk_enable(i2c->clk); ret = clk_enable(i2c->clk);
if (ret) if (ret)
return ret; return ret;
...@@ -795,7 +794,6 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, ...@@ -795,7 +794,6 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
if (ret != -EAGAIN) { if (ret != -EAGAIN) {
clk_disable(i2c->clk); clk_disable(i2c->clk);
pm_runtime_put(&adap->dev);
return ret; return ret;
} }
...@@ -805,7 +803,6 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, ...@@ -805,7 +803,6 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
} }
clk_disable(i2c->clk); clk_disable(i2c->clk);
pm_runtime_put(&adap->dev);
return -EREMOTEIO; return -EREMOTEIO;
} }
...@@ -1256,8 +1253,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ...@@ -1256,8 +1253,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
return ret; return ret;
} }
pm_runtime_enable(&i2c->adap.dev);
dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev)); dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
return 0; return 0;
} }
...@@ -1273,7 +1268,6 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) ...@@ -1273,7 +1268,6 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
clk_unprepare(i2c->clk); clk_unprepare(i2c->clk);
pm_runtime_disable(&i2c->adap.dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
s3c24xx_i2c_deregister_cpufreq(i2c); s3c24xx_i2c_deregister_cpufreq(i2c);
......
...@@ -708,8 +708,7 @@ static int st_i2c_xfer(struct i2c_adapter *i2c_adap, ...@@ -708,8 +708,7 @@ static int st_i2c_xfer(struct i2c_adapter *i2c_adap,
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int st_i2c_suspend(struct device *dev) static int st_i2c_suspend(struct device *dev)
{ {
struct platform_device *pdev = struct platform_device *pdev = to_platform_device(dev);
container_of(dev, struct platform_device, dev);
struct st_i2c_dev *i2c_dev = platform_get_drvdata(pdev); struct st_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
if (i2c_dev->busy) if (i2c_dev->busy)
......
...@@ -130,7 +130,13 @@ static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr, ...@@ -130,7 +130,13 @@ static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
return 0; return 0;
} else { } else {
if (p[0] == 'x') { if (p[0] == 'x') {
data->byte = simple_strtol(p + 1, NULL, 16); /*
* Voluntarily dropping error code of kstrtou8 since all
* error code that it could return are invalid according
* to Documentation/i2c/fault-codes.
*/
if (kstrtou8(p + 1, 16, &data->byte))
return -EPROTO;
return 0; return 0;
} }
} }
......
...@@ -466,6 +466,11 @@ static int uniphier_fi2c_clk_init(struct device *dev, ...@@ -466,6 +466,11 @@ static int uniphier_fi2c_clk_init(struct device *dev,
if (of_property_read_u32(np, "clock-frequency", &bus_speed)) if (of_property_read_u32(np, "clock-frequency", &bus_speed))
bus_speed = UNIPHIER_FI2C_DEFAULT_SPEED; bus_speed = UNIPHIER_FI2C_DEFAULT_SPEED;
if (!bus_speed) {
dev_err(dev, "clock-freqyency should not be zero\n");
return -EINVAL;
}
if (bus_speed > UNIPHIER_FI2C_MAX_SPEED) if (bus_speed > UNIPHIER_FI2C_MAX_SPEED)
bus_speed = UNIPHIER_FI2C_MAX_SPEED; bus_speed = UNIPHIER_FI2C_MAX_SPEED;
...@@ -481,6 +486,10 @@ static int uniphier_fi2c_clk_init(struct device *dev, ...@@ -481,6 +486,10 @@ static int uniphier_fi2c_clk_init(struct device *dev,
return ret; return ret;
clk_rate = clk_get_rate(priv->clk); clk_rate = clk_get_rate(priv->clk);
if (!clk_rate) {
dev_err(dev, "input clock rate should not be zero\n");
return -EINVAL;
}
uniphier_fi2c_reset(priv); uniphier_fi2c_reset(priv);
...@@ -531,7 +540,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev) ...@@ -531,7 +540,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
ret = uniphier_fi2c_clk_init(dev, priv); ret = uniphier_fi2c_clk_init(dev, priv);
if (ret) if (ret)
return ret; goto err;
ret = devm_request_irq(dev, irq, uniphier_fi2c_interrupt, 0, ret = devm_request_irq(dev, irq, uniphier_fi2c_interrupt, 0,
pdev->name, priv); pdev->name, priv);
......
...@@ -327,6 +327,11 @@ static int uniphier_i2c_clk_init(struct device *dev, ...@@ -327,6 +327,11 @@ static int uniphier_i2c_clk_init(struct device *dev,
if (of_property_read_u32(np, "clock-frequency", &bus_speed)) if (of_property_read_u32(np, "clock-frequency", &bus_speed))
bus_speed = UNIPHIER_I2C_DEFAULT_SPEED; bus_speed = UNIPHIER_I2C_DEFAULT_SPEED;
if (!bus_speed) {
dev_err(dev, "clock-freqyency should not be zero\n");
return -EINVAL;
}
if (bus_speed > UNIPHIER_I2C_MAX_SPEED) if (bus_speed > UNIPHIER_I2C_MAX_SPEED)
bus_speed = UNIPHIER_I2C_MAX_SPEED; bus_speed = UNIPHIER_I2C_MAX_SPEED;
...@@ -342,6 +347,10 @@ static int uniphier_i2c_clk_init(struct device *dev, ...@@ -342,6 +347,10 @@ static int uniphier_i2c_clk_init(struct device *dev,
return ret; return ret;
clk_rate = clk_get_rate(priv->clk); clk_rate = clk_get_rate(priv->clk);
if (!clk_rate) {
dev_err(dev, "input clock rate should not be zero\n");
return -EINVAL;
}
uniphier_i2c_reset(priv, true); uniphier_i2c_reset(priv, true);
...@@ -388,7 +397,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev) ...@@ -388,7 +397,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev)
ret = uniphier_i2c_clk_init(dev, priv); ret = uniphier_i2c_clk_init(dev, priv);
if (ret) if (ret)
return ret; goto err;
ret = devm_request_irq(dev, irq, uniphier_i2c_interrupt, 0, pdev->name, ret = devm_request_irq(dev, irq, uniphier_i2c_interrupt, 0, pdev->name,
priv); priv);
......
...@@ -70,7 +70,7 @@ struct xiic_i2c { ...@@ -70,7 +70,7 @@ struct xiic_i2c {
wait_queue_head_t wait; wait_queue_head_t wait;
struct i2c_adapter adap; struct i2c_adapter adap;
struct i2c_msg *tx_msg; struct i2c_msg *tx_msg;
spinlock_t lock; struct mutex lock;
unsigned int tx_pos; unsigned int tx_pos;
unsigned int nmsgs; unsigned int nmsgs;
enum xilinx_i2c_state state; enum xilinx_i2c_state state;
...@@ -369,7 +369,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id) ...@@ -369,7 +369,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
* To find which interrupts are pending; AND interrupts pending with * To find which interrupts are pending; AND interrupts pending with
* interrupts masked. * interrupts masked.
*/ */
spin_lock(&i2c->lock); mutex_lock(&i2c->lock);
isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET); isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET);
ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET); ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
pend = isr & ier; pend = isr & ier;
...@@ -497,7 +497,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id) ...@@ -497,7 +497,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
dev_dbg(i2c->adap.dev.parent, "%s clr: 0x%x\n", __func__, clr); dev_dbg(i2c->adap.dev.parent, "%s clr: 0x%x\n", __func__, clr);
xiic_setreg32(i2c, XIIC_IISR_OFFSET, clr); xiic_setreg32(i2c, XIIC_IISR_OFFSET, clr);
spin_unlock(&i2c->lock); mutex_unlock(&i2c->lock);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -662,10 +662,10 @@ static void __xiic_start_xfer(struct xiic_i2c *i2c) ...@@ -662,10 +662,10 @@ 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)
{ {
spin_lock(&i2c->lock); mutex_lock(&i2c->lock);
xiic_reinit(i2c); xiic_reinit(i2c);
__xiic_start_xfer(i2c); __xiic_start_xfer(i2c);
spin_unlock(&i2c->lock); mutex_unlock(&i2c->lock);
} }
static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
...@@ -745,7 +745,7 @@ static int xiic_i2c_probe(struct platform_device *pdev) ...@@ -745,7 +745,7 @@ static int xiic_i2c_probe(struct platform_device *pdev)
i2c->adap.dev.parent = &pdev->dev; i2c->adap.dev.parent = &pdev->dev;
i2c->adap.dev.of_node = pdev->dev.of_node; i2c->adap.dev.of_node = pdev->dev.of_node;
spin_lock_init(&i2c->lock); mutex_init(&i2c->lock);
init_waitqueue_head(&i2c->wait); init_waitqueue_head(&i2c->wait);
ret = devm_request_threaded_irq(&pdev->dev, irq, xiic_isr, ret = devm_request_threaded_irq(&pdev->dev, irq, xiic_isr,
......
This diff is collapsed.
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
#include <linux/jump_label.h> #include <linux/jump_label.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/property.h>
#include "i2c-core.h" #include "i2c-core.h"
...@@ -1563,6 +1564,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) ...@@ -1563,6 +1564,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
pm_runtime_no_callbacks(&adap->dev); pm_runtime_no_callbacks(&adap->dev);
pm_runtime_enable(&adap->dev);
#ifdef CONFIG_I2C_COMPAT #ifdef CONFIG_I2C_COMPAT
res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev, res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
...@@ -1817,6 +1819,8 @@ void i2c_del_adapter(struct i2c_adapter *adap) ...@@ -1817,6 +1819,8 @@ void i2c_del_adapter(struct i2c_adapter *adap)
/* device name is gone after device_unregister */ /* device name is gone after device_unregister */
dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
pm_runtime_disable(&adap->dev);
/* wait until all references to the device are gone /* wait until all references to the device are gone
* *
* FIXME: This is old code and should ideally be replaced by an * FIXME: This is old code and should ideally be replaced by an
...@@ -1839,6 +1843,58 @@ void i2c_del_adapter(struct i2c_adapter *adap) ...@@ -1839,6 +1843,58 @@ void i2c_del_adapter(struct i2c_adapter *adap)
} }
EXPORT_SYMBOL(i2c_del_adapter); EXPORT_SYMBOL(i2c_del_adapter);
/**
* i2c_parse_fw_timings - get I2C related timing parameters from firmware
* @dev: The device to scan for I2C timing properties
* @t: the i2c_timings struct to be filled with values
* @use_defaults: bool to use sane defaults derived from the I2C specification
* when properties are not found, otherwise use 0
*
* Scan the device for the generic I2C properties describing timing parameters
* for the signal and fill the given struct with the results. If a property was
* not found and use_defaults was true, then maximum timings are assumed which
* are derived from the I2C specification. If use_defaults is not used, the
* results will be 0, so drivers can apply their own defaults later. The latter
* is mainly intended for avoiding regressions of existing drivers which want
* to switch to this function. New drivers almost always should use the defaults.
*/
void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t, bool use_defaults)
{
int ret;
memset(t, 0, sizeof(*t));
ret = device_property_read_u32(dev, "clock-frequency", &t->bus_freq_hz);
if (ret && use_defaults)
t->bus_freq_hz = 100000;
ret = device_property_read_u32(dev, "i2c-scl-rising-time-ns", &t->scl_rise_ns);
if (ret && use_defaults) {
if (t->bus_freq_hz <= 100000)
t->scl_rise_ns = 1000;
else if (t->bus_freq_hz <= 400000)
t->scl_rise_ns = 300;
else
t->scl_rise_ns = 120;
}
ret = device_property_read_u32(dev, "i2c-scl-falling-time-ns", &t->scl_fall_ns);
if (ret && use_defaults) {
if (t->bus_freq_hz <= 400000)
t->scl_fall_ns = 300;
else
t->scl_fall_ns = 120;
}
device_property_read_u32(dev, "i2c-scl-internal-delay-ns", &t->scl_int_delay_ns);
ret = device_property_read_u32(dev, "i2c-sda-falling-time-ns", &t->sda_fall_ns);
if (ret && use_defaults)
t->sda_fall_ns = t->scl_fall_ns;
}
EXPORT_SYMBOL_GPL(i2c_parse_fw_timings);
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *)) int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *))
......
...@@ -413,6 +413,22 @@ struct i2c_algorithm { ...@@ -413,6 +413,22 @@ struct i2c_algorithm {
#endif #endif
}; };
/**
* struct i2c_timings - I2C timing information
* @bus_freq_hz: the bus frequency in Hz
* @scl_rise_ns: time SCL signal takes to rise in ns; t(r) in the I2C specification
* @scl_fall_ns: time SCL signal takes to fall in ns; t(f) in the I2C specification
* @scl_int_delay_ns: time IP core additionally needs to setup SCL in ns
* @sda_fall_ns: time SDA signal takes to fall in ns; t(f) in the I2C specification
*/
struct i2c_timings {
u32 bus_freq_hz;
u32 scl_rise_ns;
u32 scl_fall_ns;
u32 scl_int_delay_ns;
u32 sda_fall_ns;
};
/** /**
* struct i2c_bus_recovery_info - I2C bus recovery information * struct i2c_bus_recovery_info - I2C bus recovery information
* @recover_bus: Recover routine. Either pass driver's recover_bus() routine, or * @recover_bus: Recover routine. Either pass driver's recover_bus() routine, or
...@@ -493,6 +509,8 @@ struct i2c_adapter_quirks { ...@@ -493,6 +509,8 @@ struct i2c_adapter_quirks {
/* convenience macro for typical write-then read case */ /* convenience macro for typical write-then read case */
#define I2C_AQ_COMB_WRITE_THEN_READ (I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | \ #define I2C_AQ_COMB_WRITE_THEN_READ (I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | \
I2C_AQ_COMB_READ_SECOND | I2C_AQ_COMB_SAME_ADDR) I2C_AQ_COMB_READ_SECOND | I2C_AQ_COMB_SAME_ADDR)
/* clock stretching is not supported */
#define I2C_AQ_NO_CLK_STRETCH BIT(4)
/* /*
* i2c_adapter is the structure used to identify a physical i2c bus along * i2c_adapter is the structure used to identify a physical i2c bus along
...@@ -602,6 +620,7 @@ extern void i2c_clients_command(struct i2c_adapter *adap, ...@@ -602,6 +620,7 @@ extern void i2c_clients_command(struct i2c_adapter *adap,
extern struct i2c_adapter *i2c_get_adapter(int nr); extern struct i2c_adapter *i2c_get_adapter(int nr);
extern void i2c_put_adapter(struct i2c_adapter *adap); extern void i2c_put_adapter(struct i2c_adapter *adap);
void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t, bool use_defaults);
/* Return the functionality mask */ /* Return the functionality mask */
static inline u32 i2c_get_functionality(struct i2c_adapter *adap) static inline u32 i2c_get_functionality(struct i2c_adapter *adap)
...@@ -615,6 +634,20 @@ static inline int i2c_check_functionality(struct i2c_adapter *adap, u32 func) ...@@ -615,6 +634,20 @@ static inline int i2c_check_functionality(struct i2c_adapter *adap, u32 func)
return (func & i2c_get_functionality(adap)) == func; return (func & i2c_get_functionality(adap)) == func;
} }
/**
* i2c_check_quirks() - Function for checking the quirk flags in an i2c adapter
* @adap: i2c adapter
* @quirks: quirk flags
*
* Return: true if the adapter has all the specified quirk flags, false if not
*/
static inline bool i2c_check_quirks(struct i2c_adapter *adap, u64 quirks)
{
if (!adap->quirks)
return false;
return (adap->quirks->flags & quirks) == quirks;
}
/* Return the adapter number for a specific adapter */ /* Return the adapter number for a specific adapter */
static inline int i2c_adapter_id(struct i2c_adapter *adap) static inline int i2c_adapter_id(struct i2c_adapter *adap)
{ {
...@@ -622,7 +655,7 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap) ...@@ -622,7 +655,7 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap)
} }
/** /**
* module_i2c_driver() - Helper macro for registering a I2C driver * module_i2c_driver() - Helper macro for registering a modular I2C driver
* @__i2c_driver: i2c_driver struct * @__i2c_driver: i2c_driver struct
* *
* Helper macro for I2C drivers which do not do anything special in module * Helper macro for I2C drivers which do not do anything special in module
...@@ -633,6 +666,17 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap) ...@@ -633,6 +666,17 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap)
module_driver(__i2c_driver, i2c_add_driver, \ module_driver(__i2c_driver, i2c_add_driver, \
i2c_del_driver) i2c_del_driver)
/**
* builtin_i2c_driver() - Helper macro for registering a builtin I2C driver
* @__i2c_driver: i2c_driver struct
*
* Helper macro for I2C drivers which do not do anything special in their
* init. This eliminates a lot of boilerplate. Each driver may only
* use this macro once, and calling it replaces device_initcall().
*/
#define builtin_i2c_driver(__i2c_driver) \
builtin_driver(__i2c_driver, i2c_add_driver)
#endif /* I2C */ #endif /* I2C */
#if IS_ENABLED(CONFIG_OF) #if IS_ENABLED(CONFIG_OF)
...@@ -644,6 +688,7 @@ extern struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node) ...@@ -644,6 +688,7 @@ extern struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
/* must call i2c_put_adapter() when done with returned i2c_adapter device */ /* must call i2c_put_adapter() when done with returned i2c_adapter device */
struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node *node); struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node *node);
#else #else
static inline struct i2c_client *of_find_i2c_device_by_node(struct device_node *node) static inline struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
......
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