Merge branch 'i2c/for-5.6' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: "i2c core: - huge improvements and refactorizations of the Linux I2C documentation (lots of thanks to Luca for doing it and Jean for the careful review) - subsystem wide API conversion to i2c_new_client_device() - remove obsolete parport-light driver - smaller core updates (removal of 'extern', enabling more compile testing, use more helper macros) - and quite a bunch of driver updates (new IDs, simplifications, better PM, support of atomic transfers and other improvements) i2c-mux: - The main feature is the idle-state rework of the pca954x driver from Biwen Li at24 driver: - minor maintenance: update the license tag, sort headers - move support for the write-protect pin into nvmem core - add a reference to the new wp-gpios property in nvmem to at25 bindings - add support for regulator and pm_runtime control" * 'i2c/for-5.6' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (91 commits) i2c: cros-ec-tunnel: Fix ACPI identifier i2c: cros-ec-tunnel: Fix slave device enumeration i2c: stm32f7: add PM_SLEEP suspend/resume support i2c: cadence: Fix wording in i2c-cadence driver i2c: cadence: Fix power management order of operations i2c: cadence: Fix error printing in case of defer i2c: cadence: Handle transfer_size rollover i2c: i801: Add support for Intel Comet Lake PCH-V docs: i2c: writing-clients: properly name the stop condition docs: i2c: i2c-protocol: use same wording as smbus-protocol docs: i2c: rename sections so the overall picture is clearer docs: i2c: old-module-parameters: use monospace instead of "" docs: i2c: old-module-parameters: clarify this is for obsolete kernels docs: i2c: old-module-parameters: fix internal hyperlink docs: i2c: instantiating-devices: use monospace for sysfs attributes docs: i2c: instantiating-devices: rearrange static instatiation docs: i2c: instantiating-devices: fix internal hyperlink docs: i2c: smbus-protocol: improve I2C Block transactions description docs: i2c: smbus-protocol: fix punctuation docs: i2c: smbus-protocol: fix typo ...
This commit is contained in:
@@ -367,7 +367,8 @@ comment "I2C system bus drivers (mostly embedded / system-on-chip)"
|
||||
|
||||
config I2C_ALTERA
|
||||
tristate "Altera Soft IP I2C"
|
||||
depends on (ARCH_SOCFPGA || NIOS2) && OF
|
||||
depends on ARCH_SOCFPGA || NIOS2 || COMPILE_TEST
|
||||
depends on OF
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
Altera Soft IP I2C interfaces on SoCFPGA and Nios2 architectures.
|
||||
@@ -387,7 +388,7 @@ config I2C_ASPEED
|
||||
|
||||
config I2C_AT91
|
||||
tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
|
||||
depends on ARCH_AT91
|
||||
depends on ARCH_AT91 || COMPILE_TEST
|
||||
help
|
||||
This supports the use of the I2C interface on Atmel AT91
|
||||
processors.
|
||||
@@ -440,7 +441,8 @@ config I2C_AXXIA
|
||||
|
||||
config I2C_BCM2835
|
||||
tristate "Broadcom BCM2835 I2C controller"
|
||||
depends on ARCH_BCM2835 || ARCH_BRCMSTB
|
||||
depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST
|
||||
depends on COMMON_CLK
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
BCM2835 I2C controller.
|
||||
@@ -463,8 +465,8 @@ config I2C_BCM_IPROC
|
||||
|
||||
config I2C_BCM_KONA
|
||||
tristate "BCM Kona I2C adapter"
|
||||
depends on ARCH_BCM_MOBILE
|
||||
default y
|
||||
depends on ARCH_BCM_MOBILE || COMPILE_TEST
|
||||
default y if ARCH_BCM_MOBILE
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
I2C interface on the Broadcom Kona family of processors.
|
||||
@@ -511,7 +513,7 @@ config I2C_CPM
|
||||
|
||||
config I2C_DAVINCI
|
||||
tristate "DaVinci I2C driver"
|
||||
depends on ARCH_DAVINCI || ARCH_KEYSTONE
|
||||
depends on ARCH_DAVINCI || ARCH_KEYSTONE || COMPILE_TEST
|
||||
help
|
||||
Support for TI DaVinci I2C controller driver.
|
||||
|
||||
@@ -572,7 +574,7 @@ config I2C_DESIGNWARE_BAYTRAIL
|
||||
|
||||
config I2C_DIGICOLOR
|
||||
tristate "Conexant Digicolor I2C driver"
|
||||
depends on ARCH_DIGICOLOR
|
||||
depends on ARCH_DIGICOLOR || COMPILE_TEST
|
||||
help
|
||||
Support for Conexant Digicolor SoCs (CX92755) I2C controller driver.
|
||||
|
||||
@@ -610,11 +612,12 @@ config I2C_EMEV2
|
||||
I2C interface on the Renesas Electronics EM/EV family of processors.
|
||||
|
||||
config I2C_EXYNOS5
|
||||
tristate "Exynos5 high-speed I2C driver"
|
||||
depends on ARCH_EXYNOS && OF
|
||||
default y
|
||||
tristate "Exynos high-speed I2C driver"
|
||||
depends on OF
|
||||
depends on ARCH_EXYNOS || COMPILE_TEST
|
||||
default y if ARCH_EXYNOS
|
||||
help
|
||||
High-speed I2C controller on Exynos5 based Samsung SoCs.
|
||||
High-speed I2C controller on Exynos5 and newer Samsung SoCs.
|
||||
|
||||
config I2C_GPIO
|
||||
tristate "GPIO-based bitbanging I2C"
|
||||
@@ -634,7 +637,7 @@ config I2C_GPIO_FAULT_INJECTOR
|
||||
|
||||
config I2C_HIGHLANDER
|
||||
tristate "Highlander FPGA SMBus interface"
|
||||
depends on SH_HIGHLANDER
|
||||
depends on SH_HIGHLANDER || COMPILE_TEST
|
||||
help
|
||||
If you say yes to this option, support will be included for
|
||||
the SMBus interface located in the FPGA on various Highlander
|
||||
@@ -686,7 +689,7 @@ config I2C_IMX_LPI2C
|
||||
|
||||
config I2C_IOP3XX
|
||||
tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
|
||||
depends on ARCH_IOP32X || ARCH_IXP4XX
|
||||
depends on ARCH_IOP32X || ARCH_IXP4XX || COMPILE_TEST
|
||||
help
|
||||
Say Y here if you want to use the IIC bus controller on
|
||||
the Intel IOPx3xx I/O Processors or IXP4xx Network Processors.
|
||||
@@ -726,6 +729,7 @@ config I2C_LPC2K
|
||||
config I2C_MESON
|
||||
tristate "Amlogic Meson I2C controller"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
depends on COMMON_CLK
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
I2C interface on the Amlogic Meson family of SoCs.
|
||||
@@ -759,7 +763,7 @@ config I2C_MT7621
|
||||
|
||||
config I2C_MV64XXX
|
||||
tristate "Marvell mv64xxx I2C Controller"
|
||||
depends on MV64X60 || PLAT_ORION || ARCH_SUNXI || ARCH_MVEBU
|
||||
depends on MV64X60 || PLAT_ORION || ARCH_SUNXI || ARCH_MVEBU || COMPILE_TEST
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
built-in I2C interface on the Marvell 64xxx line of host bridges.
|
||||
@@ -770,7 +774,7 @@ config I2C_MV64XXX
|
||||
|
||||
config I2C_MXS
|
||||
tristate "Freescale i.MX28 I2C interface"
|
||||
depends on SOC_IMX28
|
||||
depends on SOC_IMX28 || COMPILE_TEST
|
||||
select STMP_DEVICE
|
||||
help
|
||||
Say Y here if you want to use the I2C bus controller on
|
||||
@@ -799,7 +803,7 @@ config I2C_OCORES
|
||||
|
||||
config I2C_OMAP
|
||||
tristate "OMAP I2C adapter"
|
||||
depends on ARCH_OMAP || ARCH_K3
|
||||
depends on ARCH_OMAP || ARCH_K3 || COMPILE_TEST
|
||||
default y if MACH_OMAP_H3 || MACH_OMAP_OSK
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
@@ -833,7 +837,7 @@ config I2C_PCA_PLATFORM
|
||||
|
||||
config I2C_PMCMSP
|
||||
tristate "PMC MSP I2C TWI Controller"
|
||||
depends on PMC_MSP
|
||||
depends on PMC_MSP || COMPILE_TEST
|
||||
help
|
||||
This driver supports the PMC TWI controller on MSP devices.
|
||||
|
||||
@@ -842,7 +846,7 @@ config I2C_PMCMSP
|
||||
|
||||
config I2C_PNX
|
||||
tristate "I2C bus support for Philips PNX and NXP LPC targets"
|
||||
depends on ARCH_LPC32XX
|
||||
depends on ARCH_LPC32XX || COMPILE_TEST
|
||||
help
|
||||
This driver supports the Philips IP3204 I2C IP block master and/or
|
||||
slave controller
|
||||
@@ -863,7 +867,7 @@ config I2C_PUV3
|
||||
|
||||
config I2C_PXA
|
||||
tristate "Intel PXA2XX I2C adapter"
|
||||
depends on ARCH_PXA || ARCH_MMP || ARCH_MVEBU || (X86_32 && PCI && OF)
|
||||
depends on ARCH_PXA || ARCH_MMP || ARCH_MVEBU || (X86_32 && PCI && OF) || COMPILE_TEST
|
||||
help
|
||||
If you have devices in the PXA I2C bus, say yes to this option.
|
||||
This driver can also be built as a module. If so, the module
|
||||
@@ -932,11 +936,11 @@ config HAVE_S3C2410_I2C
|
||||
respective Kconfig file.
|
||||
|
||||
config I2C_S3C2410
|
||||
tristate "S3C2410 I2C Driver"
|
||||
depends on HAVE_S3C2410_I2C
|
||||
tristate "S3C/Exynos I2C Driver"
|
||||
depends on HAVE_S3C2410_I2C || COMPILE_TEST
|
||||
help
|
||||
Say Y here to include support for I2C controller in the
|
||||
Samsung SoCs.
|
||||
Samsung SoCs (S3C, S5Pv210, Exynos).
|
||||
|
||||
config I2C_SH7760
|
||||
tristate "Renesas SH7760 I2C Controller"
|
||||
@@ -971,7 +975,7 @@ config I2C_SIMTEC
|
||||
|
||||
config I2C_SIRF
|
||||
tristate "CSR SiRFprimaII I2C interface"
|
||||
depends on ARCH_SIRF
|
||||
depends on ARCH_SIRF || COMPILE_TEST
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
CSR SiRFprimaII I2C interface.
|
||||
@@ -981,14 +985,14 @@ config I2C_SIRF
|
||||
|
||||
config I2C_SPRD
|
||||
tristate "Spreadtrum I2C interface"
|
||||
depends on I2C=y && ARCH_SPRD
|
||||
depends on I2C=y && (ARCH_SPRD || COMPILE_TEST)
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
Spreadtrum I2C interface.
|
||||
|
||||
config I2C_ST
|
||||
tristate "STMicroelectronics SSC I2C support"
|
||||
depends on ARCH_STI
|
||||
depends on ARCH_STI || COMPILE_TEST
|
||||
help
|
||||
Enable this option to add support for STMicroelectronics SoCs
|
||||
hardware SSC (Synchronous Serial Controller) as an I2C controller.
|
||||
@@ -1019,7 +1023,7 @@ config I2C_STM32F7
|
||||
|
||||
config I2C_STU300
|
||||
tristate "ST Microelectronics DDC I2C interface"
|
||||
depends on MACH_U300
|
||||
depends on MACH_U300 || COMPILE_TEST
|
||||
default y if MACH_U300
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
@@ -1055,15 +1059,16 @@ config I2C_SYNQUACER
|
||||
|
||||
config I2C_TEGRA
|
||||
tristate "NVIDIA Tegra internal I2C controller"
|
||||
depends on ARCH_TEGRA
|
||||
depends on ARCH_TEGRA || (COMPILE_TEST && (ARC || ARM || ARM64 || M68K || RISCV || SUPERH || SPARC))
|
||||
# COMPILE_TEST needs architectures with readsX()/writesX() primitives
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
I2C controller embedded in NVIDIA Tegra SOCs
|
||||
|
||||
config I2C_TEGRA_BPMP
|
||||
tristate "NVIDIA Tegra BPMP I2C controller"
|
||||
depends on TEGRA_BPMP
|
||||
default y
|
||||
depends on TEGRA_BPMP || COMPILE_TEST
|
||||
default y if TEGRA_BPMP
|
||||
help
|
||||
If you say yes to this option, support will be included for the I2C
|
||||
controller embedded in NVIDIA Tegra SoCs accessed via the BPMP.
|
||||
@@ -1101,7 +1106,7 @@ config I2C_VERSATILE
|
||||
|
||||
config I2C_WMT
|
||||
tristate "Wondermedia WM8xxx SoC I2C bus support"
|
||||
depends on ARCH_VT8500
|
||||
depends on ARCH_VT8500 || COMPILE_TEST
|
||||
help
|
||||
Say yes if you want to support the I2C bus on Wondermedia 8xxx-series
|
||||
SoCs.
|
||||
@@ -1142,7 +1147,7 @@ config I2C_XILINX
|
||||
|
||||
config I2C_XLR
|
||||
tristate "Netlogic XLR and Sigma Designs I2C support"
|
||||
depends on CPU_XLR || ARCH_TANGO
|
||||
depends on CPU_XLR || ARCH_TANGO || COMPILE_TEST
|
||||
help
|
||||
This driver enables support for the on-chip I2C interface of
|
||||
the Netlogic XLR/XLS MIPS processors and Sigma Designs SOCs.
|
||||
@@ -1202,46 +1207,12 @@ config I2C_PARPORT
|
||||
This supports parallel port I2C adapters such as the ones made by
|
||||
Philips or Velleman, Analog Devices evaluation boards, and more.
|
||||
Basically any adapter using the parallel port as an I2C bus with
|
||||
no extra chipset is supported by this driver, or could be.
|
||||
|
||||
This driver is a replacement for (and was inspired by) an older
|
||||
driver named i2c-philips-par. The new driver supports more devices,
|
||||
and makes it easier to add support for new devices.
|
||||
|
||||
An adapter type parameter is now mandatory. Please read the file
|
||||
Documentation/i2c/busses/i2c-parport.rst for details.
|
||||
|
||||
Another driver exists, named i2c-parport-light, which doesn't depend
|
||||
on the parport driver. This is meant for embedded systems. Don't say
|
||||
Y here if you intend to say Y or M there.
|
||||
no extra chipset is supported by this driver, or could be. Please
|
||||
read the file Documentation/i2c/busses/i2c-parport.rst for details.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-parport.
|
||||
|
||||
config I2C_PARPORT_LIGHT
|
||||
tristate "Parallel port adapter (light)"
|
||||
select I2C_ALGOBIT
|
||||
select I2C_SMBUS
|
||||
help
|
||||
This supports parallel port I2C adapters such as the ones made by
|
||||
Philips or Velleman, Analog Devices evaluation boards, and more.
|
||||
Basically any adapter using the parallel port as an I2C bus with
|
||||
no extra chipset is supported by this driver, or could be.
|
||||
|
||||
This driver is a light version of i2c-parport. It doesn't depend
|
||||
on the parport driver, and uses direct I/O access instead. This
|
||||
might be preferred on embedded systems where wasting memory for
|
||||
the clean but heavy parport handling is not an option. The
|
||||
drawback is a reduced portability and the impossibility to
|
||||
daisy-chain other parallel port devices.
|
||||
|
||||
Don't say Y here if you said Y or M to i2c-parport. Saying M to
|
||||
both is possible but both modules should not be loaded at the same
|
||||
time.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-parport-light.
|
||||
|
||||
config I2C_ROBOTFUZZ_OSIF
|
||||
tristate "RobotFuzz Open Source InterFace USB adapter"
|
||||
depends on USB
|
||||
@@ -1328,7 +1299,7 @@ config I2C_ICY
|
||||
|
||||
config I2C_MLXCPLD
|
||||
tristate "Mellanox I2C driver"
|
||||
depends on X86_64
|
||||
depends on X86_64 || COMPILE_TEST
|
||||
help
|
||||
This exposes the Mellanox platform I2C busses to the linux I2C layer
|
||||
for X86 based systems.
|
||||
|
@@ -128,7 +128,6 @@ obj-$(CONFIG_I2C_ZX2967) += i2c-zx2967.o
|
||||
obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
|
||||
obj-$(CONFIG_I2C_DLN2) += i2c-dln2.o
|
||||
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
|
||||
obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
|
||||
obj-$(CONFIG_I2C_ROBOTFUZZ_OSIF) += i2c-robotfuzz-osif.o
|
||||
obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o
|
||||
obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o
|
||||
|
@@ -66,55 +66,26 @@ static struct at91_twi_pdata at91rm9200_config = {
|
||||
.clk_max_div = 5,
|
||||
.clk_offset = 3,
|
||||
.has_unre_flag = true,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
.has_dig_filtr = false,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata at91sam9261_config = {
|
||||
.clk_max_div = 5,
|
||||
.clk_offset = 4,
|
||||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
.has_dig_filtr = false,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata at91sam9260_config = {
|
||||
.clk_max_div = 7,
|
||||
.clk_offset = 4,
|
||||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
.has_dig_filtr = false,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata at91sam9g20_config = {
|
||||
.clk_max_div = 7,
|
||||
.clk_offset = 4,
|
||||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
.has_dig_filtr = false,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata at91sam9g10_config = {
|
||||
.clk_max_div = 7,
|
||||
.clk_offset = 4,
|
||||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
.has_dig_filtr = false,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static const struct platform_device_id at91_twi_devtypes[] = {
|
||||
@@ -142,23 +113,13 @@ static const struct platform_device_id at91_twi_devtypes[] = {
|
||||
static struct at91_twi_pdata at91sam9x5_config = {
|
||||
.clk_max_div = 7,
|
||||
.clk_offset = 4,
|
||||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
.has_dig_filtr = false,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = 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,
|
||||
.has_dig_filtr = true,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata sama5d2_config = {
|
||||
|
@@ -208,6 +208,7 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
|
||||
|
||||
isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
|
||||
cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
|
||||
id->err_status = 0;
|
||||
|
||||
/* Handling nack and arbitration lost interrupt */
|
||||
if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) {
|
||||
@@ -241,10 +242,17 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
|
||||
!id->bus_hold_flag)
|
||||
cdns_i2c_clear_bus_hold(id);
|
||||
|
||||
*(id->p_recv_buf)++ =
|
||||
cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
|
||||
id->recv_count--;
|
||||
id->curr_recv_count--;
|
||||
if (id->recv_count > 0) {
|
||||
*(id->p_recv_buf)++ =
|
||||
cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
|
||||
id->recv_count--;
|
||||
id->curr_recv_count--;
|
||||
} else {
|
||||
dev_err(id->adap.dev.parent,
|
||||
"xfer_size reg rollover. xfer aborted!\n");
|
||||
id->err_status |= CDNS_I2C_IXR_TO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cdns_is_holdquirk(id, hold_quirk))
|
||||
break;
|
||||
@@ -342,7 +350,7 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
|
||||
}
|
||||
|
||||
/* Update the status for errors */
|
||||
id->err_status = isr_status & CDNS_I2C_IXR_ERR_INTR_MASK;
|
||||
id->err_status |= isr_status & CDNS_I2C_IXR_ERR_INTR_MASK;
|
||||
if (id->err_status)
|
||||
status = IRQ_HANDLED;
|
||||
|
||||
@@ -500,7 +508,7 @@ static void cdns_i2c_master_reset(struct i2c_adapter *adap)
|
||||
cdns_i2c_writereg(regval, CDNS_I2C_CR_OFFSET);
|
||||
/* Update the transfercount register to zero */
|
||||
cdns_i2c_writereg(0, CDNS_I2C_XFER_SIZE_OFFSET);
|
||||
/* Clear the interupt status register */
|
||||
/* Clear the interrupt status register */
|
||||
regval = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
|
||||
cdns_i2c_writereg(regval, CDNS_I2C_ISR_OFFSET);
|
||||
/* Clear the status register */
|
||||
@@ -921,17 +929,18 @@ static int cdns_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
id->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(id->clk)) {
|
||||
dev_err(&pdev->dev, "input clock not found.\n");
|
||||
if (PTR_ERR(id->clk) != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "input clock not found.\n");
|
||||
return PTR_ERR(id->clk);
|
||||
}
|
||||
ret = clk_prepare_enable(id->clk);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "Unable to enable clock.\n");
|
||||
|
||||
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);
|
||||
pm_runtime_enable(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))
|
||||
@@ -980,8 +989,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);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -997,10 +1006,13 @@ static int cdns_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct cdns_i2c *id = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
|
||||
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;
|
||||
}
|
||||
|
@@ -388,9 +388,9 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
|
||||
*/
|
||||
if (acpi_dev_present("INT33FE", NULL, -1)) {
|
||||
board_info.irq = adap->client_irq;
|
||||
adap->client = i2c_new_device(&adap->adapter, &board_info);
|
||||
if (!adap->client) {
|
||||
ret = -ENOMEM;
|
||||
adap->client = i2c_new_client_device(&adap->adapter, &board_info);
|
||||
if (IS_ERR(adap->client)) {
|
||||
ret = PTR_ERR(adap->client);
|
||||
goto del_adapter;
|
||||
}
|
||||
}
|
||||
|
@@ -273,6 +273,7 @@ static int ec_i2c_probe(struct platform_device *pdev)
|
||||
bus->adap.dev.parent = &pdev->dev;
|
||||
bus->adap.dev.of_node = pdev->dev.of_node;
|
||||
bus->adap.retries = I2C_MAX_RETRIES;
|
||||
ACPI_COMPANION_SET(&bus->adap.dev, ACPI_COMPANION(&pdev->dev));
|
||||
|
||||
err = i2c_add_adapter(&bus->adap);
|
||||
if (err)
|
||||
@@ -298,7 +299,7 @@ static const struct of_device_id cros_ec_i2c_of_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, cros_ec_i2c_of_match);
|
||||
|
||||
static const struct acpi_device_id cros_ec_i2c_tunnel_acpi_id[] = {
|
||||
{ "GOOG001A", 0 },
|
||||
{ "GOOG0012", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, cros_ec_i2c_tunnel_acpi_id);
|
||||
|
@@ -322,7 +322,7 @@ static int highlander_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr,
|
||||
tmp |= (SMMR_MODE0 | SMMR_MODE1);
|
||||
break;
|
||||
default:
|
||||
dev_err(dev->dev, "unsupported xfer size %d\n", dev->buf_len);
|
||||
dev_err(dev->dev, "unsupported xfer size %zu\n", dev->buf_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@@ -68,6 +68,7 @@
|
||||
* Elkhart Lake (PCH) 0x4b23 32 hard yes yes yes
|
||||
* Tiger Lake-LP (PCH) 0xa0a3 32 hard yes yes yes
|
||||
* Jasper Lake (SOC) 0x4da3 32 hard yes yes yes
|
||||
* Comet Lake-V (PCH) 0xa3a3 32 hard yes yes yes
|
||||
*
|
||||
* Features supported by this driver:
|
||||
* Software PEC no
|
||||
@@ -244,6 +245,7 @@
|
||||
#define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS 0xa223
|
||||
#define PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS 0xa2a3
|
||||
#define PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS 0xa323
|
||||
#define PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS 0xa3a3
|
||||
|
||||
struct i801_mux_config {
|
||||
char *gpio_chip;
|
||||
@@ -1074,6 +1076,7 @@ static const struct pci_device_id i801_ids[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS) },
|
||||
@@ -1142,7 +1145,7 @@ static void dmi_check_onboard_device(u8 type, const char *name,
|
||||
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||
info.addr = dmi_devices[i].i2c_addr;
|
||||
strlcpy(info.type, dmi_devices[i].i2c_type, I2C_NAME_SIZE);
|
||||
i2c_new_device(adap, &info);
|
||||
i2c_new_client_device(adap, &info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1296,7 +1299,7 @@ static void register_dell_lis3lv02d_i2c_device(struct i801_priv *priv)
|
||||
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||
info.addr = dell_lis3lv02d_devices[i].i2c_addr;
|
||||
strlcpy(info.type, "lis3lv02d", I2C_NAME_SIZE);
|
||||
i2c_new_device(&priv->adapter, &info);
|
||||
i2c_new_client_device(&priv->adapter, &info);
|
||||
}
|
||||
|
||||
/* Register optional slaves */
|
||||
@@ -1312,7 +1315,7 @@ static void i801_probe_optional_slaves(struct i801_priv *priv)
|
||||
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||
info.addr = apanel_addr;
|
||||
strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
|
||||
i2c_new_device(&priv->adapter, &info);
|
||||
i2c_new_client_device(&priv->adapter, &info);
|
||||
}
|
||||
|
||||
if (dmi_name_in_vendors("FUJITSU"))
|
||||
@@ -1742,6 +1745,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
case PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_DNV_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS:
|
||||
priv->features |= FEATURE_BLOCK_PROC;
|
||||
priv->features |= FEATURE_I2C_BLOCK_READ;
|
||||
priv->features |= FEATURE_IRQ;
|
||||
|
@@ -4,6 +4,7 @@
|
||||
*
|
||||
* Copyright (C) 2006 - 2009 Ingenic Semiconductor Inc.
|
||||
* Copyright (C) 2015 Imagination Technologies
|
||||
* Copyright (C) 2019 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
@@ -17,6 +18,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -55,6 +57,7 @@
|
||||
#define JZ4780_I2C_ACKGC 0x98
|
||||
#define JZ4780_I2C_ENSTA 0x9C
|
||||
#define JZ4780_I2C_SDAHD 0xD0
|
||||
#define X1000_I2C_SDAHD 0x7C
|
||||
|
||||
#define JZ4780_I2C_CTRL_STPHLD BIT(7)
|
||||
#define JZ4780_I2C_CTRL_SLVDIS BIT(6)
|
||||
@@ -73,6 +76,8 @@
|
||||
#define JZ4780_I2C_STA_TFNF BIT(1)
|
||||
#define JZ4780_I2C_STA_ACT BIT(0)
|
||||
|
||||
#define X1000_I2C_DC_STOP BIT(9)
|
||||
|
||||
static const char * const jz4780_i2c_abrt_src[] = {
|
||||
"ABRT_7B_ADDR_NOACK",
|
||||
"ABRT_10ADDR1_NOACK",
|
||||
@@ -130,18 +135,33 @@ static const char * const jz4780_i2c_abrt_src[] = {
|
||||
#define JZ4780_I2CFLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1))
|
||||
|
||||
#define JZ4780_I2C_FIFO_LEN 16
|
||||
#define TX_LEVEL 3
|
||||
#define RX_LEVEL (JZ4780_I2C_FIFO_LEN - TX_LEVEL - 1)
|
||||
|
||||
#define X1000_I2C_FIFO_LEN 64
|
||||
|
||||
#define JZ4780_I2C_TIMEOUT 300
|
||||
|
||||
#define BUFSIZE 200
|
||||
|
||||
enum ingenic_i2c_version {
|
||||
ID_JZ4780,
|
||||
ID_X1000,
|
||||
};
|
||||
|
||||
/* ingenic_i2c_config: SoC specific config data. */
|
||||
struct ingenic_i2c_config {
|
||||
enum ingenic_i2c_version version;
|
||||
|
||||
int fifosize;
|
||||
int tx_level;
|
||||
int rx_level;
|
||||
};
|
||||
|
||||
struct jz4780_i2c {
|
||||
void __iomem *iomem;
|
||||
int irq;
|
||||
struct clk *clk;
|
||||
struct i2c_adapter adap;
|
||||
const struct ingenic_i2c_config *cdata;
|
||||
|
||||
/* lock to protect rbuf and wbuf between xfer_rd/wr and irq handler */
|
||||
spinlock_t lock;
|
||||
@@ -340,11 +360,18 @@ static int jz4780_i2c_set_speed(struct jz4780_i2c *i2c)
|
||||
|
||||
if (hold_time >= 0) {
|
||||
/*i2c hold time enable */
|
||||
hold_time |= JZ4780_I2C_SDAHD_HDENB;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, hold_time);
|
||||
if (i2c->cdata->version >= ID_X1000) {
|
||||
jz4780_i2c_writew(i2c, X1000_I2C_SDAHD, hold_time);
|
||||
} else {
|
||||
hold_time |= JZ4780_I2C_SDAHD_HDENB;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, hold_time);
|
||||
}
|
||||
} else {
|
||||
/* disable hold time */
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, 0);
|
||||
if (i2c->cdata->version >= ID_X1000)
|
||||
jz4780_i2c_writew(i2c, X1000_I2C_SDAHD, 0);
|
||||
else
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -359,9 +386,11 @@ static int jz4780_i2c_cleanup(struct jz4780_i2c *i2c)
|
||||
spin_lock_irqsave(&i2c->lock, flags);
|
||||
|
||||
/* can send stop now if need */
|
||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||
if (i2c->cdata->version < ID_X1000) {
|
||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||
}
|
||||
|
||||
/* disable all interrupts first */
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0);
|
||||
@@ -399,11 +428,19 @@ static int jz4780_i2c_prepare(struct jz4780_i2c *i2c)
|
||||
return jz4780_i2c_enable(i2c);
|
||||
}
|
||||
|
||||
static void jz4780_i2c_send_rcmd(struct jz4780_i2c *i2c, int cmd_count)
|
||||
static void jz4780_i2c_send_rcmd(struct jz4780_i2c *i2c,
|
||||
int cmd_count,
|
||||
int cmd_left)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cmd_count; i++)
|
||||
for (i = 0; i < cmd_count - 1; i++)
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_DC, JZ4780_I2C_DC_READ);
|
||||
|
||||
if ((cmd_left == 0) && (i2c->cdata->version >= ID_X1000))
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_DC,
|
||||
JZ4780_I2C_DC_READ | X1000_I2C_DC_STOP);
|
||||
else
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_DC, JZ4780_I2C_DC_READ);
|
||||
}
|
||||
|
||||
@@ -458,37 +495,44 @@ static irqreturn_t jz4780_i2c_irq(int irqno, void *dev_id)
|
||||
|
||||
rd_left = i2c->rd_total_len - i2c->rd_data_xfered;
|
||||
|
||||
if (rd_left <= JZ4780_I2C_FIFO_LEN)
|
||||
if (rd_left <= i2c->cdata->fifosize)
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, rd_left - 1);
|
||||
}
|
||||
|
||||
if (intst & JZ4780_I2C_INTST_TXEMP) {
|
||||
if (i2c->is_write == 0) {
|
||||
int cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered;
|
||||
int max_send = (JZ4780_I2C_FIFO_LEN - 1)
|
||||
int max_send = (i2c->cdata->fifosize - 1)
|
||||
- (i2c->rd_cmd_xfered
|
||||
- i2c->rd_data_xfered);
|
||||
int cmd_to_send = min(cmd_left, max_send);
|
||||
|
||||
if (i2c->rd_cmd_xfered != 0)
|
||||
cmd_to_send = min(cmd_to_send,
|
||||
JZ4780_I2C_FIFO_LEN
|
||||
- TX_LEVEL - 1);
|
||||
i2c->cdata->fifosize
|
||||
- i2c->cdata->tx_level - 1);
|
||||
|
||||
if (cmd_to_send) {
|
||||
jz4780_i2c_send_rcmd(i2c, cmd_to_send);
|
||||
i2c->rd_cmd_xfered += cmd_to_send;
|
||||
cmd_left = i2c->rd_total_len -
|
||||
i2c->rd_cmd_xfered;
|
||||
jz4780_i2c_send_rcmd(i2c,
|
||||
cmd_to_send, cmd_left);
|
||||
|
||||
}
|
||||
|
||||
cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered;
|
||||
if (cmd_left == 0) {
|
||||
intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM);
|
||||
intmsk &= ~JZ4780_I2C_INTM_MTXEMP;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, intmsk);
|
||||
|
||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||
if (i2c->cdata->version < ID_X1000) {
|
||||
tmp = jz4780_i2c_readw(i2c,
|
||||
JZ4780_I2C_CTRL);
|
||||
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c,
|
||||
JZ4780_I2C_CTRL, tmp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unsigned short data;
|
||||
@@ -497,23 +541,26 @@ static irqreturn_t jz4780_i2c_irq(int irqno, void *dev_id)
|
||||
i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
|
||||
|
||||
while ((i2c_sta & JZ4780_I2C_STA_TFNF) &&
|
||||
(i2c->wt_len > 0)) {
|
||||
(i2c->wt_len > 0)) {
|
||||
i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
|
||||
data = *i2c->wbuf;
|
||||
data &= ~JZ4780_I2C_DC_READ;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_DC,
|
||||
data);
|
||||
if ((!i2c->stop_hold) && (i2c->cdata->version >=
|
||||
ID_X1000))
|
||||
data |= X1000_I2C_DC_STOP;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_DC, data);
|
||||
i2c->wbuf++;
|
||||
i2c->wt_len--;
|
||||
}
|
||||
|
||||
if (i2c->wt_len == 0) {
|
||||
if (!i2c->stop_hold) {
|
||||
if ((!i2c->stop_hold) && (i2c->cdata->version <
|
||||
ID_X1000)) {
|
||||
tmp = jz4780_i2c_readw(i2c,
|
||||
JZ4780_I2C_CTRL);
|
||||
JZ4780_I2C_CTRL);
|
||||
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL,
|
||||
tmp);
|
||||
jz4780_i2c_writew(i2c,
|
||||
JZ4780_I2C_CTRL, tmp);
|
||||
}
|
||||
|
||||
jz4780_i2c_trans_done(i2c);
|
||||
@@ -567,20 +614,22 @@ static inline int jz4780_i2c_xfer_read(struct jz4780_i2c *i2c,
|
||||
i2c->rd_data_xfered = 0;
|
||||
i2c->rd_cmd_xfered = 0;
|
||||
|
||||
if (len <= JZ4780_I2C_FIFO_LEN)
|
||||
if (len <= i2c->cdata->fifosize)
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, len - 1);
|
||||
else
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, RX_LEVEL);
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, i2c->cdata->rx_level);
|
||||
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, TX_LEVEL);
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, i2c->cdata->tx_level);
|
||||
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM,
|
||||
JZ4780_I2C_INTM_MRXFL | JZ4780_I2C_INTM_MTXEMP
|
||||
| JZ4780_I2C_INTM_MTXABT | JZ4780_I2C_INTM_MRXOF);
|
||||
|
||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||
tmp |= JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||
if (i2c->cdata->version < ID_X1000) {
|
||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||
tmp |= JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&i2c->lock, flags);
|
||||
|
||||
@@ -626,14 +675,16 @@ static inline int jz4780_i2c_xfer_write(struct jz4780_i2c *i2c,
|
||||
i2c->wbuf = buf;
|
||||
i2c->wt_len = len;
|
||||
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, TX_LEVEL);
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, i2c->cdata->tx_level);
|
||||
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, JZ4780_I2C_INTM_MTXEMP
|
||||
| JZ4780_I2C_INTM_MTXABT);
|
||||
|
||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||
tmp |= JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||
if (i2c->cdata->version < ID_X1000) {
|
||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||
tmp |= JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&i2c->lock, flags);
|
||||
|
||||
@@ -716,8 +767,25 @@ static const struct i2c_algorithm jz4780_i2c_algorithm = {
|
||||
.functionality = jz4780_i2c_functionality,
|
||||
};
|
||||
|
||||
static const struct ingenic_i2c_config jz4780_i2c_config = {
|
||||
.version = ID_JZ4780,
|
||||
|
||||
.fifosize = JZ4780_I2C_FIFO_LEN,
|
||||
.tx_level = JZ4780_I2C_FIFO_LEN / 2,
|
||||
.rx_level = JZ4780_I2C_FIFO_LEN / 2 - 1,
|
||||
};
|
||||
|
||||
static const struct ingenic_i2c_config x1000_i2c_config = {
|
||||
.version = ID_X1000,
|
||||
|
||||
.fifosize = X1000_I2C_FIFO_LEN,
|
||||
.tx_level = X1000_I2C_FIFO_LEN / 2,
|
||||
.rx_level = X1000_I2C_FIFO_LEN / 2 - 1,
|
||||
};
|
||||
|
||||
static const struct of_device_id jz4780_i2c_of_matches[] = {
|
||||
{ .compatible = "ingenic,jz4780-i2c", },
|
||||
{ .compatible = "ingenic,jz4780-i2c", .data = &jz4780_i2c_config },
|
||||
{ .compatible = "ingenic,x1000-i2c", .data = &x1000_i2c_config },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, jz4780_i2c_of_matches);
|
||||
@@ -734,6 +802,12 @@ static int jz4780_i2c_probe(struct platform_device *pdev)
|
||||
if (!i2c)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c->cdata = device_get_match_data(&pdev->dev);
|
||||
if (!i2c->cdata) {
|
||||
dev_err(&pdev->dev, "Error: No device match found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
i2c->adap.owner = THIS_MODULE;
|
||||
i2c->adap.algo = &jz4780_i2c_algorithm;
|
||||
i2c->adap.algo_data = i2c;
|
||||
@@ -777,9 +851,11 @@ static int jz4780_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
dev_info(&pdev->dev, "Bus frequency is %d KHz\n", i2c->speed);
|
||||
|
||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||
if (i2c->cdata->version < ID_X1000) {
|
||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||
}
|
||||
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0x0);
|
||||
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
@@ -213,6 +214,30 @@ static void meson_i2c_prepare_xfer(struct meson_i2c *i2c)
|
||||
writel(i2c->tokens[1], i2c->regs + REG_TOK_LIST1);
|
||||
}
|
||||
|
||||
static void meson_i2c_transfer_complete(struct meson_i2c *i2c, u32 ctrl)
|
||||
{
|
||||
if (ctrl & REG_CTRL_ERROR) {
|
||||
/*
|
||||
* The bit is set when the IGNORE_NAK bit is cleared
|
||||
* and the device didn't respond. In this case, the
|
||||
* I2C controller automatically generates a STOP
|
||||
* condition.
|
||||
*/
|
||||
dev_dbg(i2c->dev, "error bit set\n");
|
||||
i2c->error = -ENXIO;
|
||||
i2c->state = STATE_IDLE;
|
||||
} else {
|
||||
if (i2c->state == STATE_READ && i2c->count)
|
||||
meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos,
|
||||
i2c->count);
|
||||
|
||||
i2c->pos += i2c->count;
|
||||
|
||||
if (i2c->pos >= i2c->msg->len)
|
||||
i2c->state = STATE_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t meson_i2c_irq(int irqno, void *dev_id)
|
||||
{
|
||||
struct meson_i2c *i2c = dev_id;
|
||||
@@ -232,27 +257,9 @@ static irqreturn_t meson_i2c_irq(int irqno, void *dev_id)
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (ctrl & REG_CTRL_ERROR) {
|
||||
/*
|
||||
* The bit is set when the IGNORE_NAK bit is cleared
|
||||
* and the device didn't respond. In this case, the
|
||||
* I2C controller automatically generates a STOP
|
||||
* condition.
|
||||
*/
|
||||
dev_dbg(i2c->dev, "error bit set\n");
|
||||
i2c->error = -ENXIO;
|
||||
i2c->state = STATE_IDLE;
|
||||
complete(&i2c->done);
|
||||
goto out;
|
||||
}
|
||||
meson_i2c_transfer_complete(i2c, ctrl);
|
||||
|
||||
if (i2c->state == STATE_READ && i2c->count)
|
||||
meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos, i2c->count);
|
||||
|
||||
i2c->pos += i2c->count;
|
||||
|
||||
if (i2c->pos >= i2c->msg->len) {
|
||||
i2c->state = STATE_IDLE;
|
||||
if (i2c->state == STATE_IDLE) {
|
||||
complete(&i2c->done);
|
||||
goto out;
|
||||
}
|
||||
@@ -279,10 +286,11 @@ static void meson_i2c_do_start(struct meson_i2c *i2c, struct i2c_msg *msg)
|
||||
}
|
||||
|
||||
static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg,
|
||||
int last)
|
||||
int last, bool atomic)
|
||||
{
|
||||
unsigned long time_left, flags;
|
||||
int ret = 0;
|
||||
u32 ctrl;
|
||||
|
||||
i2c->msg = msg;
|
||||
i2c->last = last;
|
||||
@@ -300,13 +308,24 @@ static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg,
|
||||
|
||||
i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
|
||||
meson_i2c_prepare_xfer(i2c);
|
||||
reinit_completion(&i2c->done);
|
||||
|
||||
if (!atomic)
|
||||
reinit_completion(&i2c->done);
|
||||
|
||||
/* Start the transfer */
|
||||
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, REG_CTRL_START);
|
||||
|
||||
time_left = msecs_to_jiffies(I2C_TIMEOUT_MS);
|
||||
time_left = wait_for_completion_timeout(&i2c->done, time_left);
|
||||
if (atomic) {
|
||||
ret = readl_poll_timeout_atomic(i2c->regs + REG_CTRL, ctrl,
|
||||
!(ctrl & REG_CTRL_STATUS),
|
||||
10, I2C_TIMEOUT_MS * 1000);
|
||||
} else {
|
||||
time_left = msecs_to_jiffies(I2C_TIMEOUT_MS);
|
||||
time_left = wait_for_completion_timeout(&i2c->done, time_left);
|
||||
|
||||
if (!time_left)
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Protect access to i2c struct and registers from interrupt
|
||||
@@ -315,13 +334,14 @@ static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg,
|
||||
*/
|
||||
spin_lock_irqsave(&i2c->lock, flags);
|
||||
|
||||
if (atomic && !ret)
|
||||
meson_i2c_transfer_complete(i2c, ctrl);
|
||||
|
||||
/* Abort any active operation */
|
||||
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0);
|
||||
|
||||
if (!time_left) {
|
||||
if (ret)
|
||||
i2c->state = STATE_IDLE;
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (i2c->error)
|
||||
ret = i2c->error;
|
||||
@@ -331,8 +351,8 @@ static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
int num)
|
||||
static int meson_i2c_xfer_messages(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msgs, int num, bool atomic)
|
||||
{
|
||||
struct meson_i2c *i2c = adap->algo_data;
|
||||
int i, ret = 0;
|
||||
@@ -340,7 +360,7 @@ static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
clk_enable(i2c->clk);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
ret = meson_i2c_xfer_msg(i2c, msgs + i, i == num - 1);
|
||||
ret = meson_i2c_xfer_msg(i2c, msgs + i, i == num - 1, atomic);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
@@ -350,14 +370,27 @@ static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
return ret ?: i;
|
||||
}
|
||||
|
||||
static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
return meson_i2c_xfer_messages(adap, msgs, num, false);
|
||||
}
|
||||
|
||||
static int meson_i2c_xfer_atomic(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
return meson_i2c_xfer_messages(adap, msgs, num, true);
|
||||
}
|
||||
|
||||
static u32 meson_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm meson_i2c_algorithm = {
|
||||
.master_xfer = meson_i2c_xfer,
|
||||
.functionality = meson_i2c_func,
|
||||
.master_xfer = meson_i2c_xfer,
|
||||
.master_xfer_atomic = meson_i2c_xfer_atomic,
|
||||
.functionality = meson_i2c_func,
|
||||
};
|
||||
|
||||
static int meson_i2c_probe(struct platform_device *pdev)
|
||||
|
@@ -280,9 +280,9 @@ static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq)
|
||||
i2cd->gpu_ccgx_ucsi->addr = 0x8;
|
||||
i2cd->gpu_ccgx_ucsi->irq = irq;
|
||||
i2cd->gpu_ccgx_ucsi->properties = ccgx_props;
|
||||
i2cd->ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
|
||||
if (!i2cd->ccgx_client)
|
||||
return -ENODEV;
|
||||
i2cd->ccgx_client = i2c_new_client_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
|
||||
if (IS_ERR(i2cd->ccgx_client))
|
||||
return PTR_ERR(i2cd->ccgx_client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -731,7 +731,7 @@ static int ocores_i2c_probe(struct platform_device *pdev)
|
||||
/* add in known devices to the bus */
|
||||
if (pdata) {
|
||||
for (i = 0; i < pdata->num_devices; i++)
|
||||
i2c_new_device(&i2c->adap, pdata->devices + i);
|
||||
i2c_new_client_device(&i2c->adap, pdata->devices + i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@@ -1,267 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* ------------------------------------------------------------------------ *
|
||||
* i2c-parport-light.c I2C bus over parallel port *
|
||||
* ------------------------------------------------------------------------ *
|
||||
Copyright (C) 2003-2010 Jean Delvare <jdelvare@suse.de>
|
||||
|
||||
Based on older i2c-velleman.c driver
|
||||
Copyright (C) 1995-2000 Simon G. Vogl
|
||||
With some changes from:
|
||||
Frodo Looijaard <frodol@dds.nl>
|
||||
Kyösti Mälkki <kmalkki@cc.hut.fi>
|
||||
|
||||
* ------------------------------------------------------------------------ */
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
#include <linux/i2c-smbus.h>
|
||||
#include <linux/io.h>
|
||||
#include "i2c-parport.h"
|
||||
|
||||
#define DEFAULT_BASE 0x378
|
||||
#define DRVNAME "i2c-parport-light"
|
||||
|
||||
static struct platform_device *pdev;
|
||||
|
||||
static u16 base;
|
||||
module_param_hw(base, ushort, ioport, 0);
|
||||
MODULE_PARM_DESC(base, "Base I/O address");
|
||||
|
||||
static int irq;
|
||||
module_param_hw(irq, int, irq, 0);
|
||||
MODULE_PARM_DESC(irq, "IRQ (optional)");
|
||||
|
||||
/* ----- Low-level parallel port access ----------------------------------- */
|
||||
|
||||
static inline void port_write(unsigned char p, unsigned char d)
|
||||
{
|
||||
outb(d, base+p);
|
||||
}
|
||||
|
||||
static inline unsigned char port_read(unsigned char p)
|
||||
{
|
||||
return inb(base+p);
|
||||
}
|
||||
|
||||
/* ----- Unified line operation functions --------------------------------- */
|
||||
|
||||
static inline void line_set(int state, const struct lineop *op)
|
||||
{
|
||||
u8 oldval = port_read(op->port);
|
||||
|
||||
/* Touch only the bit(s) needed */
|
||||
if ((op->inverted && !state) || (!op->inverted && state))
|
||||
port_write(op->port, oldval | op->val);
|
||||
else
|
||||
port_write(op->port, oldval & ~op->val);
|
||||
}
|
||||
|
||||
static inline int line_get(const struct lineop *op)
|
||||
{
|
||||
u8 oldval = port_read(op->port);
|
||||
|
||||
return ((op->inverted && (oldval & op->val) != op->val)
|
||||
|| (!op->inverted && (oldval & op->val) == op->val));
|
||||
}
|
||||
|
||||
/* ----- I2C algorithm call-back functions and structures ----------------- */
|
||||
|
||||
static void parport_setscl(void *data, int state)
|
||||
{
|
||||
line_set(state, &adapter_parm[type].setscl);
|
||||
}
|
||||
|
||||
static void parport_setsda(void *data, int state)
|
||||
{
|
||||
line_set(state, &adapter_parm[type].setsda);
|
||||
}
|
||||
|
||||
static int parport_getscl(void *data)
|
||||
{
|
||||
return line_get(&adapter_parm[type].getscl);
|
||||
}
|
||||
|
||||
static int parport_getsda(void *data)
|
||||
{
|
||||
return line_get(&adapter_parm[type].getsda);
|
||||
}
|
||||
|
||||
/* Encapsulate the functions above in the correct structure
|
||||
Note that getscl will be set to NULL by the attaching code for adapters
|
||||
that cannot read SCL back */
|
||||
static struct i2c_algo_bit_data parport_algo_data = {
|
||||
.setsda = parport_setsda,
|
||||
.setscl = parport_setscl,
|
||||
.getsda = parport_getsda,
|
||||
.getscl = parport_getscl,
|
||||
.udelay = 50,
|
||||
.timeout = HZ,
|
||||
};
|
||||
|
||||
/* ----- Driver registration ---------------------------------------------- */
|
||||
|
||||
static struct i2c_adapter parport_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.algo_data = &parport_algo_data,
|
||||
.name = "Parallel port adapter (light)",
|
||||
};
|
||||
|
||||
/* SMBus alert support */
|
||||
static struct i2c_smbus_alert_setup alert_data = {
|
||||
};
|
||||
static struct i2c_client *ara;
|
||||
static struct lineop parport_ctrl_irq = {
|
||||
.val = (1 << 4),
|
||||
.port = PORT_CTRL,
|
||||
};
|
||||
|
||||
static int i2c_parport_probe(struct platform_device *pdev)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Reset hardware to a sane state (SCL and SDA high) */
|
||||
parport_setsda(NULL, 1);
|
||||
parport_setscl(NULL, 1);
|
||||
/* Other init if needed (power on...) */
|
||||
if (adapter_parm[type].init.val) {
|
||||
line_set(1, &adapter_parm[type].init);
|
||||
/* Give powered devices some time to settle */
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
parport_adapter.dev.parent = &pdev->dev;
|
||||
err = i2c_bit_add_bus(&parport_adapter);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Unable to register with I2C\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Setup SMBus alert if supported */
|
||||
if (adapter_parm[type].smbus_alert && irq) {
|
||||
alert_data.irq = irq;
|
||||
ara = i2c_setup_smbus_alert(&parport_adapter, &alert_data);
|
||||
if (ara)
|
||||
line_set(1, &parport_ctrl_irq);
|
||||
else
|
||||
dev_warn(&pdev->dev, "Failed to register ARA client\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_parport_remove(struct platform_device *pdev)
|
||||
{
|
||||
if (ara) {
|
||||
line_set(0, &parport_ctrl_irq);
|
||||
i2c_unregister_device(ara);
|
||||
ara = NULL;
|
||||
}
|
||||
i2c_del_adapter(&parport_adapter);
|
||||
|
||||
/* Un-init if needed (power off...) */
|
||||
if (adapter_parm[type].init.val)
|
||||
line_set(0, &adapter_parm[type].init);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver i2c_parport_driver = {
|
||||
.driver = {
|
||||
.name = DRVNAME,
|
||||
},
|
||||
.probe = i2c_parport_probe,
|
||||
.remove = i2c_parport_remove,
|
||||
};
|
||||
|
||||
static int __init i2c_parport_device_add(u16 address)
|
||||
{
|
||||
int err;
|
||||
|
||||
pdev = platform_device_alloc(DRVNAME, -1);
|
||||
if (!pdev) {
|
||||
err = -ENOMEM;
|
||||
printk(KERN_ERR DRVNAME ": Device allocation failed\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = platform_device_add(pdev);
|
||||
if (err) {
|
||||
printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
|
||||
err);
|
||||
goto exit_device_put;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_device_put:
|
||||
platform_device_put(pdev);
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __init i2c_parport_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (type < 0) {
|
||||
printk(KERN_ERR DRVNAME ": adapter type unspecified\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (type >= ARRAY_SIZE(adapter_parm)) {
|
||||
printk(KERN_ERR DRVNAME ": invalid type (%d)\n", type);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (base == 0) {
|
||||
pr_info(DRVNAME ": using default base 0x%x\n", DEFAULT_BASE);
|
||||
base = DEFAULT_BASE;
|
||||
}
|
||||
|
||||
if (!request_region(base, 3, DRVNAME))
|
||||
return -EBUSY;
|
||||
|
||||
if (irq != 0)
|
||||
pr_info(DRVNAME ": using irq %d\n", irq);
|
||||
|
||||
if (!adapter_parm[type].getscl.val)
|
||||
parport_algo_data.getscl = NULL;
|
||||
|
||||
/* Sets global pdev as a side effect */
|
||||
err = i2c_parport_device_add(base);
|
||||
if (err)
|
||||
goto exit_release;
|
||||
|
||||
err = platform_driver_register(&i2c_parport_driver);
|
||||
if (err)
|
||||
goto exit_device;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_device:
|
||||
platform_device_unregister(pdev);
|
||||
exit_release:
|
||||
release_region(base, 3);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit i2c_parport_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&i2c_parport_driver);
|
||||
platform_device_unregister(pdev);
|
||||
release_region(base, 3);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
|
||||
MODULE_DESCRIPTION("I2C bus over parallel port (light)");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(i2c_parport_init);
|
||||
module_exit(i2c_parport_exit);
|
@@ -25,7 +25,90 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include "i2c-parport.h"
|
||||
|
||||
#define PORT_DATA 0
|
||||
#define PORT_STAT 1
|
||||
#define PORT_CTRL 2
|
||||
|
||||
struct lineop {
|
||||
u8 val;
|
||||
u8 port;
|
||||
u8 inverted;
|
||||
};
|
||||
|
||||
struct adapter_parm {
|
||||
struct lineop setsda;
|
||||
struct lineop setscl;
|
||||
struct lineop getsda;
|
||||
struct lineop getscl;
|
||||
struct lineop init;
|
||||
unsigned int smbus_alert:1;
|
||||
};
|
||||
|
||||
static const struct adapter_parm adapter_parm[] = {
|
||||
/* type 0: Philips adapter */
|
||||
{
|
||||
.setsda = { 0x80, PORT_DATA, 1 },
|
||||
.setscl = { 0x08, PORT_CTRL, 0 },
|
||||
.getsda = { 0x80, PORT_STAT, 0 },
|
||||
.getscl = { 0x08, PORT_STAT, 0 },
|
||||
},
|
||||
/* type 1: home brew teletext adapter */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 0 },
|
||||
.setscl = { 0x01, PORT_DATA, 0 },
|
||||
.getsda = { 0x80, PORT_STAT, 1 },
|
||||
},
|
||||
/* type 2: Velleman K8000 adapter */
|
||||
{
|
||||
.setsda = { 0x02, PORT_CTRL, 1 },
|
||||
.setscl = { 0x08, PORT_CTRL, 1 },
|
||||
.getsda = { 0x10, PORT_STAT, 0 },
|
||||
},
|
||||
/* type 3: ELV adapter */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x40, PORT_STAT, 1 },
|
||||
.getscl = { 0x08, PORT_STAT, 1 },
|
||||
},
|
||||
/* type 4: ADM1032 evaluation board */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x10, PORT_STAT, 1 },
|
||||
.init = { 0xf0, PORT_DATA, 0 },
|
||||
.smbus_alert = 1,
|
||||
},
|
||||
/* type 5: ADM1025, ADM1030 and ADM1031 evaluation boards */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x10, PORT_STAT, 1 },
|
||||
},
|
||||
/* type 6: Barco LPT->DVI (K5800236) adapter */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x20, PORT_STAT, 0 },
|
||||
.getscl = { 0x40, PORT_STAT, 0 },
|
||||
.init = { 0xfc, PORT_DATA, 0 },
|
||||
},
|
||||
/* type 7: One For All JP1 parallel port adapter */
|
||||
{
|
||||
.setsda = { 0x01, PORT_DATA, 0 },
|
||||
.setscl = { 0x02, PORT_DATA, 0 },
|
||||
.getsda = { 0x80, PORT_STAT, 1 },
|
||||
.init = { 0x04, PORT_DATA, 1 },
|
||||
},
|
||||
/* type 8: VCT-jig */
|
||||
{
|
||||
.setsda = { 0x04, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x40, PORT_STAT, 0 },
|
||||
.getscl = { 0x80, PORT_STAT, 1 },
|
||||
},
|
||||
};
|
||||
|
||||
/* ----- Device list ------------------------------------------------------ */
|
||||
|
||||
@@ -40,9 +123,30 @@ struct i2c_par {
|
||||
|
||||
static LIST_HEAD(adapter_list);
|
||||
static DEFINE_MUTEX(adapter_list_lock);
|
||||
|
||||
#define MAX_DEVICE 4
|
||||
static int parport[MAX_DEVICE] = {0, -1, -1, -1};
|
||||
module_param_array(parport, int, NULL, 0);
|
||||
MODULE_PARM_DESC(parport,
|
||||
"List of parallel ports to bind to, by index.\n"
|
||||
" At most " __stringify(MAX_DEVICE) " devices are supported.\n"
|
||||
" Default is one device connected to parport0.\n"
|
||||
);
|
||||
|
||||
static int type = -1;
|
||||
module_param(type, int, 0);
|
||||
MODULE_PARM_DESC(type,
|
||||
"Type of adapter:\n"
|
||||
" 0 = Philips adapter\n"
|
||||
" 1 = home brew teletext adapter\n"
|
||||
" 2 = Velleman K8000 adapter\n"
|
||||
" 3 = ELV adapter\n"
|
||||
" 4 = ADM1032 evaluation board\n"
|
||||
" 5 = ADM1025, ADM1030 and ADM1031 evaluation boards\n"
|
||||
" 6 = Barco LPT->DVI (K5800236) adapter\n"
|
||||
" 7 = One For All JP1 parallel port adapter\n"
|
||||
" 8 = VCT-jig\n"
|
||||
);
|
||||
|
||||
/* ----- Low-level parallel port access ----------------------------------- */
|
||||
|
||||
@@ -311,12 +415,5 @@ MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
|
||||
MODULE_DESCRIPTION("I2C bus over parallel port");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_param_array(parport, int, NULL, 0);
|
||||
MODULE_PARM_DESC(parport,
|
||||
"List of parallel ports to bind to, by index.\n"
|
||||
" Atmost " __stringify(MAX_DEVICE) " devices are supported.\n"
|
||||
" Default is one device connected to parport0.\n"
|
||||
);
|
||||
|
||||
module_init(i2c_parport_init);
|
||||
module_exit(i2c_parport_exit);
|
||||
|
@@ -1,106 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* ------------------------------------------------------------------------ *
|
||||
* i2c-parport.h I2C bus over parallel port *
|
||||
* ------------------------------------------------------------------------ *
|
||||
Copyright (C) 2003-2010 Jean Delvare <jdelvare@suse.de>
|
||||
|
||||
* ------------------------------------------------------------------------ */
|
||||
|
||||
#define PORT_DATA 0
|
||||
#define PORT_STAT 1
|
||||
#define PORT_CTRL 2
|
||||
|
||||
struct lineop {
|
||||
u8 val;
|
||||
u8 port;
|
||||
u8 inverted;
|
||||
};
|
||||
|
||||
struct adapter_parm {
|
||||
struct lineop setsda;
|
||||
struct lineop setscl;
|
||||
struct lineop getsda;
|
||||
struct lineop getscl;
|
||||
struct lineop init;
|
||||
unsigned int smbus_alert:1;
|
||||
};
|
||||
|
||||
static const struct adapter_parm adapter_parm[] = {
|
||||
/* type 0: Philips adapter */
|
||||
{
|
||||
.setsda = { 0x80, PORT_DATA, 1 },
|
||||
.setscl = { 0x08, PORT_CTRL, 0 },
|
||||
.getsda = { 0x80, PORT_STAT, 0 },
|
||||
.getscl = { 0x08, PORT_STAT, 0 },
|
||||
},
|
||||
/* type 1: home brew teletext adapter */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 0 },
|
||||
.setscl = { 0x01, PORT_DATA, 0 },
|
||||
.getsda = { 0x80, PORT_STAT, 1 },
|
||||
},
|
||||
/* type 2: Velleman K8000 adapter */
|
||||
{
|
||||
.setsda = { 0x02, PORT_CTRL, 1 },
|
||||
.setscl = { 0x08, PORT_CTRL, 1 },
|
||||
.getsda = { 0x10, PORT_STAT, 0 },
|
||||
},
|
||||
/* type 3: ELV adapter */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x40, PORT_STAT, 1 },
|
||||
.getscl = { 0x08, PORT_STAT, 1 },
|
||||
},
|
||||
/* type 4: ADM1032 evaluation board */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x10, PORT_STAT, 1 },
|
||||
.init = { 0xf0, PORT_DATA, 0 },
|
||||
.smbus_alert = 1,
|
||||
},
|
||||
/* type 5: ADM1025, ADM1030 and ADM1031 evaluation boards */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x10, PORT_STAT, 1 },
|
||||
},
|
||||
/* type 6: Barco LPT->DVI (K5800236) adapter */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x20, PORT_STAT, 0 },
|
||||
.getscl = { 0x40, PORT_STAT, 0 },
|
||||
.init = { 0xfc, PORT_DATA, 0 },
|
||||
},
|
||||
/* type 7: One For All JP1 parallel port adapter */
|
||||
{
|
||||
.setsda = { 0x01, PORT_DATA, 0 },
|
||||
.setscl = { 0x02, PORT_DATA, 0 },
|
||||
.getsda = { 0x80, PORT_STAT, 1 },
|
||||
.init = { 0x04, PORT_DATA, 1 },
|
||||
},
|
||||
/* type 8: VCT-jig */
|
||||
{
|
||||
.setsda = { 0x04, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x40, PORT_STAT, 0 },
|
||||
.getscl = { 0x80, PORT_STAT, 1 },
|
||||
},
|
||||
};
|
||||
|
||||
static int type = -1;
|
||||
module_param(type, int, 0);
|
||||
MODULE_PARM_DESC(type,
|
||||
"Type of adapter:\n"
|
||||
" 0 = Philips adapter\n"
|
||||
" 1 = home brew teletext adapter\n"
|
||||
" 2 = Velleman K8000 adapter\n"
|
||||
" 3 = ELV adapter\n"
|
||||
" 4 = ADM1032 evaluation board\n"
|
||||
" 5 = ADM1025, ADM1030 and ADM1031 evaluation boards\n"
|
||||
" 6 = Barco LPT->DVI (K5800236) adapter\n"
|
||||
" 7 = One For All JP1 parallel port adapter\n"
|
||||
" 8 = VCT-jig\n"
|
||||
);
|
@@ -274,8 +274,8 @@ static int pmcmsptwi_probe(struct platform_device *pldev)
|
||||
if (!request_mem_region(res->start, resource_size(res),
|
||||
pldev->name)) {
|
||||
dev_err(&pldev->dev,
|
||||
"Unable to get memory/io address region 0x%08x\n",
|
||||
res->start);
|
||||
"Unable to get memory/io address region %pap\n",
|
||||
&res->start);
|
||||
rc = -EBUSY;
|
||||
goto ret_err;
|
||||
}
|
||||
@@ -285,7 +285,7 @@ static int pmcmsptwi_probe(struct platform_device *pldev)
|
||||
resource_size(res));
|
||||
if (!pmcmsptwi_data.iobase) {
|
||||
dev_err(&pldev->dev,
|
||||
"Unable to ioremap address 0x%08x\n", res->start);
|
||||
"Unable to ioremap address %pap\n", &res->start);
|
||||
rc = -EIO;
|
||||
goto ret_unreserve;
|
||||
}
|
||||
|
@@ -734,8 +734,8 @@ static int i2c_pnx_probe(struct platform_device *pdev)
|
||||
if (ret < 0)
|
||||
goto out_clock;
|
||||
|
||||
dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n",
|
||||
alg_data->adapter.name, res->start, alg_data->irq);
|
||||
dev_dbg(&pdev->dev, "%s: Master at %pap, irq %d.\n",
|
||||
alg_data->adapter.name, &res->start, alg_data->irq);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@@ -240,8 +240,8 @@ static void i2c_powermac_create_one(struct i2c_adapter *adap,
|
||||
|
||||
strncpy(info.type, type, sizeof(info.type));
|
||||
info.addr = addr;
|
||||
newdev = i2c_new_device(adap, &info);
|
||||
if (!newdev)
|
||||
newdev = i2c_new_client_device(adap, &info);
|
||||
if (IS_ERR(newdev))
|
||||
dev_err(&adap->dev,
|
||||
"i2c-powermac: Failure to register missing %s\n",
|
||||
type);
|
||||
@@ -359,8 +359,8 @@ static void i2c_powermac_register_devices(struct i2c_adapter *adap,
|
||||
info.irq = irq_of_parse_and_map(node, 0);
|
||||
info.of_node = of_node_get(node);
|
||||
|
||||
newdev = i2c_new_device(adap, &info);
|
||||
if (!newdev) {
|
||||
newdev = i2c_new_client_device(adap, &info);
|
||||
if (IS_ERR(newdev)) {
|
||||
dev_err(&adap->dev, "i2c-powermac: Failure to register"
|
||||
" %pOF\n", node);
|
||||
of_node_put(node);
|
||||
|
@@ -168,6 +168,24 @@
|
||||
|
||||
#define STM32F7_AUTOSUSPEND_DELAY (HZ / 100)
|
||||
|
||||
/**
|
||||
* struct stm32f7_i2c_regs - i2c f7 registers backup
|
||||
* @cr1: Control register 1
|
||||
* @cr2: Control register 2
|
||||
* @oar1: Own address 1 register
|
||||
* @oar2: Own address 2 register
|
||||
* @pecr: PEC register
|
||||
* @tmgr: Timing register
|
||||
*/
|
||||
struct stm32f7_i2c_regs {
|
||||
u32 cr1;
|
||||
u32 cr2;
|
||||
u32 oar1;
|
||||
u32 oar2;
|
||||
u32 pecr;
|
||||
u32 tmgr;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct stm32f7_i2c_spec - private i2c specification timing
|
||||
* @rate: I2C bus speed (Hz)
|
||||
@@ -276,6 +294,7 @@ struct stm32f7_i2c_msg {
|
||||
* @timing: I2C computed timings
|
||||
* @slave: list of slave devices registered on the I2C bus
|
||||
* @slave_running: slave device currently used
|
||||
* @backup_regs: backup of i2c controller registers (for suspend/resume)
|
||||
* @slave_dir: transfer direction for the current slave device
|
||||
* @master_mode: boolean to know in which mode the I2C is running (master or
|
||||
* slave)
|
||||
@@ -298,6 +317,7 @@ struct stm32f7_i2c_dev {
|
||||
struct stm32f7_i2c_timings timing;
|
||||
struct i2c_client *slave[STM32F7_I2C_MAX_SLAVE];
|
||||
struct i2c_client *slave_running;
|
||||
struct stm32f7_i2c_regs backup_regs;
|
||||
u32 slave_dir;
|
||||
bool master_mode;
|
||||
struct stm32_i2c_dma *dma;
|
||||
@@ -2027,8 +2047,7 @@ static int stm32f7_i2c_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int stm32f7_i2c_runtime_suspend(struct device *dev)
|
||||
static int __maybe_unused stm32f7_i2c_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
|
||||
@@ -2038,7 +2057,7 @@ static int stm32f7_i2c_runtime_suspend(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32f7_i2c_runtime_resume(struct device *dev)
|
||||
static int __maybe_unused stm32f7_i2c_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
@@ -2053,11 +2072,101 @@ static int stm32f7_i2c_runtime_resume(struct device *dev)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __maybe_unused
|
||||
stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev)
|
||||
{
|
||||
int ret;
|
||||
struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs;
|
||||
|
||||
ret = pm_runtime_get_sync(i2c_dev->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
backup_regs->cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1);
|
||||
backup_regs->cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2);
|
||||
backup_regs->oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1);
|
||||
backup_regs->oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2);
|
||||
backup_regs->pecr = readl_relaxed(i2c_dev->base + STM32F7_I2C_PECR);
|
||||
backup_regs->tmgr = readl_relaxed(i2c_dev->base + STM32F7_I2C_TIMINGR);
|
||||
|
||||
pm_runtime_put_sync(i2c_dev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused
|
||||
stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev)
|
||||
{
|
||||
u32 cr1;
|
||||
int ret;
|
||||
struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs;
|
||||
|
||||
ret = pm_runtime_get_sync(i2c_dev->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1);
|
||||
if (cr1 & STM32F7_I2C_CR1_PE)
|
||||
stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
|
||||
STM32F7_I2C_CR1_PE);
|
||||
|
||||
writel_relaxed(backup_regs->tmgr, i2c_dev->base + STM32F7_I2C_TIMINGR);
|
||||
writel_relaxed(backup_regs->cr1 & ~STM32F7_I2C_CR1_PE,
|
||||
i2c_dev->base + STM32F7_I2C_CR1);
|
||||
if (backup_regs->cr1 & STM32F7_I2C_CR1_PE)
|
||||
stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
|
||||
STM32F7_I2C_CR1_PE);
|
||||
writel_relaxed(backup_regs->cr2, i2c_dev->base + STM32F7_I2C_CR2);
|
||||
writel_relaxed(backup_regs->oar1, i2c_dev->base + STM32F7_I2C_OAR1);
|
||||
writel_relaxed(backup_regs->oar2, i2c_dev->base + STM32F7_I2C_OAR2);
|
||||
writel_relaxed(backup_regs->pecr, i2c_dev->base + STM32F7_I2C_PECR);
|
||||
|
||||
pm_runtime_put_sync(i2c_dev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused stm32f7_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
i2c_mark_adapter_suspended(&i2c_dev->adap);
|
||||
ret = stm32f7_i2c_regs_backup(i2c_dev);
|
||||
if (ret < 0) {
|
||||
i2c_mark_adapter_resumed(&i2c_dev->adap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pinctrl_pm_select_sleep_state(dev);
|
||||
pm_runtime_force_suspend(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused stm32f7_i2c_resume(struct device *dev)
|
||||
{
|
||||
struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_force_resume(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
pinctrl_pm_select_default_state(dev);
|
||||
|
||||
ret = stm32f7_i2c_regs_restore(i2c_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
i2c_mark_adapter_resumed(&i2c_dev->adap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops stm32f7_i2c_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(stm32f7_i2c_runtime_suspend,
|
||||
stm32f7_i2c_runtime_resume, NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(stm32f7_i2c_suspend, stm32f7_i2c_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id stm32f7_i2c_match[] = {
|
||||
|
@@ -444,7 +444,7 @@ static int stu300_wait_while_busy(struct stu300_dev *dev)
|
||||
"Attempt: %d\n", i+1);
|
||||
|
||||
dev_err(&dev->pdev->dev, "base address = "
|
||||
"0x%08x, reinit hardware\n", (u32) dev->virtbase);
|
||||
"0x%p, reinit hardware\n", dev->virtbase);
|
||||
|
||||
(void) stu300_init_hw(dev);
|
||||
}
|
||||
|
@@ -49,10 +49,10 @@ static struct i2c_client *taos_instantiate_device(struct i2c_adapter *adapter)
|
||||
if (!strncmp(adapter->name, "TAOS TSL2550 EVM", 16)) {
|
||||
dev_info(&adapter->dev, "Instantiating device %s at 0x%02x\n",
|
||||
tsl2550_info.type, tsl2550_info.addr);
|
||||
return i2c_new_device(adapter, &tsl2550_info);
|
||||
return i2c_new_client_device(adapter, &tsl2550_info);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
|
||||
|
@@ -16,7 +16,9 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
@@ -129,11 +131,12 @@
|
||||
#define I2C_PACKET_HEADER_SIZE 12
|
||||
|
||||
/*
|
||||
* Upto I2C_PIO_MODE_MAX_LEN bytes, controller will use PIO mode,
|
||||
* above this, controller will use DMA to fill FIFO.
|
||||
* MAX PIO len is 20 bytes excluding packet header.
|
||||
* I2C Controller will use PIO mode for transfers up to 32 bytes in order to
|
||||
* avoid DMA overhead, otherwise external APB DMA controller will be used.
|
||||
* Note that the actual MAX PIO length is 20 bytes because 32 bytes include
|
||||
* I2C_PACKET_HEADER_SIZE.
|
||||
*/
|
||||
#define I2C_PIO_MODE_MAX_LEN 32
|
||||
#define I2C_PIO_MODE_PREFERRED_LEN 32
|
||||
|
||||
/*
|
||||
* msg_end_type: The bus control which need to be send at end of transfer.
|
||||
@@ -230,7 +233,6 @@ struct tegra_i2c_hw_feature {
|
||||
* @base_phys: physical base address of the I2C controller
|
||||
* @cont_id: I2C controller ID, used for packet header
|
||||
* @irq: IRQ number of transfer complete interrupt
|
||||
* @irq_disabled: used to track whether or not the interrupt is enabled
|
||||
* @is_dvc: identifies the DVC I2C controller, has a different register layout
|
||||
* @msg_complete: transfer completion notifier
|
||||
* @msg_err: error code for completed message
|
||||
@@ -240,7 +242,6 @@ struct tegra_i2c_hw_feature {
|
||||
* @bus_clk_rate: current I2C bus clock rate
|
||||
* @clk_divisor_non_hs_mode: clock divider for non-high-speed modes
|
||||
* @is_multimaster_mode: track if I2C controller is in multi-master mode
|
||||
* @xfer_lock: lock to serialize transfer submission and processing
|
||||
* @tx_dma_chan: DMA transmit channel
|
||||
* @rx_dma_chan: DMA receive channel
|
||||
* @dma_phys: handle to DMA resources
|
||||
@@ -248,6 +249,7 @@ struct tegra_i2c_hw_feature {
|
||||
* @dma_buf_size: DMA buffer size
|
||||
* @is_curr_dma_xfer: indicates active DMA transfer
|
||||
* @dma_complete: DMA completion notifier
|
||||
* @is_curr_atomic_xfer: indicates active atomic transfer
|
||||
*/
|
||||
struct tegra_i2c_dev {
|
||||
struct device *dev;
|
||||
@@ -260,7 +262,6 @@ struct tegra_i2c_dev {
|
||||
phys_addr_t base_phys;
|
||||
int cont_id;
|
||||
int irq;
|
||||
bool irq_disabled;
|
||||
int is_dvc;
|
||||
struct completion msg_complete;
|
||||
int msg_err;
|
||||
@@ -270,8 +271,6 @@ struct tegra_i2c_dev {
|
||||
u32 bus_clk_rate;
|
||||
u16 clk_divisor_non_hs_mode;
|
||||
bool is_multimaster_mode;
|
||||
/* xfer_lock: lock to serialize transfer submission and processing */
|
||||
spinlock_t xfer_lock;
|
||||
struct dma_chan *tx_dma_chan;
|
||||
struct dma_chan *rx_dma_chan;
|
||||
dma_addr_t dma_phys;
|
||||
@@ -279,17 +278,18 @@ struct tegra_i2c_dev {
|
||||
unsigned int dma_buf_size;
|
||||
bool is_curr_dma_xfer;
|
||||
struct completion dma_complete;
|
||||
bool is_curr_atomic_xfer;
|
||||
};
|
||||
|
||||
static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
|
||||
unsigned long reg)
|
||||
{
|
||||
writel(val, i2c_dev->base + reg);
|
||||
writel_relaxed(val, i2c_dev->base + reg);
|
||||
}
|
||||
|
||||
static u32 dvc_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
|
||||
{
|
||||
return readl(i2c_dev->base + reg);
|
||||
return readl_relaxed(i2c_dev->base + reg);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -307,16 +307,16 @@ static unsigned long tegra_i2c_reg_addr(struct tegra_i2c_dev *i2c_dev,
|
||||
static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
|
||||
unsigned long reg)
|
||||
{
|
||||
writel(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
|
||||
writel_relaxed(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
|
||||
|
||||
/* Read back register to make sure that register writes completed */
|
||||
if (reg != I2C_TX_FIFO)
|
||||
readl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
|
||||
readl_relaxed(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
|
||||
}
|
||||
|
||||
static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
|
||||
{
|
||||
return readl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
|
||||
return readl_relaxed(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
|
||||
}
|
||||
|
||||
static void i2c_writesl(struct tegra_i2c_dev *i2c_dev, void *data,
|
||||
@@ -687,13 +687,15 @@ static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev)
|
||||
reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_CONFIG_LOAD);
|
||||
addr = i2c_dev->base + reg_offset;
|
||||
i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD);
|
||||
if (in_interrupt())
|
||||
err = readl_poll_timeout_atomic(addr, val, val == 0,
|
||||
1000,
|
||||
I2C_CONFIG_LOAD_TIMEOUT);
|
||||
|
||||
if (i2c_dev->is_curr_atomic_xfer)
|
||||
err = readl_relaxed_poll_timeout_atomic(
|
||||
addr, val, val == 0, 1000,
|
||||
I2C_CONFIG_LOAD_TIMEOUT);
|
||||
else
|
||||
err = readl_poll_timeout(addr, val, val == 0, 1000,
|
||||
I2C_CONFIG_LOAD_TIMEOUT);
|
||||
err = readl_relaxed_poll_timeout(
|
||||
addr, val, val == 0, 1000,
|
||||
I2C_CONFIG_LOAD_TIMEOUT);
|
||||
|
||||
if (err) {
|
||||
dev_warn(i2c_dev->dev,
|
||||
@@ -790,11 +792,6 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (i2c_dev->irq_disabled) {
|
||||
i2c_dev->irq_disabled = false;
|
||||
enable_irq(i2c_dev->irq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -825,18 +822,12 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
|
||||
|
||||
status = i2c_readl(i2c_dev, I2C_INT_STATUS);
|
||||
|
||||
spin_lock(&i2c_dev->xfer_lock);
|
||||
if (status == 0) {
|
||||
dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
|
||||
i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
|
||||
i2c_readl(i2c_dev, I2C_STATUS),
|
||||
i2c_readl(i2c_dev, I2C_CNFG));
|
||||
i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT;
|
||||
|
||||
if (!i2c_dev->irq_disabled) {
|
||||
disable_irq_nosync(i2c_dev->irq);
|
||||
i2c_dev->irq_disabled = true;
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -925,7 +916,6 @@ err:
|
||||
|
||||
complete(&i2c_dev->msg_complete);
|
||||
done:
|
||||
spin_unlock(&i2c_dev->xfer_lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -999,6 +989,64 @@ out:
|
||||
i2c_writel(i2c_dev, val, reg);
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
tegra_i2c_poll_completion_timeout(struct tegra_i2c_dev *i2c_dev,
|
||||
struct completion *complete,
|
||||
unsigned int timeout_ms)
|
||||
{
|
||||
ktime_t ktime = ktime_get();
|
||||
ktime_t ktimeout = ktime_add_ms(ktime, timeout_ms);
|
||||
|
||||
do {
|
||||
u32 status = i2c_readl(i2c_dev, I2C_INT_STATUS);
|
||||
|
||||
if (status) {
|
||||
tegra_i2c_isr(i2c_dev->irq, i2c_dev);
|
||||
|
||||
if (completion_done(complete)) {
|
||||
s64 delta = ktime_ms_delta(ktimeout, ktime);
|
||||
|
||||
return msecs_to_jiffies(delta) ?: 1;
|
||||
}
|
||||
}
|
||||
|
||||
ktime = ktime_get();
|
||||
|
||||
} while (ktime_before(ktime, ktimeout));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
tegra_i2c_wait_completion_timeout(struct tegra_i2c_dev *i2c_dev,
|
||||
struct completion *complete,
|
||||
unsigned int timeout_ms)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
if (i2c_dev->is_curr_atomic_xfer) {
|
||||
ret = tegra_i2c_poll_completion_timeout(i2c_dev, complete,
|
||||
timeout_ms);
|
||||
} else {
|
||||
enable_irq(i2c_dev->irq);
|
||||
ret = wait_for_completion_timeout(complete,
|
||||
msecs_to_jiffies(timeout_ms));
|
||||
disable_irq(i2c_dev->irq);
|
||||
|
||||
/*
|
||||
* There is a chance that completion may happen after IRQ
|
||||
* synchronization, which is done by disable_irq().
|
||||
*/
|
||||
if (ret == 0 && completion_done(complete)) {
|
||||
dev_warn(i2c_dev->dev,
|
||||
"completion done after timeout\n");
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
|
||||
@@ -1020,8 +1068,8 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
|
||||
i2c_writel(i2c_dev, reg, I2C_BUS_CLEAR_CNFG);
|
||||
tegra_i2c_unmask_irq(i2c_dev, I2C_INT_BUS_CLR_DONE);
|
||||
|
||||
time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
|
||||
msecs_to_jiffies(50));
|
||||
time_left = tegra_i2c_wait_completion_timeout(
|
||||
i2c_dev, &i2c_dev->msg_complete, 50);
|
||||
if (time_left == 0) {
|
||||
dev_err(i2c_dev->dev, "timed out for bus clear\n");
|
||||
return -ETIMEDOUT;
|
||||
@@ -1044,7 +1092,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
||||
u32 packet_header;
|
||||
u32 int_mask;
|
||||
unsigned long time_left;
|
||||
unsigned long flags;
|
||||
size_t xfer_size;
|
||||
u32 *buffer = NULL;
|
||||
int err = 0;
|
||||
@@ -1065,8 +1112,9 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
||||
xfer_size = msg->len + I2C_PACKET_HEADER_SIZE;
|
||||
|
||||
xfer_size = ALIGN(xfer_size, BYTES_PER_FIFO_WORD);
|
||||
i2c_dev->is_curr_dma_xfer = (xfer_size > I2C_PIO_MODE_MAX_LEN) &&
|
||||
i2c_dev->dma_buf;
|
||||
i2c_dev->is_curr_dma_xfer = (xfer_size > I2C_PIO_MODE_PREFERRED_LEN) &&
|
||||
i2c_dev->dma_buf &&
|
||||
!i2c_dev->is_curr_atomic_xfer;
|
||||
tegra_i2c_config_fifo_trig(i2c_dev, xfer_size);
|
||||
dma = i2c_dev->is_curr_dma_xfer;
|
||||
/*
|
||||
@@ -1075,7 +1123,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
||||
*/
|
||||
xfer_time += DIV_ROUND_CLOSEST(((xfer_size * 9) + 2) * MSEC_PER_SEC,
|
||||
i2c_dev->bus_clk_rate);
|
||||
spin_lock_irqsave(&i2c_dev->xfer_lock, flags);
|
||||
|
||||
int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
|
||||
tegra_i2c_unmask_irq(i2c_dev, int_mask);
|
||||
@@ -1090,7 +1137,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
||||
dev_err(i2c_dev->dev,
|
||||
"starting RX DMA failed, err %d\n",
|
||||
err);
|
||||
goto unlock;
|
||||
return err;
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -1149,7 +1196,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
||||
dev_err(i2c_dev->dev,
|
||||
"starting TX DMA failed, err %d\n",
|
||||
err);
|
||||
goto unlock;
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
tegra_i2c_fill_tx_fifo(i2c_dev);
|
||||
@@ -1169,20 +1216,16 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
||||
dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n",
|
||||
i2c_readl(i2c_dev, I2C_INT_MASK));
|
||||
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags);
|
||||
|
||||
if (dma) {
|
||||
if (err)
|
||||
return err;
|
||||
time_left = tegra_i2c_wait_completion_timeout(
|
||||
i2c_dev, &i2c_dev->dma_complete, xfer_time);
|
||||
|
||||
time_left = wait_for_completion_timeout(&i2c_dev->dma_complete,
|
||||
msecs_to_jiffies(xfer_time));
|
||||
if (time_left == 0) {
|
||||
dmaengine_terminate_sync(i2c_dev->msg_read ?
|
||||
i2c_dev->rx_dma_chan :
|
||||
i2c_dev->tx_dma_chan);
|
||||
|
||||
if (!time_left && !completion_done(&i2c_dev->dma_complete)) {
|
||||
dev_err(i2c_dev->dev, "DMA transfer timeout\n");
|
||||
dmaengine_terminate_sync(i2c_dev->msg_read ?
|
||||
i2c_dev->rx_dma_chan :
|
||||
i2c_dev->tx_dma_chan);
|
||||
tegra_i2c_init(i2c_dev, true);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
@@ -1195,20 +1238,15 @@ unlock:
|
||||
memcpy(i2c_dev->msg_buf, i2c_dev->dma_buf,
|
||||
msg->len);
|
||||
}
|
||||
|
||||
if (i2c_dev->msg_err != I2C_ERR_NONE)
|
||||
dmaengine_synchronize(i2c_dev->msg_read ?
|
||||
i2c_dev->rx_dma_chan :
|
||||
i2c_dev->tx_dma_chan);
|
||||
}
|
||||
|
||||
time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
|
||||
msecs_to_jiffies(xfer_time));
|
||||
time_left = tegra_i2c_wait_completion_timeout(
|
||||
i2c_dev, &i2c_dev->msg_complete, xfer_time);
|
||||
|
||||
tegra_i2c_mask_irq(i2c_dev, int_mask);
|
||||
|
||||
if (time_left == 0) {
|
||||
dev_err(i2c_dev->dev, "i2c transfer timed out\n");
|
||||
|
||||
tegra_i2c_init(i2c_dev, true);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
@@ -1270,6 +1308,19 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
||||
return ret ?: i;
|
||||
}
|
||||
|
||||
static int tegra_i2c_xfer_atomic(struct i2c_adapter *adap,
|
||||
struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
|
||||
int ret;
|
||||
|
||||
i2c_dev->is_curr_atomic_xfer = true;
|
||||
ret = tegra_i2c_xfer(adap, msgs, num);
|
||||
i2c_dev->is_curr_atomic_xfer = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 tegra_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
|
||||
@@ -1297,8 +1348,9 @@ static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev)
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm tegra_i2c_algo = {
|
||||
.master_xfer = tegra_i2c_xfer,
|
||||
.functionality = tegra_i2c_func,
|
||||
.master_xfer = tegra_i2c_xfer,
|
||||
.master_xfer_atomic = tegra_i2c_xfer_atomic,
|
||||
.functionality = tegra_i2c_func,
|
||||
};
|
||||
|
||||
/* payload size is only 12 bit */
|
||||
@@ -1568,7 +1620,6 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
||||
I2C_PACKET_HEADER_SIZE;
|
||||
init_completion(&i2c_dev->msg_complete);
|
||||
init_completion(&i2c_dev->dma_complete);
|
||||
spin_lock_init(&i2c_dev->xfer_lock);
|
||||
|
||||
if (!i2c_dev->hw->has_single_clk_source) {
|
||||
fast_clk = devm_clk_get(&pdev->dev, "fast-clk");
|
||||
@@ -1607,6 +1658,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
||||
goto unprepare_fast_clk;
|
||||
}
|
||||
|
||||
pm_runtime_irq_safe(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
if (!pm_runtime_enabled(&pdev->dev)) {
|
||||
ret = tegra_i2c_runtime_resume(&pdev->dev);
|
||||
@@ -1644,6 +1696,8 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
||||
goto release_dma;
|
||||
}
|
||||
|
||||
irq_set_status_flags(i2c_dev->irq, IRQ_NOAUTOEN);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, i2c_dev->irq,
|
||||
tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev);
|
||||
if (ret) {
|
||||
|
@@ -84,7 +84,7 @@ static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
|
||||
pmsg->buf, pmsg->len) != pmsg->len) {
|
||||
dev_err(&adapter->dev,
|
||||
"failure reading data\n");
|
||||
ret = -EREMOTEIO;
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
@@ -94,7 +94,7 @@ static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
|
||||
pmsg->buf, pmsg->len) != pmsg->len) {
|
||||
dev_err(&adapter->dev,
|
||||
"failure writing data\n");
|
||||
ret = -EREMOTEIO;
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -102,13 +102,13 @@ static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
|
||||
/* read status */
|
||||
if (usb_read(adapter, CMD_GET_STATUS, 0, 0, pstatus, 1) != 1) {
|
||||
dev_err(&adapter->dev, "failure reading status\n");
|
||||
ret = -EREMOTEIO;
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev_dbg(&adapter->dev, " status = %d\n", *pstatus);
|
||||
if (*pstatus == STATUS_ADDRESS_NAK) {
|
||||
ret = -EREMOTEIO;
|
||||
ret = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
@@ -156,6 +156,8 @@ struct xiic_i2c {
|
||||
#define XIIC_RESET_MASK 0xAUL
|
||||
|
||||
#define XIIC_PM_TIMEOUT 1000 /* ms */
|
||||
/* timeout waiting for the controller to respond */
|
||||
#define XIIC_I2C_TIMEOUT (msecs_to_jiffies(1000))
|
||||
/*
|
||||
* The following constant is used for the device global interrupt enable
|
||||
* register, to enable all interrupts for the device, this is the only bit
|
||||
@@ -166,7 +168,7 @@ struct xiic_i2c {
|
||||
#define xiic_tx_space(i2c) ((i2c)->tx_msg->len - (i2c)->tx_pos)
|
||||
#define xiic_rx_space(i2c) ((i2c)->rx_msg->len - (i2c)->rx_pos)
|
||||
|
||||
static void xiic_start_xfer(struct xiic_i2c *i2c);
|
||||
static int xiic_start_xfer(struct xiic_i2c *i2c);
|
||||
static void __xiic_start_xfer(struct xiic_i2c *i2c);
|
||||
|
||||
/*
|
||||
@@ -247,17 +249,29 @@ static inline void xiic_irq_clr_en(struct xiic_i2c *i2c, u32 mask)
|
||||
xiic_irq_en(i2c, mask);
|
||||
}
|
||||
|
||||
static void xiic_clear_rx_fifo(struct xiic_i2c *i2c)
|
||||
static int xiic_clear_rx_fifo(struct xiic_i2c *i2c)
|
||||
{
|
||||
u8 sr;
|
||||
unsigned long timeout;
|
||||
|
||||
timeout = jiffies + XIIC_I2C_TIMEOUT;
|
||||
for (sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET);
|
||||
!(sr & XIIC_SR_RX_FIFO_EMPTY_MASK);
|
||||
sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET))
|
||||
sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET)) {
|
||||
xiic_getreg8(i2c, XIIC_DRR_REG_OFFSET);
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_err(i2c->dev, "Failed to clear rx fifo\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xiic_reinit(struct xiic_i2c *i2c)
|
||||
static int xiic_reinit(struct xiic_i2c *i2c)
|
||||
{
|
||||
int ret;
|
||||
|
||||
xiic_setreg32(i2c, XIIC_RESETR_OFFSET, XIIC_RESET_MASK);
|
||||
|
||||
/* Set receive Fifo depth to maximum (zero based). */
|
||||
@@ -270,12 +284,16 @@ static void xiic_reinit(struct xiic_i2c *i2c)
|
||||
xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, XIIC_CR_ENABLE_DEVICE_MASK);
|
||||
|
||||
/* make sure RX fifo is empty */
|
||||
xiic_clear_rx_fifo(i2c);
|
||||
ret = xiic_clear_rx_fifo(i2c);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable interrupts */
|
||||
xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
|
||||
|
||||
xiic_irq_clr_en(i2c, XIIC_INTR_ARB_LOST_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xiic_deinit(struct xiic_i2c *i2c)
|
||||
@@ -655,12 +673,18 @@ static void __xiic_start_xfer(struct xiic_i2c *i2c)
|
||||
|
||||
}
|
||||
|
||||
static void xiic_start_xfer(struct xiic_i2c *i2c)
|
||||
static int xiic_start_xfer(struct xiic_i2c *i2c)
|
||||
{
|
||||
int ret;
|
||||
mutex_lock(&i2c->lock);
|
||||
xiic_reinit(i2c);
|
||||
__xiic_start_xfer(i2c);
|
||||
|
||||
ret = xiic_reinit(i2c);
|
||||
if (!ret)
|
||||
__xiic_start_xfer(i2c);
|
||||
|
||||
mutex_unlock(&i2c->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
@@ -682,7 +706,11 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
i2c->tx_msg = msgs;
|
||||
i2c->nmsgs = num;
|
||||
|
||||
xiic_start_xfer(i2c);
|
||||
err = xiic_start_xfer(i2c);
|
||||
if (err < 0) {
|
||||
dev_err(adap->dev.parent, "Error xiic_start_xfer\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
|
||||
(i2c->state == STATE_DONE), HZ)) {
|
||||
@@ -760,7 +788,8 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
i2c->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(i2c->clk)) {
|
||||
dev_err(&pdev->dev, "input clock not found.\n");
|
||||
if (PTR_ERR(i2c->clk) != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "input clock not found.\n");
|
||||
return PTR_ERR(i2c->clk);
|
||||
}
|
||||
ret = clk_prepare_enable(i2c->clk);
|
||||
@@ -769,10 +798,10 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
i2c->dev = &pdev->dev;
|
||||
pm_runtime_enable(i2c->dev);
|
||||
pm_runtime_set_autosuspend_delay(i2c->dev, XIIC_PM_TIMEOUT);
|
||||
pm_runtime_use_autosuspend(i2c->dev);
|
||||
pm_runtime_set_active(i2c->dev);
|
||||
pm_runtime_enable(i2c->dev);
|
||||
ret = devm_request_threaded_irq(&pdev->dev, irq, xiic_isr,
|
||||
xiic_process, IRQF_ONESHOT,
|
||||
pdev->name, i2c);
|
||||
@@ -794,7 +823,11 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
||||
if (!(sr & XIIC_SR_TX_FIFO_EMPTY_MASK))
|
||||
i2c->endianness = BIG;
|
||||
|
||||
xiic_reinit(i2c);
|
||||
ret = xiic_reinit(i2c);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Cannot xiic_reinit\n");
|
||||
goto err_clk_dis;
|
||||
}
|
||||
|
||||
/* add i2c adapter to i2c tree */
|
||||
ret = i2c_add_adapter(&i2c->adap);
|
||||
@@ -806,7 +839,7 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
||||
if (pdata) {
|
||||
/* add in known devices to the bus */
|
||||
for (i = 0; i < pdata->num_devices; i++)
|
||||
i2c_new_device(&i2c->adap, pdata->devices + i);
|
||||
i2c_new_client_device(&i2c->adap, pdata->devices + i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -826,14 +859,16 @@ static int xiic_i2c_remove(struct platform_device *pdev)
|
||||
/* remove adapter & data */
|
||||
i2c_del_adapter(&i2c->adap);
|
||||
|
||||
ret = clk_prepare_enable(i2c->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Unable to enable clock.\n");
|
||||
ret = pm_runtime_get_sync(i2c->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
xiic_deinit(i2c);
|
||||
pm_runtime_put_sync(i2c->dev);
|
||||
clk_disable_unprepare(i2c->clk);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -225,7 +225,7 @@ static void i2c_acpi_register_device(struct i2c_adapter *adapter,
|
||||
adev->power.flags.ignore_parent = true;
|
||||
acpi_device_set_enumerated(adev);
|
||||
|
||||
if (!i2c_new_device(adapter, info)) {
|
||||
if (IS_ERR(i2c_new_client_device(adapter, info))) {
|
||||
adev->power.flags.ignore_parent = false;
|
||||
dev_err(&adapter->dev,
|
||||
"failed to add I2C device %s from ACPI\n",
|
||||
@@ -451,7 +451,8 @@ struct notifier_block i2c_acpi_notifier = {
|
||||
* resources, in that case this function can be used to create an i2c-client
|
||||
* for other I2cSerialBus resources in the Current Resource Settings table.
|
||||
*
|
||||
* Also see i2c_new_device, which this function calls to create the i2c-client.
|
||||
* Also see i2c_new_client_device, which this function calls to create the
|
||||
* i2c-client.
|
||||
*
|
||||
* Returns a pointer to the new i2c-client, or error pointer in case of failure.
|
||||
* Specifically, -EPROBE_DEFER is returned if the adapter is not found.
|
||||
@@ -461,7 +462,6 @@ struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
|
||||
{
|
||||
struct i2c_acpi_lookup lookup;
|
||||
struct i2c_adapter *adapter;
|
||||
struct i2c_client *client;
|
||||
struct acpi_device *adev;
|
||||
LIST_HEAD(resource_list);
|
||||
int ret;
|
||||
@@ -489,11 +489,7 @@ struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
|
||||
if (!adapter)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
client = i2c_new_device(adapter, info);
|
||||
if (!client)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
return client;
|
||||
return i2c_new_client_device(adapter, info);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_acpi_new_device);
|
||||
|
||||
|
@@ -456,15 +456,15 @@ static void i2c_client_dev_release(struct device *dev)
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
show_name(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
name_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s\n", dev->type == &i2c_client_type ?
|
||||
to_i2c_client(dev)->name : to_i2c_adapter(dev)->name);
|
||||
}
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
||||
static DEVICE_ATTR_RO(name);
|
||||
|
||||
static ssize_t
|
||||
show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int len;
|
||||
@@ -479,7 +479,7 @@ show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
|
||||
return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name);
|
||||
}
|
||||
static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static struct attribute *i2c_dev_attrs[] = {
|
||||
&dev_attr_name.attr,
|
||||
@@ -831,8 +831,8 @@ EXPORT_SYMBOL_GPL(i2c_new_device);
|
||||
|
||||
|
||||
/**
|
||||
* i2c_unregister_device - reverse effect of i2c_new_device()
|
||||
* @client: value returned from i2c_new_device()
|
||||
* i2c_unregister_device - reverse effect of i2c_new_*_device()
|
||||
* @client: value returned from i2c_new_*_device()
|
||||
* Context: can sleep
|
||||
*/
|
||||
void i2c_unregister_device(struct i2c_client *client)
|
||||
@@ -1023,8 +1023,8 @@ EXPORT_SYMBOL_GPL(i2c_adapter_depth);
|
||||
* the user to provide incorrect parameters.
|
||||
*/
|
||||
static ssize_t
|
||||
i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
new_device_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_adapter *adap = to_i2c_adapter(dev);
|
||||
struct i2c_board_info info;
|
||||
@@ -1079,7 +1079,7 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
|
||||
static DEVICE_ATTR_WO(new_device);
|
||||
|
||||
/*
|
||||
* And of course let the users delete the devices they instantiated, if
|
||||
@@ -1091,8 +1091,8 @@ static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
|
||||
* the user to delete the wrong device.
|
||||
*/
|
||||
static ssize_t
|
||||
i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
delete_device_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_adapter *adap = to_i2c_adapter(dev);
|
||||
struct i2c_client *client, *next;
|
||||
@@ -1135,7 +1135,7 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr,
|
||||
return res;
|
||||
}
|
||||
static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, S_IWUSR, NULL,
|
||||
i2c_sysfs_delete_device);
|
||||
delete_device_store);
|
||||
|
||||
static struct attribute *i2c_adapter_attrs[] = {
|
||||
&dev_attr_name.attr,
|
||||
@@ -1178,9 +1178,8 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
|
||||
|
||||
down_read(&__i2c_board_lock);
|
||||
list_for_each_entry(devinfo, &__i2c_board_list, list) {
|
||||
if (devinfo->busnum == adapter->nr
|
||||
&& !i2c_new_device(adapter,
|
||||
&devinfo->board_info))
|
||||
if (devinfo->busnum == adapter->nr &&
|
||||
IS_ERR(i2c_new_client_device(adapter, &devinfo->board_info)))
|
||||
dev_err(&adapter->dev,
|
||||
"Can't create device at 0x%02x\n",
|
||||
devinfo->board_info.addr);
|
||||
@@ -2167,8 +2166,8 @@ static int i2c_detect_address(struct i2c_client *temp_client,
|
||||
|
||||
dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n",
|
||||
info.type, info.addr);
|
||||
client = i2c_new_device(adapter, &info);
|
||||
if (client)
|
||||
client = i2c_new_client_device(adapter, &info);
|
||||
if (!IS_ERR(client))
|
||||
list_add_tail(&client->detected, &driver->clients);
|
||||
else
|
||||
dev_err(&adapter->dev, "Failed creating %s at 0x%02x\n",
|
||||
|
@@ -75,11 +75,10 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
client = i2c_new_device(adap, &info);
|
||||
if (!client) {
|
||||
client = i2c_new_client_device(adap, &info);
|
||||
if (IS_ERR(client))
|
||||
dev_err(&adap->dev, "of_i2c: Failure registering %pOF\n", node);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
|
@@ -16,6 +16,7 @@
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
@@ -42,20 +43,20 @@
|
||||
#define PCA9541_CONTROL 0x01
|
||||
#define PCA9541_ISTAT 0x02
|
||||
|
||||
#define PCA9541_CTL_MYBUS (1 << 0)
|
||||
#define PCA9541_CTL_NMYBUS (1 << 1)
|
||||
#define PCA9541_CTL_BUSON (1 << 2)
|
||||
#define PCA9541_CTL_NBUSON (1 << 3)
|
||||
#define PCA9541_CTL_BUSINIT (1 << 4)
|
||||
#define PCA9541_CTL_TESTON (1 << 6)
|
||||
#define PCA9541_CTL_NTESTON (1 << 7)
|
||||
#define PCA9541_CTL_MYBUS BIT(0)
|
||||
#define PCA9541_CTL_NMYBUS BIT(1)
|
||||
#define PCA9541_CTL_BUSON BIT(2)
|
||||
#define PCA9541_CTL_NBUSON BIT(3)
|
||||
#define PCA9541_CTL_BUSINIT BIT(4)
|
||||
#define PCA9541_CTL_TESTON BIT(6)
|
||||
#define PCA9541_CTL_NTESTON BIT(7)
|
||||
|
||||
#define PCA9541_ISTAT_INTIN (1 << 0)
|
||||
#define PCA9541_ISTAT_BUSINIT (1 << 1)
|
||||
#define PCA9541_ISTAT_BUSOK (1 << 2)
|
||||
#define PCA9541_ISTAT_BUSLOST (1 << 3)
|
||||
#define PCA9541_ISTAT_MYTEST (1 << 6)
|
||||
#define PCA9541_ISTAT_NMYTEST (1 << 7)
|
||||
#define PCA9541_ISTAT_INTIN BIT(0)
|
||||
#define PCA9541_ISTAT_BUSINIT BIT(1)
|
||||
#define PCA9541_ISTAT_BUSOK BIT(2)
|
||||
#define PCA9541_ISTAT_BUSLOST BIT(3)
|
||||
#define PCA9541_ISTAT_MYTEST BIT(6)
|
||||
#define PCA9541_ISTAT_NMYTEST BIT(7)
|
||||
|
||||
#define BUSON (PCA9541_CTL_BUSON | PCA9541_CTL_NBUSON)
|
||||
#define MYBUS (PCA9541_CTL_MYBUS | PCA9541_CTL_NMYBUS)
|
||||
|
@@ -86,7 +86,7 @@ struct pca954x {
|
||||
|
||||
u8 last_chan; /* last register value */
|
||||
/* MUX_IDLE_AS_IS, MUX_IDLE_DISCONNECT or >= 0 for channel */
|
||||
s8 idle_state;
|
||||
s32 idle_state;
|
||||
|
||||
struct i2c_client *client;
|
||||
|
||||
@@ -229,20 +229,23 @@ static int pca954x_reg_write(struct i2c_adapter *adap,
|
||||
I2C_SMBUS_BYTE, &dummy);
|
||||
}
|
||||
|
||||
static u8 pca954x_regval(struct pca954x *data, u8 chan)
|
||||
{
|
||||
/* We make switches look like muxes, not sure how to be smarter. */
|
||||
if (data->chip->muxtype == pca954x_ismux)
|
||||
return chan | data->chip->enable;
|
||||
else
|
||||
return 1 << chan;
|
||||
}
|
||||
|
||||
static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
struct pca954x *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = data->client;
|
||||
const struct chip_desc *chip = data->chip;
|
||||
u8 regval;
|
||||
int ret = 0;
|
||||
|
||||
/* we make switches look like muxes, not sure how to be smarter */
|
||||
if (chip->muxtype == pca954x_ismux)
|
||||
regval = chan | chip->enable;
|
||||
else
|
||||
regval = 1 << chan;
|
||||
|
||||
regval = pca954x_regval(data, chan);
|
||||
/* Only select the channel if its different from the last channel */
|
||||
if (data->last_chan != regval) {
|
||||
ret = pca954x_reg_write(muxc->parent, client, regval);
|
||||
@@ -256,7 +259,7 @@ static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
struct pca954x *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = data->client;
|
||||
s8 idle_state;
|
||||
s32 idle_state;
|
||||
|
||||
idle_state = READ_ONCE(data->idle_state);
|
||||
if (idle_state >= 0)
|
||||
@@ -402,6 +405,22 @@ static void pca954x_cleanup(struct i2c_mux_core *muxc)
|
||||
i2c_mux_del_adapters(muxc);
|
||||
}
|
||||
|
||||
static int pca954x_init(struct i2c_client *client, struct pca954x *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (data->idle_state >= 0)
|
||||
data->last_chan = pca954x_regval(data, data->idle_state);
|
||||
else
|
||||
data->last_chan = 0; /* Disconnect multiplexer */
|
||||
|
||||
ret = i2c_smbus_write_byte(client, data->last_chan);
|
||||
if (ret < 0)
|
||||
data->last_chan = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* I2C init/probing/exit functions
|
||||
*/
|
||||
@@ -411,7 +430,6 @@ static int pca954x_probe(struct i2c_client *client,
|
||||
struct i2c_adapter *adap = client->adapter;
|
||||
struct device *dev = &client->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
bool idle_disconnect_dt;
|
||||
struct gpio_desc *gpio;
|
||||
struct i2c_mux_core *muxc;
|
||||
struct pca954x *data;
|
||||
@@ -462,23 +480,24 @@ static int pca954x_probe(struct i2c_client *client,
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the mux register at addr to verify
|
||||
data->idle_state = MUX_IDLE_AS_IS;
|
||||
if (of_property_read_u32(np, "idle-state", &data->idle_state)) {
|
||||
if (np && of_property_read_bool(np, "i2c-mux-idle-disconnect"))
|
||||
data->idle_state = MUX_IDLE_DISCONNECT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the mux register at addr to verify
|
||||
* that the mux is in fact present. This also
|
||||
* initializes the mux to disconnected state.
|
||||
* initializes the mux to a channel
|
||||
* or disconnected state.
|
||||
*/
|
||||
if (i2c_smbus_write_byte(client, 0) < 0) {
|
||||
ret = pca954x_init(client, data);
|
||||
if (ret < 0) {
|
||||
dev_warn(dev, "probe failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
data->last_chan = 0; /* force the first selection */
|
||||
data->idle_state = MUX_IDLE_AS_IS;
|
||||
|
||||
idle_disconnect_dt = np &&
|
||||
of_property_read_bool(np, "i2c-mux-idle-disconnect");
|
||||
if (idle_disconnect_dt)
|
||||
data->idle_state = MUX_IDLE_DISCONNECT;
|
||||
|
||||
ret = pca954x_irq_setup(muxc);
|
||||
if (ret)
|
||||
goto fail_cleanup;
|
||||
@@ -530,9 +549,13 @@ static int pca954x_resume(struct device *dev)
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct pca954x *data = i2c_mux_priv(muxc);
|
||||
int ret;
|
||||
|
||||
data->last_chan = 0;
|
||||
return i2c_smbus_write_byte(client, 0);
|
||||
ret = pca954x_init(client, data);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "failed to verify mux presence\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Reference in New Issue
Block a user