mirror of https://gitee.com/openkylin/linux.git
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 ...
This commit is contained in:
commit
32250e4a5f
|
@ -2,11 +2,22 @@ EEPROMs (I2C)
|
|||
|
||||
Required properties:
|
||||
|
||||
- compatible : should be "<manufacturer>,<type>"
|
||||
If there is no specific driver for <manufacturer>, a generic
|
||||
driver based on <type> is selected. Possible types are:
|
||||
24c00, 24c01, 24c02, 24c04, 24c08, 24c16, 24c32, 24c64,
|
||||
24c128, 24c256, 24c512, 24c1024, spd
|
||||
- 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
|
||||
driver based on <type> is selected. Possible types are:
|
||||
"24c00", "24c01", "24c02", "24c04", "24c08", "24c16", "24c32", "24c64",
|
||||
"24c128", "24c256", "24c512", "24c1024", "spd"
|
||||
|
||||
- reg : the I2C address of the EEPROM
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ I2C for Atmel platforms
|
|||
Required properties :
|
||||
- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-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
|
||||
region.
|
||||
- interrupts: interrupt number to the cpu.
|
||||
|
@ -17,6 +17,8 @@ Optional properties:
|
|||
- dma-names: should contain "tx" and "rx".
|
||||
- atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO
|
||||
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
|
||||
|
||||
Examples :
|
||||
|
@ -52,6 +54,7 @@ i2c0: i2c@f8034600 {
|
|||
#size-cells = <0>;
|
||||
clocks = <&flx0>;
|
||||
atmel,fifo-size = <16>;
|
||||
i2c-sda-hold-time-ns = <336>;
|
||||
|
||||
wm8731: wm8731@1a {
|
||||
compatible = "wm8731";
|
||||
|
|
|
@ -2,7 +2,7 @@ Broadcom stb bsc iic master controller
|
|||
|
||||
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
|
||||
valid values are 375000, 390000, 187500, 200000
|
||||
93750, 97500, 46875 and 50000
|
||||
|
|
|
@ -20,6 +20,10 @@ Optional properties:
|
|||
propoerty indicates the default frequency 100 kHz.
|
||||
- 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 :
|
||||
|
||||
i2c0: i2c@e6508000 {
|
||||
|
|
|
@ -29,12 +29,38 @@ Optional properties
|
|||
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.
|
||||
|
||||
- clock-frequency - frequency of bus clock in Hz.
|
||||
- wakeup-source - device can be used as a wakeup source.
|
||||
- clock-frequency
|
||||
frequency of bus clock in Hz.
|
||||
|
||||
- interrupts - interrupts used by the device.
|
||||
- interrupt-names - "irq" and "wakeup" names are recognized by I2C core,
|
||||
other names are left to individual drivers.
|
||||
- i2c-scl-falling-time-ns
|
||||
Number of nanoseconds the SCL signal takes to fall; t(f) in the I2C
|
||||
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
|
||||
used by the device. I2C core will assign "irq" interrupt (or the very first
|
||||
|
|
|
@ -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)
|
||||
ams,iaq-core AMS iAQ-Core VOC Sensor
|
||||
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)
|
||||
capella,cm32181 CM32181: Ambient Light Sensor
|
||||
capella,cm3232 CM3232: Ambient Light Sensor
|
||||
catalyst,24c32 i2c serial eeprom
|
||||
cirrus,cs42l51 Cirrus Logic CS42L51 audio codec
|
||||
dallas,ds1307 64 x 8, Serial, I2C Real-Time Clock
|
||||
dallas,ds1338 I2C RTC with 56-Byte NV RAM
|
||||
|
@ -50,11 +38,13 @@ dallas,ds4510 CPU Supervisor with Nonvolatile Memory and Programmable I/O
|
|||
dallas,ds75 Digital Thermometer and Thermostat
|
||||
dlg,da9053 DA9053: flexible system level PMIC with multicore support
|
||||
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,rx8581 I2C-BUS INTERFACE REAL TIME CLOCK MODULE
|
||||
fsl,mag3110 MAG3110: Xtrinsic High Accuracy, 3D Magnetometer
|
||||
fsl,mc13892 MC13892: Power Management Integrated Circuit (PMIC) for i.MX35/51
|
||||
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,sgtl5000 SGTL5000: Ultra Low-Power Audio Codec
|
||||
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
|
|||
pericom,pt7c4338 Real-time Clock Module
|
||||
plx,pex8648 48-Lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch
|
||||
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,r2221tl 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 = {
|
|||
};
|
||||
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
|
||||
*/
|
||||
|
@ -635,6 +639,8 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap,
|
|||
/* register new adapter to i2c module... */
|
||||
adap->algo = &i2c_bit_algo;
|
||||
adap->retries = 3;
|
||||
if (bit_adap->getscl == NULL)
|
||||
adap->quirks = &i2c_bit_quirk_no_clk_stretch;
|
||||
|
||||
ret = add_adapter(adap);
|
||||
if (ret < 0)
|
||||
|
|
|
@ -516,7 +516,7 @@ config I2C_EFM32
|
|||
|
||||
config I2C_EG20T
|
||||
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
|
||||
This driver is for PCH(Platform controller Hub) I2C of EG20T which
|
||||
is an IOH(Input/Output Hub) for x86 embedded processor.
|
||||
|
@ -532,6 +532,7 @@ config I2C_EG20T
|
|||
config I2C_EMEV2
|
||||
tristate "EMMA Mobile series I2C adapter"
|
||||
depends on HAVE_CLK
|
||||
select I2C_SLAVE
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
I2C interface on the Renesas Electronics EM/EV family of processors.
|
||||
|
@ -963,11 +964,11 @@ config I2C_XILINX
|
|||
will be called xilinx_i2c.
|
||||
|
||||
config I2C_XLR
|
||||
tristate "XLR I2C support"
|
||||
depends on CPU_XLR
|
||||
tristate "Netlogic XLR and Sigma Designs I2C support"
|
||||
depends on CPU_XLR || ARCH_TANGOX
|
||||
help
|
||||
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
|
||||
will be called i2c-xlr.
|
||||
|
|
|
@ -64,6 +64,8 @@
|
|||
#define AT91_TWI_IADR 0x000c /* Internal Address Register */
|
||||
|
||||
#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_TXCOMP BIT(0) /* Transmission Complete */
|
||||
|
@ -110,6 +112,7 @@ struct at91_twi_pdata {
|
|||
unsigned clk_offset;
|
||||
bool has_unre_flag;
|
||||
bool has_alt_cmd;
|
||||
bool has_hold_field;
|
||||
struct at_dma_slave dma_slave;
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
int ckdiv, cdiv, div;
|
||||
int ckdiv, cdiv, div, hold = 0;
|
||||
struct at91_twi_pdata *pdata = dev->pdata;
|
||||
int offset = pdata->clk_offset;
|
||||
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),
|
||||
2 * twi_clk) - offset);
|
||||
|
@ -204,8 +208,33 @@ static void at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
|
|||
cdiv = 255;
|
||||
}
|
||||
|
||||
dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv;
|
||||
dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv);
|
||||
if (pdata->has_hold_field) {
|
||||
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)
|
||||
|
@ -797,6 +826,7 @@ static struct at91_twi_pdata at91rm9200_config = {
|
|||
.clk_offset = 3,
|
||||
.has_unre_flag = true,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata at91sam9261_config = {
|
||||
|
@ -804,6 +834,7 @@ static struct at91_twi_pdata at91sam9261_config = {
|
|||
.clk_offset = 4,
|
||||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata at91sam9260_config = {
|
||||
|
@ -811,6 +842,7 @@ static struct at91_twi_pdata at91sam9260_config = {
|
|||
.clk_offset = 4,
|
||||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata at91sam9g20_config = {
|
||||
|
@ -818,6 +850,7 @@ static struct at91_twi_pdata at91sam9g20_config = {
|
|||
.clk_offset = 4,
|
||||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata at91sam9g10_config = {
|
||||
|
@ -825,6 +858,7 @@ static struct at91_twi_pdata at91sam9g10_config = {
|
|||
.clk_offset = 4,
|
||||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
};
|
||||
|
||||
static const struct platform_device_id at91_twi_devtypes[] = {
|
||||
|
@ -854,6 +888,15 @@ static struct at91_twi_pdata at91sam9x5_config = {
|
|||
.clk_offset = 4,
|
||||
.has_unre_flag = 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 = {
|
||||
|
@ -861,6 +904,7 @@ static struct at91_twi_pdata sama5d2_config = {
|
|||
.clk_offset = 4,
|
||||
.has_unre_flag = true,
|
||||
.has_alt_cmd = true,
|
||||
.has_hold_field = true,
|
||||
};
|
||||
|
||||
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",
|
||||
.data = &at91sam9x5_config,
|
||||
}, {
|
||||
.compatible = "atmel,sama5d4-i2c",
|
||||
.data = &sama5d4_config,
|
||||
}, {
|
||||
.compatible = "atmel,sama5d2-i2c",
|
||||
.data = &sama5d2_config,
|
||||
|
|
|
@ -222,6 +222,15 @@ static const struct i2c_algorithm bcm2835_i2c_algo = {
|
|||
.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)
|
||||
{
|
||||
struct bcm2835_i2c_dev *i2c_dev;
|
||||
|
@ -293,6 +302,7 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
|
|||
adap->algo = &bcm2835_i2c_algo;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
adap->dev.of_node = pdev->dev.of_node;
|
||||
adap->quirks = &bcm2835_i2c_quirks;
|
||||
|
||||
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, 0);
|
||||
|
||||
|
|
|
@ -25,13 +25,16 @@
|
|||
#include <linux/version.h>
|
||||
|
||||
#define N_DATA_REGS 8
|
||||
#define N_DATA_BYTES (N_DATA_REGS * 4)
|
||||
|
||||
/* BSC count register field definitions */
|
||||
#define BSC_CNT_REG1_MASK 0x0000003f
|
||||
#define BSC_CNT_REG1_SHIFT 0
|
||||
#define BSC_CNT_REG2_MASK 0x00000fc0
|
||||
#define BSC_CNT_REG2_SHIFT 6
|
||||
/*
|
||||
* 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
|
||||
|
||||
/* BSC CTL register field definitions */
|
||||
#define BSC_CTL_REG_DTF_MASK 0x00000003
|
||||
|
@ -41,7 +44,7 @@
|
|||
#define BSC_CTL_REG_INT_EN_SHIFT 6
|
||||
#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_NOSTART_MASK 0x00000020
|
||||
#define BSC_IIC_EN_NOSTOP_MASK 0x00000010
|
||||
|
@ -169,6 +172,7 @@ struct brcmstb_i2c_dev {
|
|||
struct completion done;
|
||||
bool is_suspended;
|
||||
u32 clk_freq_hz;
|
||||
int data_regsz;
|
||||
};
|
||||
|
||||
/* register accessors for both be and le cpu arch */
|
||||
|
@ -186,6 +190,16 @@ struct brcmstb_i2c_dev {
|
|||
#define bsc_writel(_dev, _val, _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,
|
||||
bool int_en)
|
||||
{
|
||||
|
@ -323,14 +337,16 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev,
|
|||
u8 *buf, unsigned int len,
|
||||
struct i2c_msg *pmsg)
|
||||
{
|
||||
int cnt, byte, rc;
|
||||
int cnt, byte, i, rc;
|
||||
enum bsc_xfer_cmd cmd;
|
||||
u32 ctl_reg;
|
||||
struct bsc_regs *pi2creg = dev->bsc_regmap;
|
||||
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 */
|
||||
if (no_ack || len <= N_DATA_BYTES) {
|
||||
if (no_ack || len <= xfersz) {
|
||||
cmd = (pmsg->flags & I2C_M_RD) ? CMD_RD_NOACK
|
||||
: CMD_WR_NOACK;
|
||||
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,
|
|||
pi2creg->ctl_reg = ctl_reg | DTF_RD_MASK;
|
||||
|
||||
/* set the read/write length */
|
||||
bsc_writel(dev, BSC_CNT_REG1_MASK & (len << BSC_CNT_REG1_SHIFT),
|
||||
cnt_reg);
|
||||
bsc_writel(dev, BSC_CNT_REG1_MASK(data_regsz) &
|
||||
(len << BSC_CNT_REG1_SHIFT), cnt_reg);
|
||||
|
||||
/* Write data into data_in register */
|
||||
|
||||
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;
|
||||
|
||||
for (byte = 0; byte < 4; byte++) {
|
||||
word >>= 8;
|
||||
for (byte = 0; byte < data_regsz; byte++) {
|
||||
word >>= BITS_PER_BYTE;
|
||||
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,
|
|||
return rc;
|
||||
}
|
||||
|
||||
/* Read data from data_out register */
|
||||
if (cmd == CMD_RD || cmd == CMD_RD_NOACK) {
|
||||
for (cnt = 0; cnt < len; cnt += 4) {
|
||||
u32 data = bsc_readl(dev, data_out[cnt >> 2]);
|
||||
for (cnt = 0, i = 0; cnt < len; cnt += data_regsz, i++) {
|
||||
u32 data = bsc_readl(dev, data_out[i]);
|
||||
|
||||
for (byte = 0; byte < 4 &&
|
||||
for (byte = 0; byte < data_regsz &&
|
||||
(byte + cnt) < len; byte++) {
|
||||
buf[cnt + byte] = data & 0xff;
|
||||
data >>= 8;
|
||||
data >>= BITS_PER_BYTE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -448,6 +467,7 @@ static int brcmstb_i2c_xfer(struct i2c_adapter *adapter,
|
|||
int bytes_to_xfer;
|
||||
u8 *tmp_buf;
|
||||
int len = 0;
|
||||
int xfersz = brcmstb_i2c_get_xfersz(dev);
|
||||
|
||||
if (dev->is_suspended)
|
||||
return -EBUSY;
|
||||
|
@ -482,9 +502,9 @@ static int brcmstb_i2c_xfer(struct i2c_adapter *adapter,
|
|||
|
||||
/* Perform data transfer */
|
||||
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,
|
||||
~(COND_START_STOP));
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
/* 4 byte data register */
|
||||
dev->bsc_regmap->ctlhi_reg = BSC_CTLHI_REG_DATAREG_SIZE_MASK;
|
||||
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;
|
||||
else
|
||||
dev->bsc_regmap->ctlhi_reg &= ~BSC_CTLHI_REG_DATAREG_SIZE_MASK;
|
||||
|
||||
bsc_writel(dev, dev->bsc_regmap->ctlhi_reg, ctlhi_reg);
|
||||
/* set bus speed */
|
||||
brcmstb_i2c_set_bus_speed(dev);
|
||||
|
@ -608,6 +632,13 @@ static int brcmstb_i2c_probe(struct platform_device *pdev)
|
|||
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);
|
||||
|
||||
/* Add the i2c adapter */
|
||||
|
@ -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[] = {
|
||||
{.compatible = "brcm,brcmstb-i2c"},
|
||||
{.compatible = "brcm,brcmper-i2c"},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, brcmstb_i2c_of_match);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
/* Register offsets for the I2C device. */
|
||||
#define CDNS_I2C_CR_OFFSET 0x00 /* Control Register, RW */
|
||||
|
@ -96,6 +97,8 @@
|
|||
CDNS_I2C_IXR_COMP)
|
||||
|
||||
#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
|
||||
/* FIFO depth at which the DATA interrupt occurs */
|
||||
|
@ -128,7 +131,6 @@
|
|||
* @xfer_done: Transfer complete status
|
||||
* @p_send_buf: Pointer to transmit 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
|
||||
* @recv_count: Number of bytes still expected to receive
|
||||
* @curr_recv_count: Number of bytes to be received in current transfer
|
||||
|
@ -141,6 +143,7 @@
|
|||
* @quirks: flag for broken hold bit usage in r1p10
|
||||
*/
|
||||
struct cdns_i2c {
|
||||
struct device *dev;
|
||||
void __iomem *membase;
|
||||
struct i2c_adapter adap;
|
||||
struct i2c_msg *p_msg;
|
||||
|
@ -148,7 +151,6 @@ struct cdns_i2c {
|
|||
struct completion xfer_done;
|
||||
unsigned char *p_send_buf;
|
||||
unsigned char *p_recv_buf;
|
||||
u8 suspended;
|
||||
unsigned int send_count;
|
||||
unsigned int 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,
|
|||
struct cdns_i2c *id = adap->algo_data;
|
||||
bool hold_quirk;
|
||||
|
||||
ret = pm_runtime_get_sync(id->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* Check if the bus is free */
|
||||
if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA)
|
||||
return -EAGAIN;
|
||||
if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA) {
|
||||
ret = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
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,
|
|||
if (msgs[count].flags & I2C_M_RD) {
|
||||
dev_warn(adap->dev.parent,
|
||||
"Can't do repeated start after a receive message\n");
|
||||
return -EOPNOTSUPP;
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
id->bus_hold_flag = 1;
|
||||
|
@ -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);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
/* Report the other error interrupts to application */
|
||||
if (id->err_status) {
|
||||
cdns_i2c_master_reset(adap);
|
||||
|
||||
if (id->err_status & CDNS_I2C_IXR_NACK)
|
||||
return -ENXIO;
|
||||
|
||||
return -EIO;
|
||||
if (id->err_status & CDNS_I2C_IXR_NACK) {
|
||||
ret = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
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
|
|||
struct clk_notifier_data *ndata = data;
|
||||
struct cdns_i2c *id = to_cdns_i2c(nb);
|
||||
|
||||
if (id->suspended)
|
||||
if (pm_runtime_suspended(id->dev))
|
||||
return NOTIFY_OK;
|
||||
|
||||
switch (event) {
|
||||
|
@ -808,14 +822,12 @@ static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
|
|||
*
|
||||
* 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, dev);
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct cdns_i2c *xi2c = platform_get_drvdata(pdev);
|
||||
|
||||
clk_disable(xi2c->clk);
|
||||
xi2c->suspended = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -828,26 +840,25 @@ static int __maybe_unused cdns_i2c_suspend(struct device *_dev)
|
|||
*
|
||||
* 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, dev);
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct cdns_i2c *xi2c = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = clk_enable(xi2c->clk);
|
||||
if (ret) {
|
||||
dev_err(_dev, "Cannot enable clock.\n");
|
||||
dev_err(dev, "Cannot enable clock.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
xi2c->suspended = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(cdns_i2c_dev_pm_ops, cdns_i2c_suspend,
|
||||
cdns_i2c_resume);
|
||||
static const struct dev_pm_ops cdns_i2c_dev_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(cdns_i2c_runtime_suspend,
|
||||
cdns_i2c_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct cdns_platform_data r1p10_i2c_def = {
|
||||
.quirks = CDNS_I2C_BROKEN_HOLD_BIT,
|
||||
|
@ -881,6 +892,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
|
|||
if (!id)
|
||||
return -ENOMEM;
|
||||
|
||||
id->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, id);
|
||||
|
||||
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)
|
|||
return PTR_ERR(id->clk);
|
||||
}
|
||||
ret = clk_prepare_enable(id->clk);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
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;
|
||||
if (clk_notifier_register(id->clk, &id->clk_rate_change_nb))
|
||||
dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
|
||||
|
@ -966,6 +982,8 @@ static int cdns_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
err_clk_dis:
|
||||
clk_disable_unprepare(id->clk);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -984,6 +1002,7 @@ static int cdns_i2c_remove(struct platform_device *pdev)
|
|||
i2c_del_adapter(&id->adap);
|
||||
clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
|
||||
clk_disable_unprepare(id->clk);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -271,6 +271,17 @@ static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable)
|
|||
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
|
||||
* @dev: device private data
|
||||
|
@ -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)
|
||||
{
|
||||
u32 input_clock_khz;
|
||||
u32 hcnt, lcnt;
|
||||
u32 reg;
|
||||
u32 sda_falling_time, scl_falling_time;
|
||||
|
@ -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);
|
||||
if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) {
|
||||
/* Configure register endianess access */
|
||||
|
@ -325,12 +333,12 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
|
|||
hcnt = dev->ss_hcnt;
|
||||
lcnt = dev->ss_lcnt;
|
||||
} 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 */
|
||||
sda_falling_time,
|
||||
0, /* 0: DW default, 1: Ideal */
|
||||
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 */
|
||||
scl_falling_time,
|
||||
0); /* No offset */
|
||||
|
@ -344,12 +352,12 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
|
|||
hcnt = dev->fs_hcnt;
|
||||
lcnt = dev->fs_lcnt;
|
||||
} 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 */
|
||||
sda_falling_time,
|
||||
0, /* 0: DW default, 1: Ideal */
|
||||
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 */
|
||||
scl_falling_time,
|
||||
0); /* No offset */
|
||||
|
@ -860,6 +868,7 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
|
|||
|
||||
snprintf(adap->name, sizeof(adap->name),
|
||||
"Synopsys DesignWare I2C adapter");
|
||||
adap->retries = 3;
|
||||
adap->algo = &i2c_dw_algo;
|
||||
adap->dev.parent = dev->dev;
|
||||
i2c_set_adapdata(adap, dev);
|
||||
|
|
|
@ -162,7 +162,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
|
|||
#ifdef CONFIG_PM
|
||||
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));
|
||||
return 0;
|
||||
|
@ -170,7 +170,7 @@ static int i2c_dw_pci_suspend(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));
|
||||
}
|
||||
|
|
|
@ -123,6 +123,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
|
|||
{ "80860F41", 0 },
|
||||
{ "808622C1", 0 },
|
||||
{ "AMD0010", ACCESS_INTR_MASK },
|
||||
{ "AMDI0510", 0 },
|
||||
{ "APMC0D0F", 0 },
|
||||
{ }
|
||||
};
|
||||
|
@ -134,6 +135,18 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
|
|||
}
|
||||
#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)
|
||||
{
|
||||
struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
|
@ -206,16 +219,13 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
|
|||
DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
|
||||
|
||||
dev->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
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 (!i2c_dw_plat_prepare_clk(dev, true)) {
|
||||
dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
|
||||
|
||||
if (!dev->sda_hold_time && ht) {
|
||||
u32 ic_clk = dev->get_clk_rate_khz(dev);
|
||||
|
||||
dev->sda_hold_time = div_u64((u64)ic_clk * ht + 500000,
|
||||
1000000);
|
||||
if (!dev->sda_hold_time && ht)
|
||||
dev->sda_hold_time = div_u64(
|
||||
(u64)dev->get_clk_rate_khz(dev) * ht + 500000,
|
||||
1000000);
|
||||
}
|
||||
|
||||
if (!dev->tx_fifo_depth) {
|
||||
|
@ -297,7 +307,7 @@ static int dw_i2c_plat_suspend(struct device *dev)
|
|||
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
|
||||
|
||||
i2c_dw_disable(i_dev);
|
||||
clk_disable_unprepare(i_dev->clk);
|
||||
i2c_dw_plat_prepare_clk(i_dev, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -307,7 +317,7 @@ static int dw_i2c_plat_resume(struct device *dev)
|
|||
struct platform_device *pdev = to_platform_device(dev);
|
||||
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)
|
||||
i2c_dw_init(i_dev);
|
||||
|
|
|
@ -795,6 +795,7 @@ static int pch_i2c_probe(struct pci_dev *pdev,
|
|||
/* base_addr + offset; */
|
||||
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_i2c_init(&adap_info->pch_data[i]);
|
||||
|
|
|
@ -71,6 +71,7 @@ struct em_i2c_device {
|
|||
struct i2c_adapter adap;
|
||||
struct completion msg_done;
|
||||
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)
|
||||
|
@ -226,22 +227,131 @@ static int em_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
|||
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)
|
||||
{
|
||||
struct em_i2c_device *priv = dev_id;
|
||||
|
||||
if (em_i2c_slave_irq(priv))
|
||||
return IRQ_HANDLED;
|
||||
|
||||
complete(&priv->msg_done);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
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 = {
|
||||
.master_xfer = em_i2c_xfer,
|
||||
.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)
|
||||
|
|
|
@ -99,7 +99,7 @@ static void dump_iic_regs(const char* header, struct ibm_iic_private* dev)
|
|||
#endif
|
||||
|
||||
/* Bus timings (in ns) for bit-banging */
|
||||
static struct i2c_timings {
|
||||
static struct ibm_iic_timings {
|
||||
unsigned int hd_sta;
|
||||
unsigned int su_sto;
|
||||
unsigned int low;
|
||||
|
@ -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)
|
||||
{
|
||||
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;
|
||||
int i, res;
|
||||
|
||||
|
|
|
@ -151,10 +151,11 @@
|
|||
#define INT_FIFO_EMPTYING BIT(12)
|
||||
#define INT_TRANSACTION_DONE BIT(15)
|
||||
#define INT_SLAVE_EVENT BIT(16)
|
||||
#define INT_MASTER_HALTED BIT(17)
|
||||
#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_EMPTY_EMPTYING (INT_FIFO_EMPTY | INT_FIFO_EMPTYING)
|
||||
|
||||
/* Level interrupts need clearing after handling instead of before */
|
||||
#define INT_LEVEL 0x01e00
|
||||
|
@ -177,7 +178,8 @@
|
|||
INT_FIFO_FULL | \
|
||||
INT_FIFO_FILLING | \
|
||||
INT_FIFO_EMPTY | \
|
||||
INT_FIFO_EMPTYING)
|
||||
INT_MASTER_HALTED | \
|
||||
INT_STOP_DETECTED)
|
||||
|
||||
#define INT_ENABLE_MASK_WAITSTOP (INT_SLAVE_EVENT | \
|
||||
INT_ADDR_ACK_ERR | \
|
||||
|
@ -511,7 +513,17 @@ static void img_i2c_soft_reset(struct img_i2c *i2c)
|
|||
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)
|
||||
{
|
||||
u32 val;
|
||||
|
@ -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_COUNT_REG, i2c->msg.len);
|
||||
|
||||
img_i2c_transaction_halt(i2c, false);
|
||||
mod_timer(&i2c->check_timer, jiffies + msecs_to_jiffies(1));
|
||||
}
|
||||
|
||||
|
@ -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_COUNT_REG, i2c->msg.len);
|
||||
|
||||
img_i2c_transaction_halt(i2c, false);
|
||||
mod_timer(&i2c->check_timer, jiffies + msecs_to_jiffies(1));
|
||||
img_i2c_write_fifo(i2c);
|
||||
|
||||
|
@ -750,7 +760,9 @@ static unsigned int img_i2c_atomic(struct img_i2c *i2c,
|
|||
next_cmd = CMD_RET_ACK;
|
||||
break;
|
||||
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) {
|
||||
next_cmd = CMD_GEN_STOP;
|
||||
} else if (i2c->msg.flags & I2C_M_RD) {
|
||||
|
@ -858,34 +870,42 @@ static unsigned int img_i2c_auto(struct img_i2c *i2c,
|
|||
|
||||
/* Enable transaction halt on start bit */
|
||||
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 */
|
||||
i2c->int_enable &= ~INT_SLAVE_EVENT;
|
||||
}
|
||||
|
||||
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 (int_status & INT_FIFO_FULL_FILLING) {
|
||||
if (int_status & (INT_FIFO_FULL_FILLING | INT_MASTER_HALTED)) {
|
||||
img_i2c_read_fifo(i2c);
|
||||
if (i2c->msg.len == 0)
|
||||
return ISR_WAITSTOP;
|
||||
}
|
||||
} else {
|
||||
if (int_status & INT_FIFO_EMPTY_EMPTYING) {
|
||||
/*
|
||||
* 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 | INT_MASTER_HALTED)) {
|
||||
if ((int_status & INT_FIFO_EMPTY) &&
|
||||
i2c->msg.len == 0)
|
||||
return ISR_WAITSTOP;
|
||||
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;
|
||||
}
|
||||
|
@ -1017,20 +1037,23 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
|||
return -EIO;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if (likely(msgs[i].len))
|
||||
continue;
|
||||
/*
|
||||
* 0 byte reads are not possible because the slave could try
|
||||
* 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;
|
||||
/*
|
||||
* 0 byte writes are possible and used for probing, but we
|
||||
* cannot do them in automatic mode, so use atomic mode
|
||||
* instead.
|
||||
*
|
||||
* Also, the I2C_M_IGNORE_NAK mode can only be implemented
|
||||
* in atomic mode.
|
||||
*/
|
||||
atomic = true;
|
||||
if (!msgs[i].len ||
|
||||
(msgs[i].flags & I2C_M_IGNORE_NAK))
|
||||
atomic = true;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(i2c->scb_clk);
|
||||
|
@ -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_CLEAR_REG, ~0);
|
||||
|
||||
if (atomic)
|
||||
if (atomic) {
|
||||
img_i2c_atomic_start(i2c);
|
||||
else if (msg->flags & I2C_M_RD)
|
||||
img_i2c_read(i2c);
|
||||
else
|
||||
img_i2c_write(i2c);
|
||||
} 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);
|
||||
else
|
||||
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);
|
||||
|
||||
time_left = wait_for_completion_timeout(&i2c->msg_complete,
|
||||
|
|
|
@ -29,9 +29,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
/** Includes *******************************************************************
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
|
@ -53,12 +50,10 @@
|
|||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_data/i2c-imx.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/** Defines ********************************************************************
|
||||
*******************************************************************************/
|
||||
|
||||
/* This will be the driver name the kernel reports */
|
||||
#define DRIVER_NAME "imx-i2c"
|
||||
|
||||
|
@ -120,8 +115,7 @@
|
|||
#define I2CR_IEN_OPCODE_0 0x0
|
||||
#define I2CR_IEN_OPCODE_1 I2CR_IEN
|
||||
|
||||
/** Variables ******************************************************************
|
||||
*******************************************************************************/
|
||||
#define I2C_PM_TIMEOUT 10 /* ms */
|
||||
|
||||
/*
|
||||
* sorted list of clock divider, register value pairs
|
||||
|
@ -346,7 +340,7 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
|
|||
dma_release_channel(dma->chan_tx);
|
||||
fail_al:
|
||||
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)
|
||||
|
@ -393,6 +387,7 @@ static int i2c_imx_dma_xfer(struct imx_i2c_struct *i2c_imx,
|
|||
return 0;
|
||||
|
||||
err_submit:
|
||||
dmaengine_terminate_all(dma->chan_using);
|
||||
err_desc:
|
||||
dma_unmap_single(chan_dev, dma->dma_buf,
|
||||
dma->dma_len, dma->dma_data_dir);
|
||||
|
@ -416,9 +411,6 @@ static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx)
|
|||
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)
|
||||
{
|
||||
unsigned long orig_jiffies = jiffies;
|
||||
|
@ -527,9 +519,6 @@ static int i2c_imx_start(struct imx_i2c_struct *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);
|
||||
/* Enable I2C controller */
|
||||
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)
|
|||
/* Disable I2C controller */
|
||||
temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
|
||||
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)
|
||||
|
@ -901,6 +889,10 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
|
|||
|
||||
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 */
|
||||
result = i2c_imx_start(i2c_imx);
|
||||
if (result) {
|
||||
|
@ -964,6 +956,10 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
|
|||
/* Stop I2C transfer */
|
||||
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__,
|
||||
(result < 0) ? "error" : "success msg",
|
||||
(result < 0) ? result : num);
|
||||
|
@ -997,10 +993,8 @@ static void i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
|
|||
PINCTRL_STATE_DEFAULT);
|
||||
i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl,
|
||||
"gpio");
|
||||
rinfo->sda_gpio = of_get_named_gpio_flags(pdev->dev.of_node,
|
||||
"sda-gpios", 0, NULL);
|
||||
rinfo->scl_gpio = of_get_named_gpio_flags(pdev->dev.of_node,
|
||||
"scl-gpios", 0, NULL);
|
||||
rinfo->sda_gpio = of_get_named_gpio(pdev->dev.of_node, "sda-gpios", 0);
|
||||
rinfo->scl_gpio = of_get_named_gpio(pdev->dev.of_node, "scl-gpios", 0);
|
||||
|
||||
if (!gpio_is_valid(rinfo->sda_gpio) ||
|
||||
!gpio_is_valid(rinfo->scl_gpio) ||
|
||||
|
@ -1083,7 +1077,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
|||
|
||||
ret = clk_prepare_enable(i2c_imx->clk);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1107,6 +1101,18 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
|||
/* Set up adapter data */
|
||||
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 */
|
||||
i2c_imx->bitrate = IMX_I2C_BIT_RATE;
|
||||
ret = of_property_read_u32(pdev->dev.of_node,
|
||||
|
@ -1125,12 +1131,11 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
|||
ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "registration failed\n");
|
||||
goto clk_disable;
|
||||
goto rpm_disable;
|
||||
}
|
||||
|
||||
/* Set up platform driver data */
|
||||
platform_set_drvdata(pdev, i2c_imx);
|
||||
clk_disable_unprepare(i2c_imx->clk);
|
||||
pm_runtime_mark_last_busy(&pdev->dev);
|
||||
pm_runtime_put_autosuspend(&pdev->dev);
|
||||
|
||||
dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", irq);
|
||||
dev_dbg(&i2c_imx->adapter.dev, "device resources: %pR\n", res);
|
||||
|
@ -1143,6 +1148,12 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
|||
|
||||
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_unprepare(i2c_imx->clk);
|
||||
return ret;
|
||||
|
@ -1151,6 +1162,11 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
|||
static int i2c_imx_remove(struct platform_device *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 */
|
||||
dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n");
|
||||
|
@ -1165,17 +1181,54 @@ 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_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;
|
||||
}
|
||||
|
||||
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 = {
|
||||
.probe = i2c_imx_probe,
|
||||
.remove = i2c_imx_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.pm = I2C_IMX_PM_OPS,
|
||||
.of_match_table = i2c_imx_dt_ids,
|
||||
},
|
||||
.id_table = imx_i2c_devtype,
|
||||
.id_table = imx_i2c_devtype,
|
||||
};
|
||||
|
||||
static int __init i2c_adap_imx_init(void)
|
||||
|
|
|
@ -132,6 +132,7 @@ struct mtk_i2c_compatible {
|
|||
unsigned char pmic_i2c: 1;
|
||||
unsigned char dcm: 1;
|
||||
unsigned char auto_restart: 1;
|
||||
unsigned char aux_len_reg: 1;
|
||||
};
|
||||
|
||||
struct mtk_i2c {
|
||||
|
@ -153,6 +154,8 @@ struct mtk_i2c {
|
|||
enum mtk_trans_op op;
|
||||
u16 timing_reg;
|
||||
u16 high_speed_reg;
|
||||
unsigned char auto_restart;
|
||||
bool ignore_restart_irq;
|
||||
const struct mtk_i2c_compatible *dev_comp;
|
||||
};
|
||||
|
||||
|
@ -178,6 +181,7 @@ static const struct mtk_i2c_compatible mt6577_compat = {
|
|||
.pmic_i2c = 0,
|
||||
.dcm = 1,
|
||||
.auto_restart = 0,
|
||||
.aux_len_reg = 0,
|
||||
};
|
||||
|
||||
static const struct mtk_i2c_compatible mt6589_compat = {
|
||||
|
@ -185,6 +189,7 @@ static const struct mtk_i2c_compatible mt6589_compat = {
|
|||
.pmic_i2c = 1,
|
||||
.dcm = 0,
|
||||
.auto_restart = 0,
|
||||
.aux_len_reg = 0,
|
||||
};
|
||||
|
||||
static const struct mtk_i2c_compatible mt8173_compat = {
|
||||
|
@ -192,6 +197,7 @@ static const struct mtk_i2c_compatible mt8173_compat = {
|
|||
.pmic_i2c = 0,
|
||||
.dcm = 1,
|
||||
.auto_restart = 1,
|
||||
.aux_len_reg = 1,
|
||||
};
|
||||
|
||||
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,
|
|||
|
||||
i2c->irq_stat = 0;
|
||||
|
||||
if (i2c->dev_comp->auto_restart)
|
||||
if (i2c->auto_restart)
|
||||
restart_flag = I2C_RS_TRANSFER;
|
||||
|
||||
reinit_completion(&i2c->msg_complete);
|
||||
|
@ -411,8 +417,14 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
|||
|
||||
/* Set transfer and transaction len */
|
||||
if (i2c->op == I2C_MASTER_WRRD) {
|
||||
writew(msgs->len | ((msgs + 1)->len) << 8,
|
||||
i2c->base + OFFSET_TRANSFER_LEN);
|
||||
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,
|
||||
i2c->base + OFFSET_TRANSFER_LEN);
|
||||
}
|
||||
writew(I2C_WRRD_TRANAC_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
|
||||
} else {
|
||||
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,
|
|||
|
||||
writel(I2C_DMA_START_EN, i2c->pdmabase + OFFSET_EN);
|
||||
|
||||
if (!i2c->dev_comp->auto_restart) {
|
||||
if (!i2c->auto_restart) {
|
||||
start_reg = I2C_TRANSAC_START;
|
||||
} else {
|
||||
start_reg = I2C_TRANSAC_START | I2C_RS_MUL_TRIG;
|
||||
|
@ -518,6 +530,24 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
|
|||
if (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--) {
|
||||
if (!msgs->buf) {
|
||||
dev_dbg(i2c->dev, "data buffer is NULL.\n");
|
||||
|
@ -530,7 +560,7 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
|
|||
else
|
||||
i2c->op = I2C_MASTER_WR;
|
||||
|
||||
if (!i2c->dev_comp->auto_restart) {
|
||||
if (!i2c->auto_restart) {
|
||||
if (num > 1) {
|
||||
/* combined two messages into one transaction */
|
||||
i2c->op = I2C_MASTER_WRRD;
|
||||
|
@ -559,7 +589,7 @@ static irqreturn_t mtk_i2c_irq(int irqno, void *dev_id)
|
|||
u16 restart_flag = 0;
|
||||
u16 intr_stat;
|
||||
|
||||
if (i2c->dev_comp->auto_restart)
|
||||
if (i2c->auto_restart)
|
||||
restart_flag = I2C_RS_TRANSFER;
|
||||
|
||||
intr_stat = readw(i2c->base + OFFSET_INTR_STAT);
|
||||
|
@ -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 |= intr_stat;
|
||||
if (i2c->irq_stat & (I2C_TRANSAC_COMP | restart_flag))
|
||||
complete(&i2c->msg_complete);
|
||||
|
||||
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))
|
||||
complete(&i2c->msg_complete);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
|
||||
Note: we assume there can only be one device, with one or more
|
||||
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>
|
||||
|
@ -37,6 +40,7 @@
|
|||
#include <linux/dmi.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
|
||||
/* PIIX4 SMBus address offsets */
|
||||
|
@ -75,6 +79,16 @@
|
|||
#define PIIX4_WORD_DATA 0x0C
|
||||
#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 */
|
||||
|
||||
/* 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[] = {
|
|||
{ },
|
||||
};
|
||||
|
||||
/* 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 {
|
||||
unsigned short smba;
|
||||
|
||||
/* SB800 */
|
||||
bool sb800_main;
|
||||
unsigned short port;
|
||||
struct mutex *mutex;
|
||||
};
|
||||
|
||||
static int piix4_setup(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)
|
||||
{
|
||||
unsigned short piix4_smba;
|
||||
unsigned short smba_idx = 0xcd6;
|
||||
u8 smba_en_lo, smba_en_hi, smb_en, smb_en_status;
|
||||
u8 i2ccfg, i2ccfg_offset = 0x10;
|
||||
|
||||
|
@ -251,16 +275,10 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
|
|||
else
|
||||
smb_en = (aux) ? 0x28 : 0x2c;
|
||||
|
||||
if (!request_region(smba_idx, 2, "smba_idx")) {
|
||||
dev_err(&PIIX4_dev->dev, "SMBus base address index region "
|
||||
"0x%x already in use!\n", smba_idx);
|
||||
return -EBUSY;
|
||||
}
|
||||
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);
|
||||
outb_p(smb_en, SB800_PIIX4_SMB_IDX);
|
||||
smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1);
|
||||
outb_p(smb_en + 1, SB800_PIIX4_SMB_IDX);
|
||||
smba_en_hi = inb_p(SB800_PIIX4_SMB_IDX + 1);
|
||||
|
||||
if (!smb_en) {
|
||||
smb_en_status = smba_en_lo & 0x10;
|
||||
|
@ -483,7 +501,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
|
|||
if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
|
||||
return -EINVAL;
|
||||
outb_p(len, SMBHSTDAT0);
|
||||
i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
|
||||
inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
|
||||
for (i = 1; i <= len; i++)
|
||||
outb_p(data->block[i], SMBBLKDAT);
|
||||
}
|
||||
|
@ -516,7 +534,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
|
|||
data->block[0] = inb_p(SMBHSTDAT0);
|
||||
if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
|
||||
return -EPROTO;
|
||||
i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
|
||||
inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
|
||||
for (i = 1; i <= data->block[0]; i++)
|
||||
data->block[i] = inb_p(SMBBLKDAT);
|
||||
break;
|
||||
|
@ -524,6 +542,43 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
|
|||
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)
|
||||
{
|
||||
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
|
||||
|
@ -536,6 +591,11 @@ static const struct i2c_algorithm smbus_algorithm = {
|
|||
.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[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_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[] = {
|
|||
|
||||
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 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_piix4_adapdata *adapdata;
|
||||
|
@ -594,7 +654,7 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
|
|||
adap->dev.parent = &dev->dev;
|
||||
|
||||
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);
|
||||
|
||||
|
@ -611,6 +671,54 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
|
|||
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)
|
||||
{
|
||||
int retval;
|
||||
|
@ -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 &&
|
||||
dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
|
||||
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 */
|
||||
retval = piix4_setup_sb800(dev, id, 0);
|
||||
else
|
||||
if (retval < 0) {
|
||||
release_region(SB800_PIIX4_SMB_IDX, 2);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
return retval;
|
||||
|
||||
/* If no main SMBus found, give up */
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
/* Try to register main SMBus adapter, give up if we can't */
|
||||
retval = piix4_add_adapter(dev, retval, &piix4_main_adapter);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
/* Try to register main SMBus adapter, give up if we can't */
|
||||
retval = piix4_add_adapter(dev, retval, "main",
|
||||
&piix4_main_adapters[0]);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Check for auxiliary SMBus on some AMD chipsets */
|
||||
retval = -ENODEV;
|
||||
|
@ -654,7 +783,8 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||
if (retval > 0) {
|
||||
/* Try to add the aux adapter if it exists,
|
||||
* 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;
|
||||
|
@ -666,7 +796,13 @@ static void piix4_adap_remove(struct i2c_adapter *adap)
|
|||
|
||||
if (adapdata->smba) {
|
||||
i2c_del_adapter(adap);
|
||||
release_region(adapdata->smba, SMBIOSIZE);
|
||||
if (adapdata->port == 0) {
|
||||
release_region(adapdata->smba, SMBIOSIZE);
|
||||
if (adapdata->sb800_main) {
|
||||
kfree(adapdata->mutex);
|
||||
release_region(SB800_PIIX4_SMB_IDX, 2);
|
||||
}
|
||||
}
|
||||
kfree(adapdata);
|
||||
kfree(adap);
|
||||
}
|
||||
|
@ -674,9 +810,13 @@ static void piix4_adap_remove(struct i2c_adapter *adap)
|
|||
|
||||
static void piix4_remove(struct pci_dev *dev)
|
||||
{
|
||||
if (piix4_main_adapter) {
|
||||
piix4_adap_remove(piix4_main_adapter);
|
||||
piix4_main_adapter = NULL;
|
||||
int port = PIIX4_MAX_ADAPTERS;
|
||||
|
||||
while (--port >= 0) {
|
||||
if (piix4_main_adapters[port]) {
|
||||
piix4_adap_remove(piix4_main_adapters[port]);
|
||||
piix4_main_adapters[port] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (piix4_aux_adapter) {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
/*
|
||||
* Driver for the Renesas RCar I2C unit
|
||||
*
|
||||
* Copyright (C) 2014 Wolfram Sang <wsa@sang-engineering.com>
|
||||
* Copyright (C) 2014-15 Wolfram Sang <wsa@sang-engineering.com>
|
||||
* Copyright (C) 2011-2015 Renesas Electronics Corporation
|
||||
*
|
||||
* Copyright (C) 2012-14 Renesas Solutions Corp.
|
||||
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
|
||||
|
@ -9,9 +10,6 @@
|
|||
* This file is based on the drivers/i2c/busses/i2c-sh7760.c
|
||||
* (c) 2005-2008 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com>
|
||||
*
|
||||
* This file used out-of-tree driver i2c-rcar.c
|
||||
* Copyright (C) 2011-2012 Renesas Electronics Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
|
@ -33,7 +31,6 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
/* register offsets */
|
||||
#define ICSCR 0x00 /* slave ctrl */
|
||||
|
@ -84,6 +81,7 @@
|
|||
|
||||
#define RCAR_BUS_PHASE_START (MDBS | MIE | ESG)
|
||||
#define RCAR_BUS_PHASE_DATA (MDBS | MIE)
|
||||
#define RCAR_BUS_MASK_DATA (~(ESG | FSB) & 0xFF)
|
||||
#define RCAR_BUS_PHASE_STOP (MDBS | MIE | FSB)
|
||||
|
||||
#define RCAR_IRQ_SEND (MNR | MAL | MST | MAT | MDE)
|
||||
|
@ -94,10 +92,13 @@
|
|||
#define RCAR_IRQ_ACK_RECV (~(MAT | MDR) & 0xFF)
|
||||
|
||||
#define ID_LAST_MSG (1 << 0)
|
||||
#define ID_IOERROR (1 << 1)
|
||||
#define ID_FIRST_MSG (1 << 1)
|
||||
#define ID_DONE (1 << 2)
|
||||
#define ID_ARBLOST (1 << 3)
|
||||
#define ID_NACK (1 << 4)
|
||||
/* persistent flags */
|
||||
#define ID_P_PM_BLOCKED (1 << 31)
|
||||
#define ID_P_MASK ID_P_PM_BLOCKED
|
||||
|
||||
enum rcar_i2c_type {
|
||||
I2C_RCAR_GEN1,
|
||||
|
@ -108,10 +109,10 @@ enum rcar_i2c_type {
|
|||
struct rcar_i2c_priv {
|
||||
void __iomem *io;
|
||||
struct i2c_adapter adap;
|
||||
struct i2c_msg *msg;
|
||||
struct i2c_msg *msg;
|
||||
int msgs_left;
|
||||
struct clk *clk;
|
||||
|
||||
spinlock_t lock;
|
||||
wait_queue_head_t wait;
|
||||
|
||||
int pos;
|
||||
|
@ -124,9 +125,6 @@ struct rcar_i2c_priv {
|
|||
#define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent)
|
||||
#define rcar_i2c_is_recv(p) ((p)->msg->flags & I2C_M_RD)
|
||||
|
||||
#define rcar_i2c_flags_set(p, f) ((p)->flags |= (f))
|
||||
#define rcar_i2c_flags_has(p, f) ((p)->flags & (f))
|
||||
|
||||
#define LOOP_TIMEOUT 1024
|
||||
|
||||
|
||||
|
@ -144,9 +142,10 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv)
|
|||
{
|
||||
/* reset master mode */
|
||||
rcar_i2c_write(priv, ICMIER, 0);
|
||||
rcar_i2c_write(priv, ICMCR, 0);
|
||||
rcar_i2c_write(priv, ICMCR, MDBS);
|
||||
rcar_i2c_write(priv, ICMSR, 0);
|
||||
rcar_i2c_write(priv, ICMAR, 0);
|
||||
/* start clock */
|
||||
rcar_i2c_write(priv, ICCCR, priv->icccr);
|
||||
}
|
||||
|
||||
static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
|
||||
|
@ -163,15 +162,17 @@ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
|
||||
u32 bus_speed,
|
||||
struct device *dev)
|
||||
static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, struct i2c_timings *t)
|
||||
{
|
||||
u32 scgd, cdf;
|
||||
u32 round, ick;
|
||||
u32 scl;
|
||||
u32 cdf_width;
|
||||
u32 scgd, cdf, round, ick, sum, scl, cdf_width;
|
||||
unsigned long rate;
|
||||
struct device *dev = rcar_i2c_priv_to_dev(priv);
|
||||
|
||||
/* Fall back to previously used values if not supplied */
|
||||
t->bus_freq_hz = t->bus_freq_hz ?: 100000;
|
||||
t->scl_fall_ns = t->scl_fall_ns ?: 35;
|
||||
t->scl_rise_ns = t->scl_rise_ns ?: 200;
|
||||
t->scl_int_delay_ns = t->scl_int_delay_ns ?: 50;
|
||||
|
||||
switch (priv->devtype) {
|
||||
case I2C_RCAR_GEN1:
|
||||
|
@ -195,9 +196,9 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
|
|||
* SCL = ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick])
|
||||
*
|
||||
* ick : I2C internal clock < 20 MHz
|
||||
* ticf : I2C SCL falling time = 35 ns here
|
||||
* tr : I2C SCL rising time = 200 ns here
|
||||
* intd : LSI internal delay = 50 ns here
|
||||
* ticf : I2C SCL falling time
|
||||
* tr : I2C SCL rising time
|
||||
* intd : LSI internal delay
|
||||
* clkp : peripheral_clk
|
||||
* F[] : integer up-valuation
|
||||
*/
|
||||
|
@ -213,12 +214,12 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
|
|||
* it is impossible to calculate large scale
|
||||
* number on u32. separate it
|
||||
*
|
||||
* F[(ticf + tr + intd) * ick]
|
||||
* = F[(35 + 200 + 50)ns * ick]
|
||||
* = F[285 * ick / 1000000000]
|
||||
* = F[(ick / 1000000) * 285 / 1000]
|
||||
* F[(ticf + tr + intd) * ick] with sum = (ticf + tr + intd)
|
||||
* = F[sum * ick / 1000000000]
|
||||
* = F[(ick / 1000000) * sum / 1000]
|
||||
*/
|
||||
round = (ick + 500000) / 1000000 * 285;
|
||||
sum = t->scl_fall_ns + t->scl_rise_ns + t->scl_int_delay_ns;
|
||||
round = (ick + 500000) / 1000000 * sum;
|
||||
round = (round + 500) / 1000;
|
||||
|
||||
/*
|
||||
|
@ -235,7 +236,7 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
|
|||
*/
|
||||
for (scgd = 0; scgd < 0x40; scgd++) {
|
||||
scl = ick / (20 + (scgd * 8) + round);
|
||||
if (scl <= bus_speed)
|
||||
if (scl <= t->bus_freq_hz)
|
||||
goto scgd_find;
|
||||
}
|
||||
dev_err(dev, "it is impossible to calculate best SCL\n");
|
||||
|
@ -243,11 +244,9 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
|
|||
|
||||
scgd_find:
|
||||
dev_dbg(dev, "clk %d/%d(%lu), round %u, CDF:0x%x, SCGD: 0x%x\n",
|
||||
scl, bus_speed, clk_get_rate(priv->clk), round, cdf, scgd);
|
||||
scl, t->bus_freq_hz, clk_get_rate(priv->clk), round, cdf, scgd);
|
||||
|
||||
/*
|
||||
* keep icccr value
|
||||
*/
|
||||
/* keep icccr value */
|
||||
priv->icccr = scgd << cdf_width | cdf;
|
||||
|
||||
return 0;
|
||||
|
@ -257,33 +256,44 @@ static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv)
|
|||
{
|
||||
int read = !!rcar_i2c_is_recv(priv);
|
||||
|
||||
priv->pos = 0;
|
||||
if (priv->msgs_left == 1)
|
||||
priv->flags |= ID_LAST_MSG;
|
||||
|
||||
rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | read);
|
||||
rcar_i2c_write(priv, ICMSR, 0);
|
||||
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
|
||||
/*
|
||||
* We don't have a testcase but the HW engineers say that the write order
|
||||
* of ICMSR and ICMCR depends on whether we issue START or REP_START. Since
|
||||
* it didn't cause a drawback for me, let's rather be safe than sorry.
|
||||
*/
|
||||
if (priv->flags & ID_FIRST_MSG) {
|
||||
rcar_i2c_write(priv, ICMSR, 0);
|
||||
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
|
||||
} else {
|
||||
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
|
||||
rcar_i2c_write(priv, ICMSR, 0);
|
||||
}
|
||||
rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND);
|
||||
}
|
||||
|
||||
static void rcar_i2c_next_msg(struct rcar_i2c_priv *priv)
|
||||
{
|
||||
priv->msg++;
|
||||
priv->msgs_left--;
|
||||
priv->flags &= ID_P_MASK;
|
||||
rcar_i2c_prepare_msg(priv);
|
||||
}
|
||||
|
||||
/*
|
||||
* interrupt functions
|
||||
*/
|
||||
static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
|
||||
static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
|
||||
{
|
||||
struct i2c_msg *msg = priv->msg;
|
||||
|
||||
/*
|
||||
* FIXME
|
||||
* sometimes, unknown interrupt happened.
|
||||
* Do nothing
|
||||
*/
|
||||
/* FIXME: sometimes, unknown interrupt happened. Do nothing */
|
||||
if (!(msr & MDE))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If address transfer phase finished,
|
||||
* goto data phase.
|
||||
*/
|
||||
if (msr & MAT)
|
||||
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
|
||||
return;
|
||||
|
||||
if (priv->pos < msg->len) {
|
||||
/*
|
||||
|
@ -305,67 +315,50 @@ static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
|
|||
* [ICRXTX] -> [SHIFT] -> [I2C bus]
|
||||
*/
|
||||
|
||||
if (priv->flags & ID_LAST_MSG)
|
||||
if (priv->flags & ID_LAST_MSG) {
|
||||
/*
|
||||
* If current msg is the _LAST_ msg,
|
||||
* prepare stop condition here.
|
||||
* ID_DONE will be set on STOP irq.
|
||||
*/
|
||||
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
|
||||
else
|
||||
/*
|
||||
* If current msg is _NOT_ last msg,
|
||||
* it doesn't call stop phase.
|
||||
* thus, there is no STOP irq.
|
||||
* return ID_DONE here.
|
||||
*/
|
||||
return ID_DONE;
|
||||
} else {
|
||||
rcar_i2c_next_msg(priv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_SEND);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
|
||||
static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
|
||||
{
|
||||
struct i2c_msg *msg = priv->msg;
|
||||
|
||||
/*
|
||||
* FIXME
|
||||
* sometimes, unknown interrupt happened.
|
||||
* Do nothing
|
||||
*/
|
||||
/* FIXME: sometimes, unknown interrupt happened. Do nothing */
|
||||
if (!(msr & MDR))
|
||||
return 0;
|
||||
return;
|
||||
|
||||
if (msr & MAT) {
|
||||
/*
|
||||
* Address transfer phase finished,
|
||||
* but, there is no data at this point.
|
||||
* Do nothing.
|
||||
*/
|
||||
/* Address transfer phase finished, but no data at this point. */
|
||||
} else if (priv->pos < msg->len) {
|
||||
/*
|
||||
* get received data
|
||||
*/
|
||||
/* get received data */
|
||||
msg->buf[priv->pos] = rcar_i2c_read(priv, ICRXTX);
|
||||
priv->pos++;
|
||||
}
|
||||
|
||||
/*
|
||||
* If next received data is the _LAST_,
|
||||
* go to STOP phase,
|
||||
* otherwise, go to DATA phase.
|
||||
* If next received data is the _LAST_, go to STOP phase. Might be
|
||||
* overwritten by REP START when setting up a new msg. Not elegant
|
||||
* but the only stable sequence for REP START I have found so far.
|
||||
*/
|
||||
if (priv->pos + 1 >= msg->len)
|
||||
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
|
||||
|
||||
if (priv->pos == msg->len && !(priv->flags & ID_LAST_MSG))
|
||||
rcar_i2c_next_msg(priv);
|
||||
else
|
||||
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
|
||||
|
||||
rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_RECV);
|
||||
|
||||
return 0;
|
||||
rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_RECV);
|
||||
}
|
||||
|
||||
static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
|
||||
|
@ -426,62 +419,57 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
|
|||
static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
|
||||
{
|
||||
struct rcar_i2c_priv *priv = ptr;
|
||||
irqreturn_t result = IRQ_HANDLED;
|
||||
u32 msr;
|
||||
u32 msr, val;
|
||||
|
||||
/*-------------- spin lock -----------------*/
|
||||
spin_lock(&priv->lock);
|
||||
|
||||
if (rcar_i2c_slave_irq(priv))
|
||||
goto exit;
|
||||
/* Clear START or STOP as soon as we can */
|
||||
val = rcar_i2c_read(priv, ICMCR);
|
||||
rcar_i2c_write(priv, ICMCR, val & RCAR_BUS_MASK_DATA);
|
||||
|
||||
msr = rcar_i2c_read(priv, ICMSR);
|
||||
|
||||
/* Only handle interrupts that are currently enabled */
|
||||
msr &= rcar_i2c_read(priv, ICMIER);
|
||||
if (!msr) {
|
||||
result = IRQ_NONE;
|
||||
goto exit;
|
||||
if (rcar_i2c_slave_irq(priv))
|
||||
return IRQ_HANDLED;
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/* Arbitration lost */
|
||||
if (msr & MAL) {
|
||||
rcar_i2c_flags_set(priv, (ID_DONE | ID_ARBLOST));
|
||||
priv->flags |= ID_DONE | ID_ARBLOST;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Nack */
|
||||
if (msr & MNR) {
|
||||
/* go to stop phase */
|
||||
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
|
||||
/* HW automatically sends STOP after received NACK */
|
||||
rcar_i2c_write(priv, ICMIER, RCAR_IRQ_STOP);
|
||||
rcar_i2c_flags_set(priv, ID_NACK);
|
||||
priv->flags |= ID_NACK;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Stop */
|
||||
if (msr & MST) {
|
||||
rcar_i2c_flags_set(priv, ID_DONE);
|
||||
priv->msgs_left--; /* The last message also made it */
|
||||
priv->flags |= ID_DONE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rcar_i2c_is_recv(priv))
|
||||
rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr));
|
||||
rcar_i2c_irq_recv(priv, msr);
|
||||
else
|
||||
rcar_i2c_flags_set(priv, rcar_i2c_irq_send(priv, msr));
|
||||
rcar_i2c_irq_send(priv, msr);
|
||||
|
||||
out:
|
||||
if (rcar_i2c_flags_has(priv, ID_DONE)) {
|
||||
if (priv->flags & ID_DONE) {
|
||||
rcar_i2c_write(priv, ICMIER, 0);
|
||||
rcar_i2c_write(priv, ICMSR, 0);
|
||||
wake_up(&priv->wait);
|
||||
}
|
||||
|
||||
exit:
|
||||
spin_unlock(&priv->lock);
|
||||
/*-------------- spin unlock -----------------*/
|
||||
|
||||
return result;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
|
||||
|
@ -490,22 +478,11 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
|
|||
{
|
||||
struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
|
||||
struct device *dev = rcar_i2c_priv_to_dev(priv);
|
||||
unsigned long flags;
|
||||
int i, ret;
|
||||
long timeout;
|
||||
long time_left;
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
/*-------------- spin lock -----------------*/
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
rcar_i2c_init(priv);
|
||||
/* start clock */
|
||||
rcar_i2c_write(priv, ICCCR, priv->icccr);
|
||||
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
/*-------------- spin unlock -----------------*/
|
||||
|
||||
ret = rcar_i2c_bus_barrier(priv);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
@ -514,48 +491,27 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
|
|||
/* This HW can't send STOP after address phase */
|
||||
if (msgs[i].len == 0) {
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------- spin lock -----------------*/
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
/* init first message */
|
||||
priv->msg = msgs;
|
||||
priv->msgs_left = num;
|
||||
priv->flags = (priv->flags & ID_P_MASK) | ID_FIRST_MSG;
|
||||
rcar_i2c_prepare_msg(priv);
|
||||
|
||||
/* init each data */
|
||||
priv->msg = &msgs[i];
|
||||
priv->pos = 0;
|
||||
priv->flags = 0;
|
||||
if (i == num - 1)
|
||||
rcar_i2c_flags_set(priv, ID_LAST_MSG);
|
||||
|
||||
rcar_i2c_prepare_msg(priv);
|
||||
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
/*-------------- spin unlock -----------------*/
|
||||
|
||||
timeout = wait_event_timeout(priv->wait,
|
||||
rcar_i2c_flags_has(priv, ID_DONE),
|
||||
adap->timeout);
|
||||
if (!timeout) {
|
||||
ret = -ETIMEDOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rcar_i2c_flags_has(priv, ID_NACK)) {
|
||||
ret = -ENXIO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rcar_i2c_flags_has(priv, ID_ARBLOST)) {
|
||||
ret = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rcar_i2c_flags_has(priv, ID_IOERROR)) {
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = i + 1; /* The number of transfer */
|
||||
time_left = wait_event_timeout(priv->wait, priv->flags & ID_DONE,
|
||||
num * adap->timeout);
|
||||
if (!time_left) {
|
||||
rcar_i2c_init(priv);
|
||||
ret = -ETIMEDOUT;
|
||||
} else if (priv->flags & ID_NACK) {
|
||||
ret = -ENXIO;
|
||||
} else if (priv->flags & ID_ARBLOST) {
|
||||
ret = -EAGAIN;
|
||||
} else {
|
||||
ret = num - priv->msgs_left; /* The number of transfer */
|
||||
}
|
||||
out:
|
||||
pm_runtime_put(dev);
|
||||
|
@ -637,7 +593,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
|
|||
struct i2c_adapter *adap;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
u32 bus_speed;
|
||||
struct i2c_timings i2c_t;
|
||||
int irq, ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL);
|
||||
|
@ -650,23 +606,13 @@ static int rcar_i2c_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(priv->clk);
|
||||
}
|
||||
|
||||
bus_speed = 100000; /* default 100 kHz */
|
||||
of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed);
|
||||
|
||||
priv->devtype = (enum rcar_i2c_type)of_match_device(rcar_i2c_dt_ids, dev)->data;
|
||||
|
||||
ret = rcar_i2c_clock_calculate(priv, bus_speed, dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->io = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->io))
|
||||
return PTR_ERR(priv->io);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
priv->devtype = (enum rcar_i2c_type)of_match_device(rcar_i2c_dt_ids, dev)->data;
|
||||
init_waitqueue_head(&priv->wait);
|
||||
spin_lock_init(&priv->lock);
|
||||
|
||||
adap = &priv->adap;
|
||||
adap->nr = pdev->id;
|
||||
|
@ -678,26 +624,47 @@ static int rcar_i2c_probe(struct platform_device *pdev)
|
|||
i2c_set_adapdata(adap, priv);
|
||||
strlcpy(adap->name, pdev->name, sizeof(adap->name));
|
||||
|
||||
ret = devm_request_irq(dev, irq, rcar_i2c_irq, 0,
|
||||
dev_name(dev), priv);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "cannot get irq %d\n", irq);
|
||||
return ret;
|
||||
}
|
||||
i2c_parse_fw_timings(dev, &i2c_t, false);
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_get_sync(dev);
|
||||
ret = rcar_i2c_clock_calculate(priv, &i2c_t);
|
||||
if (ret < 0)
|
||||
goto out_pm_put;
|
||||
|
||||
rcar_i2c_init(priv);
|
||||
|
||||
/* Don't suspend when multi-master to keep arbitration working */
|
||||
if (of_property_read_bool(dev->of_node, "multi-master"))
|
||||
priv->flags |= ID_P_PM_BLOCKED;
|
||||
else
|
||||
pm_runtime_put(dev);
|
||||
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
ret = devm_request_irq(dev, irq, rcar_i2c_irq, 0, dev_name(dev), priv);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "cannot get irq %d\n", irq);
|
||||
goto out_pm_disable;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
ret = i2c_add_numbered_adapter(adap);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "reg adap failed: %d\n", ret);
|
||||
pm_runtime_disable(dev);
|
||||
return ret;
|
||||
goto out_pm_disable;
|
||||
}
|
||||
|
||||
dev_info(dev, "probed\n");
|
||||
|
||||
return 0;
|
||||
|
||||
out_pm_put:
|
||||
pm_runtime_put(dev);
|
||||
out_pm_disable:
|
||||
pm_runtime_disable(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rcar_i2c_remove(struct platform_device *pdev)
|
||||
|
@ -706,6 +673,8 @@ static int rcar_i2c_remove(struct platform_device *pdev)
|
|||
struct device *dev = &pdev->dev;
|
||||
|
||||
i2c_del_adapter(&priv->adap);
|
||||
if (priv->flags & ID_P_PM_BLOCKED)
|
||||
pm_runtime_put(dev);
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -784,7 +784,6 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
|
|||
int retry;
|
||||
int ret;
|
||||
|
||||
pm_runtime_get_sync(&adap->dev);
|
||||
ret = clk_enable(i2c->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -795,7 +794,6 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
|
|||
|
||||
if (ret != -EAGAIN) {
|
||||
clk_disable(i2c->clk);
|
||||
pm_runtime_put(&adap->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -805,7 +803,6 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
|
|||
}
|
||||
|
||||
clk_disable(i2c->clk);
|
||||
pm_runtime_put(&adap->dev);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
|
@ -1256,8 +1253,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&i2c->adap.dev);
|
||||
|
||||
dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
|
||||
return 0;
|
||||
}
|
||||
|
@ -1273,7 +1268,6 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
|
|||
|
||||
clk_unprepare(i2c->clk);
|
||||
|
||||
pm_runtime_disable(&i2c->adap.dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
s3c24xx_i2c_deregister_cpufreq(i2c);
|
||||
|
|
|
@ -708,8 +708,7 @@ static int st_i2c_xfer(struct i2c_adapter *i2c_adap,
|
|||
#ifdef CONFIG_PM_SLEEP
|
||||
static int st_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev =
|
||||
container_of(dev, struct platform_device, dev);
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct st_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
|
||||
|
||||
if (i2c_dev->busy)
|
||||
|
|
|
@ -130,7 +130,13 @@ static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
|
|||
return 0;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -466,6 +466,11 @@ static int uniphier_fi2c_clk_init(struct device *dev,
|
|||
if (of_property_read_u32(np, "clock-frequency", &bus_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)
|
||||
bus_speed = UNIPHIER_FI2C_MAX_SPEED;
|
||||
|
||||
|
@ -481,6 +486,10 @@ static int uniphier_fi2c_clk_init(struct device *dev,
|
|||
return ret;
|
||||
|
||||
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);
|
||||
|
||||
|
@ -531,7 +540,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
|
|||
|
||||
ret = uniphier_fi2c_clk_init(dev, priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err;
|
||||
|
||||
ret = devm_request_irq(dev, irq, uniphier_fi2c_interrupt, 0,
|
||||
pdev->name, priv);
|
||||
|
|
|
@ -327,6 +327,11 @@ static int uniphier_i2c_clk_init(struct device *dev,
|
|||
if (of_property_read_u32(np, "clock-frequency", &bus_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)
|
||||
bus_speed = UNIPHIER_I2C_MAX_SPEED;
|
||||
|
||||
|
@ -342,6 +347,10 @@ static int uniphier_i2c_clk_init(struct device *dev,
|
|||
return ret;
|
||||
|
||||
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);
|
||||
|
||||
|
@ -388,7 +397,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
ret = uniphier_i2c_clk_init(dev, priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err;
|
||||
|
||||
ret = devm_request_irq(dev, irq, uniphier_i2c_interrupt, 0, pdev->name,
|
||||
priv);
|
||||
|
|
|
@ -70,7 +70,7 @@ struct xiic_i2c {
|
|||
wait_queue_head_t wait;
|
||||
struct i2c_adapter adap;
|
||||
struct i2c_msg *tx_msg;
|
||||
spinlock_t lock;
|
||||
struct mutex lock;
|
||||
unsigned int tx_pos;
|
||||
unsigned int nmsgs;
|
||||
enum xilinx_i2c_state state;
|
||||
|
@ -369,7 +369,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
|
|||
* To find which interrupts are pending; AND interrupts pending with
|
||||
* interrupts masked.
|
||||
*/
|
||||
spin_lock(&i2c->lock);
|
||||
mutex_lock(&i2c->lock);
|
||||
isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET);
|
||||
ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
|
||||
pend = isr & ier;
|
||||
|
@ -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);
|
||||
|
||||
xiic_setreg32(i2c, XIIC_IISR_OFFSET, clr);
|
||||
spin_unlock(&i2c->lock);
|
||||
mutex_unlock(&i2c->lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -662,10 +662,10 @@ 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_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)
|
||||
|
@ -745,7 +745,7 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
|||
i2c->adap.dev.parent = &pdev->dev;
|
||||
i2c->adap.dev.of_node = pdev->dev.of_node;
|
||||
|
||||
spin_lock_init(&i2c->lock);
|
||||
mutex_init(&i2c->lock);
|
||||
init_waitqueue_head(&i2c->wait);
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, irq, xiic_isr,
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
/* XLR I2C REGISTERS */
|
||||
#define XLR_I2C_CFG 0x00
|
||||
|
@ -30,6 +34,10 @@
|
|||
#define XLR_I2C_BYTECNT 0x08
|
||||
#define XLR_I2C_HDSTATIM 0x09
|
||||
|
||||
/* Sigma Designs additional registers */
|
||||
#define XLR_I2C_INT_EN 0x09
|
||||
#define XLR_I2C_INT_STAT 0x0a
|
||||
|
||||
/* XLR I2C REGISTERS FLAGS */
|
||||
#define XLR_I2C_BUS_BUSY 0x01
|
||||
#define XLR_I2C_SDOEMPTY 0x02
|
||||
|
@ -63,11 +71,98 @@ static inline u32 xlr_i2c_rdreg(u32 __iomem *base, unsigned int reg)
|
|||
return __raw_readl(base + reg);
|
||||
}
|
||||
|
||||
#define XLR_I2C_FLAG_IRQ 1
|
||||
|
||||
struct xlr_i2c_config {
|
||||
u32 flags; /* optional feature support */
|
||||
u32 status_busy; /* value of STATUS[0] when busy */
|
||||
u32 cfg_extra; /* extra CFG bits to set */
|
||||
};
|
||||
|
||||
struct xlr_i2c_private {
|
||||
struct i2c_adapter adap;
|
||||
u32 __iomem *iobase;
|
||||
int irq;
|
||||
int pos;
|
||||
struct i2c_msg *msg;
|
||||
const struct xlr_i2c_config *cfg;
|
||||
wait_queue_head_t wait;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static int xlr_i2c_busy(struct xlr_i2c_private *priv, u32 status)
|
||||
{
|
||||
return (status & XLR_I2C_BUS_BUSY) == priv->cfg->status_busy;
|
||||
}
|
||||
|
||||
static int xlr_i2c_idle(struct xlr_i2c_private *priv)
|
||||
{
|
||||
return !xlr_i2c_busy(priv, xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS));
|
||||
}
|
||||
|
||||
static int xlr_i2c_wait(struct xlr_i2c_private *priv, unsigned long timeout)
|
||||
{
|
||||
int status;
|
||||
int t;
|
||||
|
||||
t = wait_event_timeout(priv->wait, xlr_i2c_idle(priv),
|
||||
msecs_to_jiffies(timeout));
|
||||
if (!t)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS);
|
||||
|
||||
return status & XLR_I2C_ACK_ERR ? -EIO : 0;
|
||||
}
|
||||
|
||||
static void xlr_i2c_tx_irq(struct xlr_i2c_private *priv, u32 status)
|
||||
{
|
||||
struct i2c_msg *msg = priv->msg;
|
||||
|
||||
if (status & XLR_I2C_SDOEMPTY)
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT,
|
||||
msg->buf[priv->pos++]);
|
||||
}
|
||||
|
||||
static void xlr_i2c_rx_irq(struct xlr_i2c_private *priv, u32 status)
|
||||
{
|
||||
struct i2c_msg *msg = priv->msg;
|
||||
|
||||
if (status & XLR_I2C_RXRDY)
|
||||
msg->buf[priv->pos++] =
|
||||
xlr_i2c_rdreg(priv->iobase, XLR_I2C_DATAIN);
|
||||
}
|
||||
|
||||
static irqreturn_t xlr_i2c_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct xlr_i2c_private *priv = dev_id;
|
||||
struct i2c_msg *msg = priv->msg;
|
||||
u32 int_stat, status;
|
||||
|
||||
int_stat = xlr_i2c_rdreg(priv->iobase, XLR_I2C_INT_STAT);
|
||||
if (!int_stat)
|
||||
return IRQ_NONE;
|
||||
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_STAT, int_stat);
|
||||
|
||||
if (!msg)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS);
|
||||
|
||||
if (priv->pos < msg->len) {
|
||||
if (msg->flags & I2C_M_RD)
|
||||
xlr_i2c_rx_irq(priv, status);
|
||||
else
|
||||
xlr_i2c_tx_irq(priv, status);
|
||||
}
|
||||
|
||||
if (!xlr_i2c_busy(priv, status))
|
||||
wake_up(&priv->wait);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int xlr_i2c_tx(struct xlr_i2c_private *priv, u16 len,
|
||||
u8 *buf, u16 addr)
|
||||
{
|
||||
|
@ -75,37 +170,48 @@ static int xlr_i2c_tx(struct xlr_i2c_private *priv, u16 len,
|
|||
unsigned long timeout, stoptime, checktime;
|
||||
u32 i2c_status;
|
||||
int pos, timedout;
|
||||
u8 offset, byte;
|
||||
u8 offset;
|
||||
u32 xfer;
|
||||
|
||||
if (!len)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
offset = buf[0];
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_ADDR, offset);
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr);
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, XLR_I2C_CFG_ADDR);
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1);
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG,
|
||||
XLR_I2C_CFG_ADDR | priv->cfg->cfg_extra);
|
||||
|
||||
timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT);
|
||||
stoptime = jiffies + timeout;
|
||||
timedout = 0;
|
||||
pos = 1;
|
||||
retry:
|
||||
|
||||
if (len == 1) {
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR,
|
||||
XLR_I2C_STARTXFR_ND);
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1);
|
||||
xfer = XLR_I2C_STARTXFR_ND;
|
||||
pos = 1;
|
||||
} else {
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, buf[pos]);
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR,
|
||||
XLR_I2C_STARTXFR_WR);
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 2);
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, buf[1]);
|
||||
xfer = XLR_I2C_STARTXFR_WR;
|
||||
pos = 2;
|
||||
}
|
||||
|
||||
priv->pos = pos;
|
||||
|
||||
retry:
|
||||
/* retry can only happen on the first byte */
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR, xfer);
|
||||
|
||||
if (priv->irq > 0)
|
||||
return xlr_i2c_wait(priv, XLR_I2C_TIMEOUT * len);
|
||||
|
||||
while (!timedout) {
|
||||
checktime = jiffies;
|
||||
i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS);
|
||||
|
||||
if (i2c_status & XLR_I2C_SDOEMPTY) {
|
||||
pos++;
|
||||
/* need to do a empty dataout after the last byte */
|
||||
byte = (pos < len) ? buf[pos] : 0;
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, byte);
|
||||
if ((i2c_status & XLR_I2C_SDOEMPTY) && pos < len) {
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, buf[pos++]);
|
||||
|
||||
/* reset timeout on successful xmit */
|
||||
stoptime = jiffies + timeout;
|
||||
|
@ -121,7 +227,7 @@ static int xlr_i2c_tx(struct xlr_i2c_private *priv, u16 len,
|
|||
if (i2c_status & XLR_I2C_ACK_ERR)
|
||||
return -EIO;
|
||||
|
||||
if ((i2c_status & XLR_I2C_BUS_BUSY) == 0 && pos >= len)
|
||||
if (!xlr_i2c_busy(priv, i2c_status) && pos >= len)
|
||||
return 0;
|
||||
}
|
||||
dev_err(&adap->dev, "I2C transmit timeout\n");
|
||||
|
@ -134,12 +240,17 @@ static int xlr_i2c_rx(struct xlr_i2c_private *priv, u16 len, u8 *buf, u16 addr)
|
|||
u32 i2c_status;
|
||||
unsigned long timeout, stoptime, checktime;
|
||||
int nbytes, timedout;
|
||||
u8 byte;
|
||||
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, XLR_I2C_CFG_NOADDR);
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len);
|
||||
if (!len)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG,
|
||||
XLR_I2C_CFG_NOADDR | priv->cfg->cfg_extra);
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1);
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr);
|
||||
|
||||
priv->pos = 0;
|
||||
|
||||
timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT);
|
||||
stoptime = jiffies + timeout;
|
||||
timedout = 0;
|
||||
|
@ -147,18 +258,18 @@ static int xlr_i2c_rx(struct xlr_i2c_private *priv, u16 len, u8 *buf, u16 addr)
|
|||
retry:
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR, XLR_I2C_STARTXFR_RD);
|
||||
|
||||
if (priv->irq > 0)
|
||||
return xlr_i2c_wait(priv, XLR_I2C_TIMEOUT * len);
|
||||
|
||||
while (!timedout) {
|
||||
checktime = jiffies;
|
||||
i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS);
|
||||
if (i2c_status & XLR_I2C_RXRDY) {
|
||||
if (nbytes > len)
|
||||
if (nbytes >= len)
|
||||
return -EIO; /* should not happen */
|
||||
|
||||
/* we need to do a dummy datain when nbytes == len */
|
||||
byte = xlr_i2c_rdreg(priv->iobase, XLR_I2C_DATAIN);
|
||||
if (nbytes < len)
|
||||
buf[nbytes] = byte;
|
||||
nbytes++;
|
||||
buf[nbytes++] =
|
||||
xlr_i2c_rdreg(priv->iobase, XLR_I2C_DATAIN);
|
||||
|
||||
/* reset timeout on successful read */
|
||||
stoptime = jiffies + timeout;
|
||||
|
@ -174,7 +285,7 @@ static int xlr_i2c_rx(struct xlr_i2c_private *priv, u16 len, u8 *buf, u16 addr)
|
|||
if (i2c_status & XLR_I2C_ACK_ERR)
|
||||
return -EIO;
|
||||
|
||||
if ((i2c_status & XLR_I2C_BUS_BUSY) == 0)
|
||||
if (!xlr_i2c_busy(priv, i2c_status))
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -190,8 +301,17 @@ static int xlr_i2c_xfer(struct i2c_adapter *adap,
|
|||
int ret = 0;
|
||||
struct xlr_i2c_private *priv = i2c_get_adapdata(adap);
|
||||
|
||||
ret = clk_enable(priv->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (priv->irq)
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_EN, 0xf);
|
||||
|
||||
|
||||
for (i = 0; ret == 0 && i < num; i++) {
|
||||
msg = &msgs[i];
|
||||
priv->msg = msg;
|
||||
if (msg->flags & I2C_M_RD)
|
||||
ret = xlr_i2c_rx(priv, msg->len, &msg->buf[0],
|
||||
msg->addr);
|
||||
|
@ -200,13 +320,19 @@ static int xlr_i2c_xfer(struct i2c_adapter *adap,
|
|||
msg->addr);
|
||||
}
|
||||
|
||||
if (priv->irq)
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_EN, 0);
|
||||
|
||||
clk_disable(priv->clk);
|
||||
priv->msg = NULL;
|
||||
|
||||
return (ret != 0) ? ret : num;
|
||||
}
|
||||
|
||||
static u32 xlr_func(struct i2c_adapter *adap)
|
||||
{
|
||||
/* Emulate SMBUS over I2C */
|
||||
return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
|
||||
return (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm xlr_i2c_algo = {
|
||||
|
@ -214,22 +340,89 @@ static struct i2c_algorithm xlr_i2c_algo = {
|
|||
.functionality = xlr_func,
|
||||
};
|
||||
|
||||
static const struct xlr_i2c_config xlr_i2c_config_default = {
|
||||
.status_busy = XLR_I2C_BUS_BUSY,
|
||||
.cfg_extra = 0,
|
||||
};
|
||||
|
||||
static const struct xlr_i2c_config xlr_i2c_config_tangox = {
|
||||
.flags = XLR_I2C_FLAG_IRQ,
|
||||
.status_busy = 0,
|
||||
.cfg_extra = 1 << 8,
|
||||
};
|
||||
|
||||
static const struct of_device_id xlr_i2c_dt_ids[] = {
|
||||
{
|
||||
.compatible = "sigma,smp8642-i2c",
|
||||
.data = &xlr_i2c_config_tangox,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static int xlr_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
struct xlr_i2c_private *priv;
|
||||
struct resource *res;
|
||||
struct clk *clk;
|
||||
unsigned long clk_rate;
|
||||
unsigned long clk_div;
|
||||
u32 busfreq;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
match = of_match_device(xlr_i2c_dt_ids, &pdev->dev);
|
||||
if (match)
|
||||
priv->cfg = match->data;
|
||||
else
|
||||
priv->cfg = &xlr_i2c_config_default;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->iobase = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(priv->iobase))
|
||||
return PTR_ERR(priv->iobase);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
|
||||
if (irq > 0 && (priv->cfg->flags & XLR_I2C_FLAG_IRQ)) {
|
||||
priv->irq = irq;
|
||||
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_EN, 0);
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_STAT, 0xf);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, priv->irq, xlr_i2c_irq,
|
||||
IRQF_SHARED, dev_name(&pdev->dev),
|
||||
priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
init_waitqueue_head(&priv->wait);
|
||||
}
|
||||
|
||||
if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
|
||||
&busfreq))
|
||||
busfreq = 100000;
|
||||
|
||||
clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (!IS_ERR(clk)) {
|
||||
ret = clk_prepare_enable(clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk_rate = clk_get_rate(clk);
|
||||
clk_div = DIV_ROUND_UP(clk_rate, 2 * busfreq);
|
||||
xlr_i2c_wreg(priv->iobase, XLR_I2C_CLKDIV, clk_div);
|
||||
|
||||
clk_disable(clk);
|
||||
priv->clk = clk;
|
||||
}
|
||||
|
||||
priv->adap.dev.parent = &pdev->dev;
|
||||
priv->adap.dev.of_node = pdev->dev.of_node;
|
||||
priv->adap.owner = THIS_MODULE;
|
||||
priv->adap.algo_data = priv;
|
||||
priv->adap.algo = &xlr_i2c_algo;
|
||||
|
@ -255,6 +448,8 @@ static int xlr_i2c_remove(struct platform_device *pdev)
|
|||
|
||||
priv = platform_get_drvdata(pdev);
|
||||
i2c_del_adapter(&priv->adap);
|
||||
clk_unprepare(priv->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -263,6 +458,7 @@ static struct platform_driver xlr_i2c_driver = {
|
|||
.remove = xlr_i2c_remove,
|
||||
.driver = {
|
||||
.name = "xlr-i2cbus",
|
||||
.of_match_table = xlr_i2c_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include <linux/jump_label.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#include "i2c-core.h"
|
||||
|
||||
|
@ -1563,6 +1564,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
|
|||
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
|
||||
|
||||
pm_runtime_no_callbacks(&adap->dev);
|
||||
pm_runtime_enable(&adap->dev);
|
||||
|
||||
#ifdef CONFIG_I2C_COMPAT
|
||||
res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
|
||||
|
@ -1817,6 +1819,8 @@ void i2c_del_adapter(struct i2c_adapter *adap)
|
|||
/* device name is gone after device_unregister */
|
||||
dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
|
||||
|
||||
pm_runtime_disable(&adap->dev);
|
||||
|
||||
/* wait until all references to the device are gone
|
||||
*
|
||||
* FIXME: This is old code and should ideally be replaced by an
|
||||
|
@ -1839,6 +1843,58 @@ void i2c_del_adapter(struct i2c_adapter *adap)
|
|||
}
|
||||
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 *))
|
||||
|
|
|
@ -413,6 +413,22 @@ struct i2c_algorithm {
|
|||
#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
|
||||
* @recover_bus: Recover routine. Either pass driver's recover_bus() routine, or
|
||||
|
@ -493,6 +509,8 @@ struct i2c_adapter_quirks {
|
|||
/* convenience macro for typical write-then read case */
|
||||
#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)
|
||||
/* 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
|
||||
|
@ -602,6 +620,7 @@ extern void i2c_clients_command(struct i2c_adapter *adap,
|
|||
extern struct i2c_adapter *i2c_get_adapter(int nr);
|
||||
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 */
|
||||
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)
|
|||
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 */
|
||||
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
|
||||
*
|
||||
* 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)
|
|||
module_driver(__i2c_driver, i2c_add_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 */
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
|
@ -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 */
|
||||
struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node *node);
|
||||
|
||||
#else
|
||||
|
||||
static inline struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
|
||||
|
|
Loading…
Reference in New Issue