mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
i2c for v7.2
Two major cleanup across drivers and core code:
- use named initializers in device ID tables
- replace dev_err() with dev_err_probe()
Drivers:
- at24: use named initializers for arrays of i2c_device_data
- at91: add MCHP_LAN966X_PCI dependency
- cadence: add shutdown callback
- k1: enable by default on SpacemiT
- mxs: improve documentation
- qcom-geni: use pm_runtime_force_suspend/resume for system sleep
- tegra:
- disable fair arbitration on non-MCTP buses
- allocate DMA buffers from the correct DMA device
- designware:
- handle active target shutdown cleanly
- add shutdown callbacks for platform and PCI drivers
- adopt the new PM_RUNTIME_ACQUIRE() helpers
DT bindings:
- convert davinci bindings to DT schema
Core and muxes:
- acpi: report missing I2C resources as -ENOENT
- gpiolib: add gpiod_is_single_ended() helper for I2C GPIO users
- i2c-mux-reg: add generic firmware node support
- a set of 10 patches from Johan Hovold fixing adapter
registration races, cleanup paths and resource management
issues
New support:
- DesignWare LECA0003 (ACPI ID)
- Loongson LS2K0300 I2C controller (new driver)
- Qualcomm CCI Glymur and Shikra compatibles
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQScDfrjQa34uOld1VLaeAVmJtMtbgUCai/V1gAKCRDaeAVmJtMt
bse9AQDssuI+jeF6X/UGddy926zIie+YuVITcBzObT+3MSQSzQD9E1HZTRJeuqA/
dRS6Thf0k4VpES8ecF6NxifZJIS4VgQ=
=GUmn
-----END PGP SIGNATURE-----
Merge tag 'i2c-7.2-part1' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux
Pull i2c updates from Andi Shyti:
"This pull request is mostly made of cleanups and small infrastructure
improvements across the I2C core, drivers and bindings. It also adds
support for three drivers and a few new compatibles.
Two major cleanup across drivers and core code:
- use named initializers in device ID tables
- replace dev_err() with dev_err_probe()
Drivers:
- at24: use named initializers for arrays of i2c_device_data
- at91: add MCHP_LAN966X_PCI dependency
- cadence: add shutdown callback
- k1: enable by default on SpacemiT
- mxs: improve documentation
- qcom-geni: use pm_runtime_force_suspend/resume for system sleep
- tegra:
- disable fair arbitration on non-MCTP buses
- allocate DMA buffers from the correct DMA device
- designware:
- handle active target shutdown cleanly
- add shutdown callbacks for platform and PCI drivers
- adopt the new PM_RUNTIME_ACQUIRE() helpers
DT bindings:
- convert davinci bindings to DT schema
Core and muxes:
- acpi: report missing I2C resources as -ENOENT
- gpiolib: add gpiod_is_single_ended() helper for I2C GPIO users
- i2c-mux-reg: add generic firmware node support
- a set of 10 patches from Johan Hovold fixing adapter registration
races, cleanup paths and resource management issues
New support:
- DesignWare LECA0003 (ACPI ID)
- Loongson LS2K0300 I2C controller (new driver)
- Qualcomm CCI Glymur and Shikra compatibles"
* tag 'i2c-7.2-part1' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux: (46 commits)
i2c: mxs: add missing kernel-doc for struct mxs_i2c_dev members
i2c: qcom-geni: Use pm_runtime_force_{suspend,resume} helpers
dt-bindings: i2c: qcom-cci: Document Glymur compatible
dt-bindings: i2c: qcom-cci: Document Shikra compatible
i2c: mux: reg: use device property accessors
i2c: acpi: Return -ENOENT when no resources found in i2c_acpi_client_count()
i2c: at91: Add MCHP_LAN966X_PCI dependency
i2c: eg20t: Consistently define pci_device_ids using named initializers
i2c: designware-pcidrv: Consistently define pci_device_ids using named initializers
i2c: bcm-kona: fix spelling mistake in timeout-check comment
i2c: cadence: Add shutdown handler
i2c: tegra: Disable fair arbitration for non-MCTP buses
i2c: tegra: use dmaengine_get_dma_device() for DMA buffer allocation
i2c: busses: make K1 driver default for SpacemiT platforms
i2c: Use named initializers for arrays of i2c_device_data
i2c: core: clean up adapter registration error label
i2c: core: clean up bus id allocation
i2c: core: fix adapter deregistration race
i2c: core: fix adapter registration race
i2c: core: disable runtime PM on adapter registration failure
...
This commit is contained in:
commit
2779759c09
|
|
@ -1,43 +0,0 @@
|
|||
* Texas Instruments Davinci/Keystone I2C
|
||||
|
||||
This file provides information, what the device node for the
|
||||
davinci/keystone i2c interface contains.
|
||||
|
||||
Required properties:
|
||||
- compatible: "ti,davinci-i2c" or "ti,keystone-i2c";
|
||||
- reg : Offset and length of the register set for the device
|
||||
- clocks: I2C functional clock phandle.
|
||||
For 66AK2G this property should be set per binding,
|
||||
Documentation/devicetree/bindings/clock/ti,sci-clk.yaml
|
||||
|
||||
SoC-specific Required Properties:
|
||||
|
||||
The following are mandatory properties for Keystone 2 66AK2G SoCs only:
|
||||
|
||||
- power-domains: Should contain a phandle to a PM domain provider node
|
||||
and an args specifier containing the I2C device id
|
||||
value. This property is as per the binding,
|
||||
Documentation/devicetree/bindings/soc/ti/sci-pm-domain.yaml
|
||||
|
||||
Recommended properties :
|
||||
- interrupts : standard interrupt property.
|
||||
- clock-frequency : desired I2C bus clock frequency in Hz.
|
||||
- ti,has-pfunc: boolean; if defined, it indicates that SoC supports PFUNC
|
||||
registers. PFUNC registers allow to switch I2C pins to function as
|
||||
GPIOs, so they can be toggled manually.
|
||||
|
||||
Example (enbw_cmc board):
|
||||
i2c@1c22000 {
|
||||
compatible = "ti,davinci-i2c";
|
||||
reg = <0x22000 0x1000>;
|
||||
clock-frequency = <100000>;
|
||||
interrupts = <15>;
|
||||
interrupt-parent = <&intc>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
dtt@48 {
|
||||
compatible = "national,lm75";
|
||||
reg = <0x48>;
|
||||
};
|
||||
};
|
||||
|
|
@ -16,6 +16,7 @@ properties:
|
|||
compatible:
|
||||
enum:
|
||||
- loongson,ls2k-i2c
|
||||
- loongson,ls2k0300-i2c
|
||||
- loongson,ls7a-i2c
|
||||
|
||||
reg:
|
||||
|
|
@ -24,6 +25,9 @@ properties:
|
|||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ properties:
|
|||
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,glymur-cci
|
||||
- qcom,kaanapali-cci
|
||||
- qcom,milos-cci
|
||||
- qcom,qcm2290-cci
|
||||
|
|
@ -35,6 +36,7 @@ properties:
|
|||
- qcom,sc8280xp-cci
|
||||
- qcom,sdm670-cci
|
||||
- qcom,sdm845-cci
|
||||
- qcom,shikra-cci
|
||||
- qcom,sm6150-cci
|
||||
- qcom,sm6350-cci
|
||||
- qcom,sm8250-cci
|
||||
|
|
@ -134,9 +136,11 @@ allOf:
|
|||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,glymur-cci
|
||||
- qcom,kaanapali-cci
|
||||
- qcom,qcm2290-cci
|
||||
- qcom,qcs8300-cci
|
||||
- qcom,shikra-cci
|
||||
- qcom,sm8750-cci
|
||||
then:
|
||||
properties:
|
||||
|
|
|
|||
70
Documentation/devicetree/bindings/i2c/ti,davinci-i2c.yaml
Normal file
70
Documentation/devicetree/bindings/i2c/ti,davinci-i2c.yaml
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/ti,davinci-i2c.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments DaVinci/Keystone I2C
|
||||
|
||||
maintainers:
|
||||
- Chaitanya Sabnis <chaitanya.msabnis@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-controller.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: ti,keystone-i2c
|
||||
then:
|
||||
required:
|
||||
- power-domains
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,davinci-i2c
|
||||
- ti,keystone-i2c
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
ti,has-pfunc:
|
||||
description:
|
||||
Indicates that the SoC supports PFUNC registers, allowing I2C pins
|
||||
to function as GPIOs for manual toggling.
|
||||
type: boolean
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c@1c22000 {
|
||||
compatible = "ti,davinci-i2c";
|
||||
reg = <0x01c22000 0x1000>;
|
||||
clocks = <&i2c_clk>;
|
||||
clock-frequency = <100000>;
|
||||
interrupts = <15>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
sensor@48 {
|
||||
compatible = "national,lm75";
|
||||
reg = <0x48>;
|
||||
};
|
||||
};
|
||||
|
|
@ -15069,6 +15069,7 @@ M: Binbin Zhou <zhoubinbin@loongson.cn>
|
|||
L: linux-i2c@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml
|
||||
F: drivers/i2c/busses/i2c-ls2x-v2.c
|
||||
F: drivers/i2c/busses/i2c-ls2x.c
|
||||
|
||||
LOONGSON PWM DRIVER
|
||||
|
|
@ -26710,7 +26711,7 @@ M: Bartosz Golaszewski <brgl@kernel.org>
|
|||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git
|
||||
F: Documentation/devicetree/bindings/i2c/i2c-davinci.txt
|
||||
F: Documentation/devicetree/bindings/i2c/ti,davinci-i2c.yaml
|
||||
F: arch/arm/boot/dts/ti/davinci/
|
||||
F: arch/arm/mach-davinci/
|
||||
F: drivers/i2c/busses/i2c-davinci.c
|
||||
|
|
|
|||
|
|
@ -181,6 +181,12 @@ static const struct apd_device_desc hip08_spi_desc = {
|
|||
.setup = acpi_apd_setup,
|
||||
.fixed_clk_rate = 250000000,
|
||||
};
|
||||
|
||||
static const struct apd_device_desc leca_i2c_desc = {
|
||||
.setup = acpi_apd_setup,
|
||||
.fixed_clk_rate = 250000000,
|
||||
};
|
||||
|
||||
#endif /* CONFIG_ARM64 */
|
||||
|
||||
#endif
|
||||
|
|
@ -251,6 +257,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = {
|
|||
{ "HISI02A2", APD_ADDR(hip08_i2c_desc) },
|
||||
{ "HISI02A3", APD_ADDR(hip08_lite_i2c_desc) },
|
||||
{ "HISI0173", APD_ADDR(hip08_spi_desc) },
|
||||
{ "LECA0003", APD_ADDR(leca_i2c_desc) },
|
||||
{ "NXP0001", APD_ADDR(nxp_i2c_desc) },
|
||||
#endif
|
||||
{ }
|
||||
|
|
|
|||
|
|
@ -417,7 +417,7 @@ config I2C_ASPEED
|
|||
|
||||
config I2C_AT91
|
||||
tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
|
||||
depends on ARCH_MICROCHIP || COMPILE_TEST
|
||||
depends on ARCH_MICROCHIP || MCHP_LAN966X_PCI || COMPILE_TEST
|
||||
help
|
||||
This supports the use of the I2C interface on Atmel AT91
|
||||
processors.
|
||||
|
|
@ -794,6 +794,7 @@ config I2C_K1
|
|||
tristate "SpacemiT K1 I2C adapter"
|
||||
depends on ARCH_SPACEMIT || COMPILE_TEST
|
||||
depends on OF
|
||||
default ARCH_SPACEMIT
|
||||
help
|
||||
This option enables support for the I2C interface on the SpacemiT K1
|
||||
platform.
|
||||
|
|
@ -850,6 +851,17 @@ config I2C_LS2X
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-ls2x.
|
||||
|
||||
config I2C_LS2X_V2
|
||||
tristate "Loongson-2 Fast Speed I2C adapter"
|
||||
depends on LOONGARCH || COMPILE_TEST
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
I2C interface on the Loongson-2K0300 SoCs.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-ls2x-v2.
|
||||
|
||||
config I2C_MLXBF
|
||||
tristate "Mellanox BlueField I2C controller"
|
||||
depends on (MELLANOX_PLATFORM && ARM64) || COMPILE_TEST
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ obj-$(CONFIG_I2C_KEBA) += i2c-keba.o
|
|||
obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o
|
||||
obj-$(CONFIG_I2C_LPC2K) += i2c-lpc2k.o
|
||||
obj-$(CONFIG_I2C_LS2X) += i2c-ls2x.o
|
||||
obj-$(CONFIG_I2C_LS2X_V2) += i2c-ls2x-v2.o
|
||||
obj-$(CONFIG_I2C_MESON) += i2c-meson.o
|
||||
obj-$(CONFIG_I2C_MICROCHIP_CORE) += i2c-microchip-corei2c.o
|
||||
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
|
||||
|
|
|
|||
|
|
@ -427,7 +427,7 @@ static int bcm_kona_i2c_write_fifo_single(struct bcm_kona_i2c_dev *dev,
|
|||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
/* Check if a timeout occured */
|
||||
/* Check if a timeout occurred */
|
||||
if (!time_left) {
|
||||
dev_err(dev->device, "completion timed out\n");
|
||||
return -EREMOTEIO;
|
||||
|
|
|
|||
|
|
@ -1635,6 +1635,25 @@ static void cdns_i2c_remove(struct platform_device *pdev)
|
|||
reset_control_assert(id->reset);
|
||||
}
|
||||
|
||||
/**
|
||||
* cdns_i2c_shutdown - Prepare I2C controller for system shutdown
|
||||
* @pdev: Handle to the platform device structure
|
||||
*
|
||||
* Mark the adapter as suspended and reset the controller to ensure a clean
|
||||
* handoff during system reboot or kexec.
|
||||
*/
|
||||
static void cdns_i2c_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct cdns_i2c *id = platform_get_drvdata(pdev);
|
||||
|
||||
/* Mark the adapter as suspended to prevent further I2C transfers */
|
||||
i2c_mark_adapter_suspended(&id->adap);
|
||||
|
||||
/* Reset the controller state if active - clocks are disabled when suspended */
|
||||
if (!pm_runtime_status_suspended(&pdev->dev))
|
||||
cdns_i2c_master_reset(&id->adap);
|
||||
}
|
||||
|
||||
static struct platform_driver cdns_i2c_drv = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
|
|
@ -1643,6 +1662,7 @@ static struct platform_driver cdns_i2c_drv = {
|
|||
},
|
||||
.probe = cdns_i2c_probe,
|
||||
.remove = cdns_i2c_remove,
|
||||
.shutdown = cdns_i2c_shutdown,
|
||||
};
|
||||
|
||||
module_platform_driver(cdns_i2c_drv);
|
||||
|
|
|
|||
|
|
@ -633,6 +633,14 @@ void __i2c_dw_disable(struct dw_i2c_dev *dev)
|
|||
|
||||
abort_needed = (raw_intr_stats & DW_IC_INTR_MST_ON_HOLD) ||
|
||||
(ic_stats & DW_IC_STATUS_MASTER_HOLD_TX_FIFO_EMPTY);
|
||||
|
||||
/*
|
||||
* If we are in target mode and there is activity, we should also
|
||||
* trigger an abort to clear the internal state machines.
|
||||
*/
|
||||
if (dev->mode == DW_IC_SLAVE && (ic_stats & DW_IC_STATUS_SLAVE_ACTIVITY))
|
||||
abort_needed = true;
|
||||
|
||||
if (abort_needed) {
|
||||
if (!(enable & DW_IC_ENABLE_ENABLE)) {
|
||||
regmap_write(dev->map, DW_IC_ENABLE, DW_IC_ENABLE_ENABLE);
|
||||
|
|
@ -958,8 +966,8 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
|
|||
* registered to the device core and immediate resume in case bus has
|
||||
* registered I2C slaves that do I2C transfers in their probe.
|
||||
*/
|
||||
ACQUIRE(pm_runtime_noresume, pm)(dev->dev);
|
||||
ret = ACQUIRE_ERR(pm_runtime_noresume, &pm);
|
||||
PM_RUNTIME_ACQUIRE(dev->dev, pm);
|
||||
ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -1028,5 +1036,29 @@ EXPORT_GPL_DEV_PM_OPS(i2c_dw_dev_pm_ops) = {
|
|||
RUNTIME_PM_OPS(i2c_dw_runtime_suspend, i2c_dw_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
void i2c_dw_shutdown(struct dw_i2c_dev *dev)
|
||||
{
|
||||
unsigned int con;
|
||||
|
||||
/*
|
||||
* We only need to handle shutdown for target mode to ensure
|
||||
* we NACK any incoming controller requests. Controller mode cleanup
|
||||
* is handled after each transfer in i2c_dw_xfer().
|
||||
*/
|
||||
if (dev->mode != DW_IC_SLAVE)
|
||||
return;
|
||||
|
||||
/*
|
||||
* To quickly NACK the controller during shutdown, we set the target
|
||||
* disable bit while the controller is still enabled.
|
||||
*/
|
||||
regmap_read(dev->map, DW_IC_CON, &con);
|
||||
con |= DW_IC_CON_SLAVE_DISABLE;
|
||||
regmap_write(dev->map, DW_IC_CON, con);
|
||||
|
||||
i2c_dw_disable(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_dw_shutdown);
|
||||
|
||||
MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -417,6 +417,7 @@ static inline void i2c_dw_configure(struct dw_i2c_dev *dev)
|
|||
|
||||
int i2c_dw_probe(struct dw_i2c_dev *dev);
|
||||
int i2c_dw_init(struct dw_i2c_dev *dev);
|
||||
void i2c_dw_shutdown(struct dw_i2c_dev *dev);
|
||||
void i2c_dw_set_mode(struct dw_i2c_dev *dev, int mode);
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL)
|
||||
|
|
|
|||
|
|
@ -785,18 +785,25 @@ __i2c_dw_xfer_one_part(struct dw_i2c_dev *dev, struct i2c_msg *msgs, size_t num)
|
|||
* IC_RAW_INTR_STAT.MASTER_ON_HOLD holding SCL low. Check if
|
||||
* controller is still ACTIVE before disabling I2C.
|
||||
*/
|
||||
if (i2c_dw_is_controller_active(dev))
|
||||
dev_err(dev->dev, "controller active\n");
|
||||
|
||||
/*
|
||||
* We must disable the adapter before returning and signaling the end
|
||||
* of the current transfer. Otherwise the hardware might continue
|
||||
* generating interrupts which in turn causes a race condition with
|
||||
* the following transfer. Needs some more investigation if the
|
||||
* additional interrupts are a hardware bug or this driver doesn't
|
||||
* handle them correctly yet.
|
||||
*/
|
||||
__i2c_dw_disable_nowait(dev);
|
||||
if (i2c_dw_is_controller_active(dev)) {
|
||||
/*
|
||||
* If the controller is still active after the timeout, attempt a
|
||||
* bus recovery to clear any potentially locked state.
|
||||
*/
|
||||
dev_err(dev->dev, "controller active after xfer, recovering\n");
|
||||
i2c_recover_bus(&dev->adapter);
|
||||
i2c_dw_init(dev);
|
||||
} else {
|
||||
/*
|
||||
* We must disable the adapter before returning and signaling the end
|
||||
* of the current transfer. Otherwise the hardware might continue
|
||||
* generating interrupts which in turn causes a race condition with
|
||||
* the following transfer. Needs some more investigation if the
|
||||
* additional interrupts are a hardware bug or this driver doesn't
|
||||
* handle them correctly yet.
|
||||
*/
|
||||
__i2c_dw_disable_nowait(dev);
|
||||
}
|
||||
|
||||
if (dev->msg_err)
|
||||
return dev->msg_err;
|
||||
|
|
|
|||
|
|
@ -308,58 +308,72 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev)
|
|||
|
||||
static const struct pci_device_id i2c_designware_pci_ids[] = {
|
||||
/* Medfield */
|
||||
{ PCI_VDEVICE(INTEL, 0x0817), medfield },
|
||||
{ PCI_VDEVICE(INTEL, 0x0818), medfield },
|
||||
{ PCI_VDEVICE(INTEL, 0x0819), medfield },
|
||||
{ PCI_VDEVICE(INTEL, 0x082C), medfield },
|
||||
{ PCI_VDEVICE(INTEL, 0x082D), medfield },
|
||||
{ PCI_VDEVICE(INTEL, 0x082E), medfield },
|
||||
{ PCI_VDEVICE(INTEL, 0x0817), .driver_data = medfield },
|
||||
{ PCI_VDEVICE(INTEL, 0x0818), .driver_data = medfield },
|
||||
{ PCI_VDEVICE(INTEL, 0x0819), .driver_data = medfield },
|
||||
{ PCI_VDEVICE(INTEL, 0x082C), .driver_data = medfield },
|
||||
{ PCI_VDEVICE(INTEL, 0x082D), .driver_data = medfield },
|
||||
{ PCI_VDEVICE(INTEL, 0x082E), .driver_data = medfield },
|
||||
/* Merrifield */
|
||||
{ PCI_VDEVICE(INTEL, 0x1195), merrifield },
|
||||
{ PCI_VDEVICE(INTEL, 0x1196), merrifield },
|
||||
{ PCI_VDEVICE(INTEL, 0x1195), .driver_data = merrifield },
|
||||
{ PCI_VDEVICE(INTEL, 0x1196), .driver_data = merrifield },
|
||||
/* Baytrail */
|
||||
{ PCI_VDEVICE(INTEL, 0x0F41), baytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x0F42), baytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x0F43), baytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x0F44), baytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x0F45), baytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x0F46), baytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x0F47), baytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x0F41), .driver_data = baytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x0F42), .driver_data = baytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x0F43), .driver_data = baytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x0F44), .driver_data = baytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x0F45), .driver_data = baytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x0F46), .driver_data = baytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x0F47), .driver_data = baytrail },
|
||||
/* Haswell */
|
||||
{ PCI_VDEVICE(INTEL, 0x9c61), haswell },
|
||||
{ PCI_VDEVICE(INTEL, 0x9c62), haswell },
|
||||
{ PCI_VDEVICE(INTEL, 0x9c61), .driver_data = haswell },
|
||||
{ PCI_VDEVICE(INTEL, 0x9c62), .driver_data = haswell },
|
||||
/* Braswell / Cherrytrail */
|
||||
{ PCI_VDEVICE(INTEL, 0x22C1), cherrytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C2), cherrytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C3), cherrytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C4), cherrytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C5), cherrytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C6), cherrytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C7), cherrytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C1), .driver_data = cherrytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C2), .driver_data = cherrytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C3), .driver_data = cherrytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C4), .driver_data = cherrytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C5), .driver_data = cherrytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C6), .driver_data = cherrytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C7), .driver_data = cherrytrail },
|
||||
/* Elkhart Lake (PSE I2C) */
|
||||
{ PCI_VDEVICE(INTEL, 0x4bb9), elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bba), elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bbb), elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bbc), elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bbd), elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bbe), elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bbf), elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bc0), elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bb9), .driver_data = elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bba), .driver_data = elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bbb), .driver_data = elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bbc), .driver_data = elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bbd), .driver_data = elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bbe), .driver_data = elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bbf), .driver_data = elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bc0), .driver_data = elkhartlake },
|
||||
/* AMD NAVI */
|
||||
{ PCI_VDEVICE(ATI, 0x7314), navi_amd },
|
||||
{ PCI_VDEVICE(ATI, 0x73a4), navi_amd },
|
||||
{ PCI_VDEVICE(ATI, 0x73e4), navi_amd },
|
||||
{ PCI_VDEVICE(ATI, 0x73c4), navi_amd },
|
||||
{ PCI_VDEVICE(ATI, 0x7444), navi_amd },
|
||||
{ PCI_VDEVICE(ATI, 0x7464), navi_amd },
|
||||
{}
|
||||
{ PCI_VDEVICE(ATI, 0x7314), .driver_data = navi_amd },
|
||||
{ PCI_VDEVICE(ATI, 0x73a4), .driver_data = navi_amd },
|
||||
{ PCI_VDEVICE(ATI, 0x73e4), .driver_data = navi_amd },
|
||||
{ PCI_VDEVICE(ATI, 0x73c4), .driver_data = navi_amd },
|
||||
{ PCI_VDEVICE(ATI, 0x7444), .driver_data = navi_amd },
|
||||
{ PCI_VDEVICE(ATI, 0x7464), .driver_data = navi_amd },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, i2c_designware_pci_ids);
|
||||
|
||||
static void i2c_dw_pci_shutdown(struct pci_dev *pdev)
|
||||
{
|
||||
struct dw_i2c_dev *i_dev;
|
||||
|
||||
i_dev = pci_get_drvdata(pdev);
|
||||
if (!i_dev)
|
||||
return;
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
if (!pm_runtime_status_suspended(&pdev->dev))
|
||||
i2c_dw_shutdown(i_dev);
|
||||
}
|
||||
|
||||
static struct pci_driver dw_i2c_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe = i2c_dw_pci_probe,
|
||||
.remove = i2c_dw_pci_remove,
|
||||
.shutdown = i2c_dw_pci_shutdown,
|
||||
.driver = {
|
||||
.pm = pm_ptr(&i2c_dw_dev_pm_ops),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -279,6 +279,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
|
|||
{ "INT3432", 0 },
|
||||
{ "INT3433", 0 },
|
||||
{ "INTC10EF", 0 },
|
||||
{ "LECA0003", 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
|
||||
|
|
@ -289,9 +290,23 @@ static const struct platform_device_id dw_i2c_platform_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(platform, dw_i2c_platform_ids);
|
||||
|
||||
static void dw_i2c_plat_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct dw_i2c_dev *i_dev;
|
||||
|
||||
i_dev = platform_get_drvdata(pdev);
|
||||
if (!i_dev)
|
||||
return;
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
if (!pm_runtime_status_suspended(&pdev->dev))
|
||||
i2c_dw_shutdown(i_dev);
|
||||
}
|
||||
|
||||
static struct platform_driver dw_i2c_driver = {
|
||||
.probe = dw_i2c_plat_probe,
|
||||
.remove = dw_i2c_plat_remove,
|
||||
.shutdown = dw_i2c_plat_shutdown,
|
||||
.driver = {
|
||||
.name = "i2c_designware",
|
||||
.of_match_table = dw_i2c_of_match,
|
||||
|
|
|
|||
|
|
@ -169,11 +169,11 @@ static DEFINE_MUTEX(pch_mutex);
|
|||
#define PCI_DEVICE_ID_ML7831_I2C 0x8817
|
||||
|
||||
static const struct pci_device_id pch_pcidev_id[] = {
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, },
|
||||
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
|
||||
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, },
|
||||
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_I2C), 1, },
|
||||
{0,}
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), .driver_data = 1 },
|
||||
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), .driver_data = 2 },
|
||||
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), .driver_data = 1 },
|
||||
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_I2C), .driver_data = 1 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pch_pcidev_id);
|
||||
|
||||
|
|
|
|||
|
|
@ -193,8 +193,8 @@ static void icy_remove(struct zorro_dev *z)
|
|||
}
|
||||
|
||||
static const struct zorro_device_id icy_zorro_tbl[] = {
|
||||
{ ZORRO_ID(VMC, 15, 0), },
|
||||
{ 0 }
|
||||
{ .id = ZORRO_ID(VMC, 15, 0) },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(zorro, icy_zorro_tbl);
|
||||
|
|
|
|||
544
drivers/i2c/busses/i2c-ls2x-v2.c
Normal file
544
drivers/i2c/busses/i2c-ls2x-v2.c
Normal file
|
|
@ -0,0 +1,544 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Loongson-2K0300 I2C controller driver
|
||||
*
|
||||
* Copyright (C) 2025-2026 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
/* Loongson-2 fast I2C offset registers */
|
||||
#define LOONGSON2_I2C_CR1 0x00 /* I2C control 1 register */
|
||||
#define LOONGSON2_I2C_CR2 0x04 /* I2C control 2 register */
|
||||
#define LOONGSON2_I2C_OAR 0x08 /* I2C slave address register */
|
||||
#define LOONGSON2_I2C_DR 0x10 /* I2C data register */
|
||||
#define LOONGSON2_I2C_SR1 0x14 /* I2C status 1 register */
|
||||
#define LOONGSON2_I2C_SR2 0x18 /* I2C status 2 register */
|
||||
#define LOONGSON2_I2C_CCR 0x1c /* I2C clock control register */
|
||||
#define LOONGSON2_I2C_TRISE 0x20 /* I2C trise register */
|
||||
#define LOONGSON2_I2C_FLTR 0x24
|
||||
|
||||
/* Bitfields of I2C control 1 register */
|
||||
#define LOONGSON2_I2C_CR1_PE BIT(0) /* Peripheral enable */
|
||||
#define LOONGSON2_I2C_CR1_START BIT(8) /* Start generation */
|
||||
#define LOONGSON2_I2C_CR1_STOP BIT(9) /* Stop generation */
|
||||
#define LOONGSON2_I2C_CR1_ACK BIT(10) /* Acknowledge enable */
|
||||
#define LOONGSON2_I2C_CR1_POS BIT(11) /* Acknowledge/PEC Position (for data reception) */
|
||||
|
||||
#define LOONGSON2_I2C_CR1_OP_MASK (LOONGSON2_I2C_CR1_START | LOONGSON2_I2C_CR1_STOP)
|
||||
|
||||
/* Bitfields of I2C control 2 register */
|
||||
#define LOONGSON2_I2C_CR2_FREQ GENMASK(5, 0) /* APB Clock Frequency in MHz */
|
||||
#define LOONGSON2_I2C_CR2_ITERREN BIT(8) /* Fault-Class Interrupt Enable */
|
||||
#define LOONGSON2_I2C_CR2_ITEVTEN BIT(9) /* Event-Based Interrupt Enable */
|
||||
#define LOONGSON2_I2C_CR2_ITBUFEN BIT(10) /* Cache-Class Interrupt Enable */
|
||||
|
||||
#define LOONGSON2_I2C_CR2_INT_MASK \
|
||||
(LOONGSON2_I2C_CR2_ITBUFEN | LOONGSON2_I2C_CR2_ITEVTEN | LOONGSON2_I2C_CR2_ITERREN)
|
||||
|
||||
/* Bitfields of I2C status 1 register */
|
||||
#define LOONGSON2_I2C_SR1_SB BIT(0) /* Start bit (Master mode) */
|
||||
#define LOONGSON2_I2C_SR1_ADDR BIT(1) /* Address sent (master mode) */
|
||||
#define LOONGSON2_I2C_SR1_BTF BIT(2) /* Byte transfer finished */
|
||||
#define LOONGSON2_I2C_SR1_RXNE BIT(6) /* Data register not empty (receivers) */
|
||||
#define LOONGSON2_I2C_SR1_TXE BIT(7) /* Data register empty (transmitters) */
|
||||
#define LOONGSON2_I2C_SR1_BERR BIT(8) /* Bus error */
|
||||
#define LOONGSON2_I2C_SR1_ARLO BIT(9) /* Arbitration lost (master mode) */
|
||||
#define LOONGSON2_I2C_SR1_AF BIT(10) /* Acknowledge failure */
|
||||
|
||||
#define LOONGSON2_I2C_SR1_ITEVTEN_MASK \
|
||||
(LOONGSON2_I2C_SR1_BTF | LOONGSON2_I2C_SR1_ADDR | LOONGSON2_I2C_SR1_SB)
|
||||
#define LOONGSON2_I2C_SR1_ITBUFEN_MASK (LOONGSON2_I2C_SR1_TXE | LOONGSON2_I2C_SR1_RXNE)
|
||||
#define LOONGSON2_I2C_SR1_ITERREN_MASK \
|
||||
(LOONGSON2_I2C_SR1_AF | LOONGSON2_I2C_SR1_ARLO | LOONGSON2_I2C_SR1_BERR)
|
||||
|
||||
/* Bitfields of I2C status 2 register */
|
||||
#define LOONGSON2_I2C_SR2_MSL BIT(0) /* Master/slave */
|
||||
#define LOONGSON2_I2C_SR2_BUSY BIT(1) /* Bus busy */
|
||||
#define LOONGSON2_I2C_SR2_TRA BIT(2) /* Transmitter/receiver */
|
||||
#define LOONGSON2_I2C_SR2_GENCALL BIT(4) /* General call address (Slave mode) */
|
||||
|
||||
/* Bitfields of I2C clock control register */
|
||||
#define LOONGSON2_I2C_CCR_CCR GENMASK(11, 0)
|
||||
#define LOONGSON2_I2C_CCR_DUTY BIT(14)
|
||||
#define LOONGSON2_I2C_CCR_FS BIT(15)
|
||||
|
||||
/* Bitfields of I2C trise register */
|
||||
#define LOONGSON2_I2C_TRISE_SCL GENMASK(5, 0)
|
||||
|
||||
#define LOONGSON2_I2C_FREE_SLEEP_US 10
|
||||
#define LOONGSON2_I2C_FREE_TIMEOUT_US (2 * USEC_PER_MSEC)
|
||||
|
||||
/**
|
||||
* struct loongson2_i2c_msg - client specific data
|
||||
* @buf: data buffer
|
||||
* @count: number of bytes to be transferred
|
||||
* @result: result of the transfer
|
||||
* @addr: 8-bit slave addr, including r/w bit
|
||||
* @stop: last I2C msg to be sent, i.e. STOP to be generated
|
||||
*/
|
||||
struct loongson2_i2c_msg {
|
||||
u8 *buf;
|
||||
u32 count;
|
||||
int result;
|
||||
u8 addr;
|
||||
bool stop;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct loongson2_i2c_priv - private data of the controller
|
||||
* @adapter: I2C adapter for this controller
|
||||
* @complete: completion of I2C message
|
||||
* @clk: hw i2c clock
|
||||
* @regmap: regmap of the I2C device
|
||||
* @parent_rate_MHz: I2C clock parent rate
|
||||
* @msg: I2C transfer information
|
||||
*/
|
||||
struct loongson2_i2c_priv {
|
||||
struct i2c_adapter adapter;
|
||||
struct completion complete;
|
||||
struct clk *clk;
|
||||
struct regmap *regmap;
|
||||
unsigned long parent_rate_MHz;
|
||||
struct loongson2_i2c_msg msg;
|
||||
};
|
||||
|
||||
static void loongson2_i2c_disable_irq(struct loongson2_i2c_priv *priv)
|
||||
{
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR2, LOONGSON2_I2C_CR2_INT_MASK, 0);
|
||||
}
|
||||
|
||||
static void loongson2_i2c_read_msg(struct loongson2_i2c_priv *priv)
|
||||
{
|
||||
struct loongson2_i2c_msg *msg = &priv->msg;
|
||||
u32 rbuf;
|
||||
|
||||
regmap_read(priv->regmap, LOONGSON2_I2C_DR, &rbuf);
|
||||
*msg->buf++ = rbuf;
|
||||
msg->count--;
|
||||
}
|
||||
|
||||
static void loongson2_i2c_write_msg(struct loongson2_i2c_priv *priv, u8 byte)
|
||||
{
|
||||
regmap_write(priv->regmap, LOONGSON2_I2C_DR, byte);
|
||||
}
|
||||
|
||||
static void loongson2_i2c_terminate_xfer(struct loongson2_i2c_priv *priv)
|
||||
{
|
||||
struct loongson2_i2c_msg *msg = &priv->msg;
|
||||
|
||||
loongson2_i2c_disable_irq(priv);
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_OP_MASK,
|
||||
msg->stop ? LOONGSON2_I2C_CR1_STOP : LOONGSON2_I2C_CR1_START);
|
||||
complete(&priv->complete);
|
||||
}
|
||||
|
||||
static void loongson2_i2c_handle_write(struct loongson2_i2c_priv *priv)
|
||||
{
|
||||
struct loongson2_i2c_msg *msg = &priv->msg;
|
||||
|
||||
if (msg->count) {
|
||||
loongson2_i2c_write_msg(priv, *msg->buf++);
|
||||
if (!--msg->count)
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR2,
|
||||
LOONGSON2_I2C_CR2_ITBUFEN, 0);
|
||||
} else {
|
||||
loongson2_i2c_terminate_xfer(priv);
|
||||
}
|
||||
}
|
||||
|
||||
static void loongson2_i2c_handle_rx_addr(struct loongson2_i2c_priv *priv)
|
||||
{
|
||||
struct loongson2_i2c_msg *msg = &priv->msg;
|
||||
|
||||
switch (msg->count) {
|
||||
case 0:
|
||||
loongson2_i2c_terminate_xfer(priv);
|
||||
break;
|
||||
case 1:
|
||||
/* Enable NACK and reset POS (Acknowledge position) */
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1,
|
||||
LOONGSON2_I2C_CR1_ACK | LOONGSON2_I2C_CR1_POS, 0);
|
||||
/* Set STOP or RepSTART */
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_OP_MASK,
|
||||
msg->stop ? LOONGSON2_I2C_CR1_STOP : LOONGSON2_I2C_CR1_START);
|
||||
break;
|
||||
case 2:
|
||||
/* Enable NACK */
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_ACK, 0);
|
||||
/* Set POS (NACK position) */
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_POS,
|
||||
LOONGSON2_I2C_CR1_POS);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Enable ACK */
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_ACK,
|
||||
LOONGSON2_I2C_CR1_ACK);
|
||||
/* Reset POS (ACK position) */
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_POS, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void loongson2_i2c_isr_error(u32 status, void *data)
|
||||
{
|
||||
struct loongson2_i2c_priv *priv = data;
|
||||
struct loongson2_i2c_msg *msg = &priv->msg;
|
||||
|
||||
/* Arbitration lost */
|
||||
if (status & LOONGSON2_I2C_SR1_ARLO) {
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_SR1, LOONGSON2_I2C_SR1_ARLO, 0);
|
||||
msg->result = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Acknowledge failure:
|
||||
* In master transmitter mode a Stop must be generated by software.
|
||||
*/
|
||||
if (status & LOONGSON2_I2C_SR1_AF) {
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_STOP,
|
||||
LOONGSON2_I2C_CR1_STOP);
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_SR1, LOONGSON2_I2C_SR1_AF, 0);
|
||||
msg->result = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Bus error */
|
||||
if (status & LOONGSON2_I2C_SR1_BERR) {
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_SR1, LOONGSON2_I2C_SR1_BERR, 0);
|
||||
msg->result = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
loongson2_i2c_disable_irq(priv);
|
||||
complete(&priv->complete);
|
||||
}
|
||||
|
||||
static void loongson2_i2c_handle_read(struct loongson2_i2c_priv *priv)
|
||||
{
|
||||
struct loongson2_i2c_msg *msg = &priv->msg;
|
||||
|
||||
switch (msg->count) {
|
||||
case 1:
|
||||
loongson2_i2c_disable_irq(priv);
|
||||
loongson2_i2c_read_msg(priv);
|
||||
complete(&priv->complete);
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
/*
|
||||
* For 2-byte/3-byte reception and for N-byte reception with N > 3, we have to
|
||||
* wait for byte transferred finished event before reading data.
|
||||
* Just disable buffer interrupt in order to avoid another system preemption due
|
||||
* to RX not empty event.
|
||||
*/
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR2, LOONGSON2_I2C_CR2_ITBUFEN, 0);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* For N byte reception with N > 3 we directly read data register
|
||||
* until N-2 data.
|
||||
*/
|
||||
loongson2_i2c_read_msg(priv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void loongson2_i2c_handle_rx_done(struct loongson2_i2c_priv *priv)
|
||||
{
|
||||
struct loongson2_i2c_msg *msg = &priv->msg;
|
||||
|
||||
switch (msg->count) {
|
||||
case 2:
|
||||
/*
|
||||
* The STOP/START bit has to be set before reading the last two bytes.
|
||||
* After that, we could read the last two bytes.
|
||||
*/
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_OP_MASK,
|
||||
msg->stop ? LOONGSON2_I2C_CR1_STOP : LOONGSON2_I2C_CR1_START);
|
||||
|
||||
for (unsigned int i = msg->count; i > 0; i--)
|
||||
loongson2_i2c_read_msg(priv);
|
||||
|
||||
loongson2_i2c_disable_irq(priv);
|
||||
|
||||
complete(&priv->complete);
|
||||
break;
|
||||
case 3:
|
||||
/*
|
||||
* In order to generate the NACK after the last received data byte, enable NACK
|
||||
* before reading N-2 data.
|
||||
*/
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_ACK, 0);
|
||||
loongson2_i2c_read_msg(priv);
|
||||
break;
|
||||
default:
|
||||
loongson2_i2c_read_msg(priv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t loongson2_i2c_isr_event(int irq, void *data)
|
||||
{
|
||||
struct loongson2_i2c_priv *priv = data;
|
||||
struct device *dev = regmap_get_device(priv->regmap);
|
||||
struct loongson2_i2c_msg *msg = &priv->msg;
|
||||
u32 status, ien, event, cr2, possible_status;
|
||||
|
||||
regmap_read(priv->regmap, LOONGSON2_I2C_SR1, &status);
|
||||
if (status & LOONGSON2_I2C_SR1_ITERREN_MASK) {
|
||||
loongson2_i2c_isr_error(status, data);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
regmap_read(priv->regmap, LOONGSON2_I2C_CR2, &cr2);
|
||||
ien = cr2 & LOONGSON2_I2C_CR2_INT_MASK;
|
||||
|
||||
/* Update possible_status if buffer interrupt is enabled */
|
||||
possible_status = LOONGSON2_I2C_SR1_ITEVTEN_MASK;
|
||||
if (ien & LOONGSON2_I2C_CR2_ITBUFEN)
|
||||
possible_status |= LOONGSON2_I2C_SR1_ITBUFEN_MASK;
|
||||
|
||||
event = status & possible_status;
|
||||
if (!event) {
|
||||
dev_dbg(dev, "spurious evt IRQ (status=0x%08x, ien=0x%08x)\n", status, ien);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/* Start condition generated */
|
||||
if (event & LOONGSON2_I2C_SR1_SB)
|
||||
loongson2_i2c_write_msg(priv, msg->addr);
|
||||
|
||||
/* I2C Address sent */
|
||||
if (event & LOONGSON2_I2C_SR1_ADDR) {
|
||||
if (msg->addr & I2C_M_RD)
|
||||
loongson2_i2c_handle_rx_addr(priv);
|
||||
/* Clear ADDR flag */
|
||||
regmap_read(priv->regmap, LOONGSON2_I2C_SR2, &status);
|
||||
/* Enable buffer interrupts for RX/TX not empty events */
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR2, LOONGSON2_I2C_CR2_ITBUFEN,
|
||||
LOONGSON2_I2C_CR2_ITBUFEN);
|
||||
}
|
||||
|
||||
/* TX empty */
|
||||
if ((event & LOONGSON2_I2C_SR1_TXE) && !(msg->addr & I2C_M_RD))
|
||||
loongson2_i2c_handle_write(priv);
|
||||
|
||||
/* RX not empty */
|
||||
if ((event & LOONGSON2_I2C_SR1_RXNE) && (msg->addr & I2C_M_RD))
|
||||
loongson2_i2c_handle_read(priv);
|
||||
|
||||
/*
|
||||
* The BTF (Byte Transfer finished) event occurs when:
|
||||
* - in reception: a new byte is received in the shift register
|
||||
* but the previous byte has not been read yet from data register
|
||||
* - in transmission: a new byte should be sent but the data register
|
||||
* has not been written yet
|
||||
*/
|
||||
if (event & LOONGSON2_I2C_SR1_BTF) {
|
||||
if (msg->addr & I2C_M_RD)
|
||||
loongson2_i2c_handle_rx_done(priv);
|
||||
else
|
||||
loongson2_i2c_handle_write(priv);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int loongson2_i2c_xfer_msg(struct loongson2_i2c_priv *priv, struct i2c_msg *msg,
|
||||
bool is_stop)
|
||||
{
|
||||
struct loongson2_i2c_msg *l_msg = &priv->msg;
|
||||
unsigned long timeout;
|
||||
|
||||
l_msg->addr = i2c_8bit_addr_from_msg(msg);
|
||||
l_msg->buf = msg->buf;
|
||||
l_msg->count = msg->len;
|
||||
l_msg->stop = is_stop;
|
||||
l_msg->result = 0;
|
||||
|
||||
reinit_completion(&priv->complete);
|
||||
|
||||
/* Enable events and errors interrupts */
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR2,
|
||||
LOONGSON2_I2C_CR2_ITEVTEN | LOONGSON2_I2C_CR2_ITERREN,
|
||||
LOONGSON2_I2C_CR2_ITEVTEN | LOONGSON2_I2C_CR2_ITERREN);
|
||||
|
||||
timeout = wait_for_completion_timeout(&priv->complete, priv->adapter.timeout);
|
||||
if (!timeout)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return l_msg->result;
|
||||
}
|
||||
|
||||
static int loongson2_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct loongson2_i2c_priv *priv = i2c_get_adapdata(i2c_adap);
|
||||
struct device *dev = regmap_get_device(priv->regmap);
|
||||
unsigned int status;
|
||||
int ret;
|
||||
|
||||
/* Wait I2C bus free */
|
||||
ret = regmap_read_poll_timeout(priv->regmap, LOONGSON2_I2C_SR2, status,
|
||||
!(status & LOONGSON2_I2C_SR2_BUSY),
|
||||
LOONGSON2_I2C_FREE_SLEEP_US,
|
||||
LOONGSON2_I2C_FREE_TIMEOUT_US);
|
||||
if (ret) {
|
||||
dev_dbg(dev, "The I2C bus is busy now.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Start generation */
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_START,
|
||||
LOONGSON2_I2C_CR1_START);
|
||||
|
||||
for (unsigned int i = 0; i < num; i++) {
|
||||
ret = loongson2_i2c_xfer_msg(priv, &msgs[i], i == num - 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static u32 loongson2_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm loongson2_i2c_algo = {
|
||||
.xfer = loongson2_i2c_xfer,
|
||||
.functionality = loongson2_i2c_func,
|
||||
};
|
||||
|
||||
static int loongson2_i2c_adjust_bus_speed(struct loongson2_i2c_priv *priv)
|
||||
{
|
||||
struct device *dev = regmap_get_device(priv->regmap);
|
||||
struct i2c_timings i2c_t;
|
||||
u32 val, freq_MHz, ccr;
|
||||
|
||||
i2c_parse_fw_timings(dev, &i2c_t, true);
|
||||
priv->parent_rate_MHz = clk_get_rate(priv->clk);
|
||||
|
||||
if (i2c_t.bus_freq_hz == I2C_MAX_STANDARD_MODE_FREQ) {
|
||||
/* Select Standard mode */
|
||||
ccr = 0;
|
||||
val = DIV_ROUND_UP(priv->parent_rate_MHz, i2c_t.bus_freq_hz * 2);
|
||||
} else if (i2c_t.bus_freq_hz == I2C_MAX_FAST_MODE_FREQ) {
|
||||
/* Select Fast mode */
|
||||
ccr = LOONGSON2_I2C_CCR_FS;
|
||||
val = DIV_ROUND_UP(priv->parent_rate_MHz, i2c_t.bus_freq_hz * 3);
|
||||
} else {
|
||||
return dev_err_probe(dev, -EINVAL, "Unsupported speed (%uHz)\n", i2c_t.bus_freq_hz);
|
||||
}
|
||||
|
||||
FIELD_MODIFY(LOONGSON2_I2C_CCR_CCR, &ccr, val);
|
||||
regmap_write(priv->regmap, LOONGSON2_I2C_CCR, ccr);
|
||||
|
||||
freq_MHz = DIV_ROUND_UP(priv->parent_rate_MHz, HZ_PER_MHZ);
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR2, LOONGSON2_I2C_CR2_FREQ,
|
||||
FIELD_GET(LOONGSON2_I2C_CR2_FREQ, freq_MHz));
|
||||
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_TRISE, LOONGSON2_I2C_TRISE_SCL,
|
||||
LOONGSON2_I2C_TRISE_SCL);
|
||||
|
||||
/* Enable I2C */
|
||||
regmap_update_bits(priv->regmap, LOONGSON2_I2C_CR1, LOONGSON2_I2C_CR1_PE,
|
||||
LOONGSON2_I2C_CR1_PE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct regmap_config loongson2_i2c_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.max_register = LOONGSON2_I2C_TRISE,
|
||||
};
|
||||
|
||||
static int loongson2_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct loongson2_i2c_priv *priv;
|
||||
struct i2c_adapter *adap;
|
||||
void __iomem *base;
|
||||
int irq, ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
priv->regmap = devm_regmap_init_mmio(dev, base, &loongson2_i2c_regmap_config);
|
||||
if (IS_ERR(priv->regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->regmap), "Failed to init regmap.\n");
|
||||
|
||||
priv->clk = devm_clk_get_enabled(dev, NULL);
|
||||
if (IS_ERR(priv->clk))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->clk), "Failed to enable clock.\n");
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
adap = &priv->adapter;
|
||||
adap->retries = 5;
|
||||
adap->nr = pdev->id;
|
||||
adap->dev.parent = dev;
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->algo = &loongson2_i2c_algo;
|
||||
adap->timeout = 2 * HZ;
|
||||
device_set_node(&adap->dev, dev_fwnode(dev));
|
||||
i2c_set_adapdata(adap, priv);
|
||||
strscpy(adap->name, pdev->name);
|
||||
init_completion(&priv->complete);
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
ret = loongson2_i2c_adjust_bus_speed(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_request_irq(dev, irq, loongson2_i2c_isr_event, IRQF_SHARED, pdev->name, priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_i2c_add_adapter(dev, adap);
|
||||
}
|
||||
|
||||
static const struct of_device_id loongson2_i2c_id_table[] = {
|
||||
{ .compatible = "loongson,ls2k0300-i2c" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, loongson2_i2c_id_table);
|
||||
|
||||
static struct platform_driver loongson2_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "loongson2-i2c-v2",
|
||||
.of_match_table = loongson2_i2c_id_table,
|
||||
},
|
||||
.probe = loongson2_i2c_probe,
|
||||
};
|
||||
module_platform_driver(loongson2_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Loongson-2K0300 I2C bus driver");
|
||||
MODULE_AUTHOR("Loongson Technology Corporation Limited");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -108,6 +108,14 @@ enum mxs_i2c_devtype {
|
|||
* @cmd_complete: completion object for transaction wait
|
||||
* @cmd_err: error code for last transaction
|
||||
* @adapter: i2c subsystem adapter node
|
||||
* @timing0: I2C TIMING0 register value
|
||||
* @timing1: I2C TIMING1 register value
|
||||
* @timing2: I2C TIMING2 register value
|
||||
* @dmach: DMA channel
|
||||
* @pio_data: PIO data for DMA
|
||||
* @addr_data: address data for DMA
|
||||
* @sg_io: scatterlist for I/O
|
||||
* @dma_read: flag indicating DMA read
|
||||
*/
|
||||
struct mxs_i2c_dev {
|
||||
struct device *dev;
|
||||
|
|
|
|||
|
|
@ -110,7 +110,6 @@ struct geni_i2c_dev {
|
|||
struct clk *core_clk;
|
||||
u32 clk_freq_out;
|
||||
const struct geni_i2c_clk_fld *clk_fld;
|
||||
int suspended;
|
||||
void *dma_buf;
|
||||
size_t xfer_len;
|
||||
dma_addr_t dma_addr;
|
||||
|
|
@ -1143,7 +1142,6 @@ static int geni_i2c_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto err_dma;
|
||||
|
||||
gi2c->suspended = 1;
|
||||
pm_runtime_set_suspended(gi2c->se.dev);
|
||||
pm_runtime_set_autosuspend_delay(gi2c->se.dev, I2C_AUTO_SUSPEND_DELAY);
|
||||
pm_runtime_use_autosuspend(gi2c->se.dev);
|
||||
|
|
@ -1200,9 +1198,6 @@ static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev)
|
|||
if (ret) {
|
||||
enable_irq(gi2c->irq);
|
||||
return ret;
|
||||
|
||||
} else {
|
||||
gi2c->suspended = 1;
|
||||
}
|
||||
|
||||
clk_disable_unprepare(gi2c->core_clk);
|
||||
|
|
@ -1228,7 +1223,6 @@ static int __maybe_unused geni_i2c_runtime_resume(struct device *dev)
|
|||
goto out_clk_disable;
|
||||
|
||||
enable_irq(gi2c->irq);
|
||||
gi2c->suspended = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
@ -1243,21 +1237,25 @@ static int __maybe_unused geni_i2c_runtime_resume(struct device *dev)
|
|||
static int __maybe_unused geni_i2c_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
i2c_mark_adapter_suspended(&gi2c->adap);
|
||||
|
||||
if (!gi2c->suspended) {
|
||||
geni_i2c_runtime_suspend(dev);
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_suspended(dev);
|
||||
pm_runtime_enable(dev);
|
||||
}
|
||||
return 0;
|
||||
ret = pm_runtime_force_suspend(dev);
|
||||
if (ret)
|
||||
i2c_mark_adapter_resumed(&gi2c->adap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused geni_i2c_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_force_resume(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
i2c_mark_adapter_resumed(&gi2c->adap);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -431,24 +431,23 @@ static int sis630_setup(struct pci_dev *sis630_dev)
|
|||
in acpi io space and read acpi base addr
|
||||
*/
|
||||
if (pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, &b)) {
|
||||
dev_err(&sis630_dev->dev, "Error: Can't read bios ctl reg\n");
|
||||
retval = -ENODEV;
|
||||
retval = dev_err_probe(&sis630_dev->dev, -ENODEV,
|
||||
"Error: Can't read bios ctl reg\n");
|
||||
goto exit;
|
||||
}
|
||||
/* if ACPI already enabled , do nothing */
|
||||
if (!(b & 0x80) &&
|
||||
pci_write_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, b | 0x80)) {
|
||||
dev_err(&sis630_dev->dev, "Error: Can't enable ACPI\n");
|
||||
retval = -ENODEV;
|
||||
retval = dev_err_probe(&sis630_dev->dev, -ENODEV,
|
||||
"Error: Can't enable ACPI\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Determine the ACPI base address */
|
||||
if (pci_read_config_word(sis630_dev,
|
||||
SIS630_ACPI_BASE_REG, &acpi_base)) {
|
||||
dev_err(&sis630_dev->dev,
|
||||
"Error: Can't determine ACPI base address\n");
|
||||
retval = -ENODEV;
|
||||
retval = dev_err_probe(&sis630_dev->dev, -ENODEV,
|
||||
"Error: Can't determine ACPI base address\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
|
@ -469,11 +468,10 @@ static int sis630_setup(struct pci_dev *sis630_dev)
|
|||
/* Everything is happy, let's grab the memory and set things up. */
|
||||
if (!request_region(smbus_base + SMB_STS, SIS630_SMB_IOREGION,
|
||||
sis630_driver.name)) {
|
||||
dev_err(&sis630_dev->dev,
|
||||
"I/O Region 0x%04x-0x%04x for SMBus already in use.\n",
|
||||
smbus_base + SMB_STS,
|
||||
smbus_base + SMB_STS + SIS630_SMB_IOREGION - 1);
|
||||
retval = -EBUSY;
|
||||
retval = dev_err_probe(&sis630_dev->dev, -EBUSY,
|
||||
"I/O Region 0x%04x-0x%04x for SMBus already in use.\n",
|
||||
smbus_base + SMB_STS,
|
||||
smbus_base + SMB_STS + SIS630_SMB_IOREGION - 1);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
|
@ -511,12 +509,9 @@ static int sis630_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (sis630_setup(dev)) {
|
||||
dev_err(&dev->dev,
|
||||
"SIS630 compatible bus not detected, "
|
||||
"module not inserted.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (sis630_setup(dev))
|
||||
return dev_err_probe(&dev->dev, -ENODEV,
|
||||
"Compatible bus not detected, module not inserted.\n");
|
||||
|
||||
/* set up the sysfs linkage to our parent device */
|
||||
sis630_adapter.dev.parent = &dev->dev;
|
||||
|
|
|
|||
|
|
@ -245,23 +245,19 @@ static int sis96x_probe(struct pci_dev *dev,
|
|||
u16 ww = 0;
|
||||
int retval;
|
||||
|
||||
if (sis96x_smbus_base) {
|
||||
dev_err(&dev->dev, "Only one device supported.\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
if (sis96x_smbus_base)
|
||||
return dev_err_probe(&dev->dev, -EBUSY, "Only one device supported.\n");
|
||||
|
||||
pci_read_config_word(dev, PCI_CLASS_DEVICE, &ww);
|
||||
if (PCI_CLASS_SERIAL_SMBUS != ww) {
|
||||
dev_err(&dev->dev, "Unsupported device class 0x%04x!\n", ww);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (ww != PCI_CLASS_SERIAL_SMBUS)
|
||||
return dev_err_probe(&dev->dev, -ENODEV,
|
||||
"Unsupported device class 0x%04x!\n", ww);
|
||||
|
||||
sis96x_smbus_base = pci_resource_start(dev, SIS96x_BAR);
|
||||
if (!sis96x_smbus_base) {
|
||||
dev_err(&dev->dev, "SiS96x SMBus base address "
|
||||
"not initialized!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!sis96x_smbus_base)
|
||||
return dev_err_probe(&dev->dev, -EINVAL,
|
||||
"SiS96x SMBus base address not initialized!\n");
|
||||
|
||||
dev_info(&dev->dev, "SiS96x SMBus base address: 0x%04x\n",
|
||||
sis96x_smbus_base);
|
||||
|
||||
|
|
@ -272,9 +268,9 @@ static int sis96x_probe(struct pci_dev *dev,
|
|||
/* Everything is happy, let's grab the memory and set things up. */
|
||||
if (!request_region(sis96x_smbus_base, SMB_IOSIZE,
|
||||
sis96x_driver.name)) {
|
||||
dev_err(&dev->dev, "SMBus registers 0x%04x-0x%04x "
|
||||
"already in use!\n", sis96x_smbus_base,
|
||||
sis96x_smbus_base + SMB_IOSIZE - 1);
|
||||
dev_err_probe(&dev->dev, -EINVAL,
|
||||
"SMBus registers 0x%04x-0x%04x already in use!\n",
|
||||
sis96x_smbus_base, sis96x_smbus_base + SMB_IOSIZE - 1);
|
||||
|
||||
sis96x_smbus_base = 0;
|
||||
return -EINVAL;
|
||||
|
|
@ -287,7 +283,7 @@ static int sis96x_probe(struct pci_dev *dev,
|
|||
"SiS96x SMBus adapter at 0x%04x", sis96x_smbus_base);
|
||||
|
||||
if ((retval = i2c_add_adapter(&sis96x_adapter))) {
|
||||
dev_err(&dev->dev, "Couldn't register adapter!\n");
|
||||
dev_err_probe(&dev->dev, retval, "Couldn't register adapter!\n");
|
||||
release_region(sis96x_smbus_base, SMB_IOSIZE);
|
||||
sis96x_smbus_base = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -469,11 +469,10 @@ static int sprd_i2c_clk_init(struct sprd_i2c *i2c_dev)
|
|||
i2c_dev->adap.nr, i2c_dev->src_clk);
|
||||
|
||||
i2c_dev->clk = devm_clk_get(i2c_dev->dev, "enable");
|
||||
if (IS_ERR(i2c_dev->clk)) {
|
||||
dev_err(i2c_dev->dev, "i2c%d can't get the enable clock\n",
|
||||
i2c_dev->adap.nr);
|
||||
return PTR_ERR(i2c_dev->clk);
|
||||
}
|
||||
if (IS_ERR(i2c_dev->clk))
|
||||
return dev_err_probe(i2c_dev->dev, PTR_ERR(i2c_dev->clk),
|
||||
"i2c%d can't get the enable clock\n",
|
||||
i2c_dev->adap.nr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -548,13 +547,13 @@ static int sprd_i2c_probe(struct platform_device *pdev)
|
|||
IRQF_NO_SUSPEND | IRQF_ONESHOT,
|
||||
pdev->name, i2c_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to request irq %d\n", i2c_dev->irq);
|
||||
dev_err_probe(&pdev->dev, ret, "failed to request irq %d\n", i2c_dev->irq);
|
||||
goto err_rpm_put;
|
||||
}
|
||||
|
||||
ret = i2c_add_numbered_adapter(&i2c_dev->adap);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "add adapter failed\n");
|
||||
dev_err_probe(&pdev->dev, ret, "add adapter failed\n");
|
||||
goto err_rpm_put;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -775,17 +775,15 @@ static int st_i2c_of_get_deglitch(struct device_node *np,
|
|||
|
||||
ret = of_property_read_u32(np, "st,i2c-min-scl-pulse-width-us",
|
||||
&i2c_dev->scl_min_width_us);
|
||||
if ((ret == -ENODATA) || (ret == -EOVERFLOW)) {
|
||||
dev_err(i2c_dev->dev, "st,i2c-min-scl-pulse-width-us invalid\n");
|
||||
return ret;
|
||||
}
|
||||
if ((ret == -ENODATA) || (ret == -EOVERFLOW))
|
||||
return dev_err_probe(i2c_dev->dev, ret,
|
||||
"st,i2c-min-scl-pulse-width-us invalid\n");
|
||||
|
||||
ret = of_property_read_u32(np, "st,i2c-min-sda-pulse-width-us",
|
||||
&i2c_dev->sda_min_width_us);
|
||||
if ((ret == -ENODATA) || (ret == -EOVERFLOW)) {
|
||||
dev_err(i2c_dev->dev, "st,i2c-min-sda-pulse-width-us invalid\n");
|
||||
return ret;
|
||||
}
|
||||
if ((ret == -ENODATA) || (ret == -EOVERFLOW))
|
||||
return dev_err_probe(i2c_dev->dev, ret,
|
||||
"st,i2c-min-sda-pulse-width-us invalid\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -808,16 +806,13 @@ static int st_i2c_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(i2c_dev->base);
|
||||
|
||||
i2c_dev->irq = irq_of_parse_and_map(np, 0);
|
||||
if (!i2c_dev->irq) {
|
||||
dev_err(&pdev->dev, "IRQ missing or invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!i2c_dev->irq)
|
||||
return dev_err_probe(&pdev->dev, -EINVAL, "IRQ missing or invalid\n");
|
||||
|
||||
i2c_dev->clk = of_clk_get_by_name(np, "ssc");
|
||||
if (IS_ERR(i2c_dev->clk)) {
|
||||
dev_err(&pdev->dev, "Unable to request clock\n");
|
||||
return PTR_ERR(i2c_dev->clk);
|
||||
}
|
||||
if (IS_ERR(i2c_dev->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(i2c_dev->clk),
|
||||
"Unable to request clock\n");
|
||||
|
||||
i2c_dev->mode = I2C_MODE_STANDARD;
|
||||
ret = of_property_read_u32(np, "clock-frequency", &clk_rate);
|
||||
|
|
@ -829,10 +824,9 @@ static int st_i2c_probe(struct platform_device *pdev)
|
|||
ret = devm_request_threaded_irq(&pdev->dev, i2c_dev->irq,
|
||||
NULL, st_i2c_isr_thread,
|
||||
IRQF_ONESHOT, pdev->name, i2c_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"Failed to request irq %i\n", i2c_dev->irq);
|
||||
|
||||
pinctrl_pm_select_default_state(i2c_dev->dev);
|
||||
/* In case idle state available, select it */
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev,
|
|||
dma_sconfig.direction = DMA_MEM_TO_DEV;
|
||||
ret = dmaengine_slave_config(dma->chan_tx, &dma_sconfig);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "can't configure tx channel\n");
|
||||
dev_err_probe(dev, ret, "can't configure tx channel\n");
|
||||
goto fail_tx;
|
||||
}
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev,
|
|||
dma_sconfig.direction = DMA_DEV_TO_MEM;
|
||||
ret = dmaengine_slave_config(dma->chan_rx, &dma_sconfig);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "can't configure rx channel\n");
|
||||
dev_err_probe(dev, ret, "can't configure rx channel\n");
|
||||
goto fail_rx;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -163,11 +163,9 @@ static int stm32f4_i2c_set_periph_clk_freq(struct stm32f4_i2c_dev *i2c_dev)
|
|||
* to hardware limitation
|
||||
*/
|
||||
if (freq < STM32F4_I2C_MIN_STANDARD_FREQ ||
|
||||
freq > STM32F4_I2C_MAX_FREQ) {
|
||||
dev_err(i2c_dev->dev,
|
||||
"bad parent clk freq for standard mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
freq > STM32F4_I2C_MAX_FREQ)
|
||||
return dev_err_probe(i2c_dev->dev, -EINVAL,
|
||||
"bad parent clk freq for standard mode\n");
|
||||
} else {
|
||||
/*
|
||||
* To be as close as possible to 400 kHz, the parent clk
|
||||
|
|
@ -175,11 +173,9 @@ static int stm32f4_i2c_set_periph_clk_freq(struct stm32f4_i2c_dev *i2c_dev)
|
|||
* maximum value of 46 MHz due to hardware limitation
|
||||
*/
|
||||
if (freq < STM32F4_I2C_MIN_FAST_FREQ ||
|
||||
freq > STM32F4_I2C_MAX_FREQ) {
|
||||
dev_err(i2c_dev->dev,
|
||||
"bad parent clk freq for fast mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
freq > STM32F4_I2C_MAX_FREQ)
|
||||
return dev_err_probe(i2c_dev->dev, -EINVAL,
|
||||
"bad parent clk freq for fast mode\n");
|
||||
}
|
||||
|
||||
cr2 |= STM32F4_I2C_CR2_FREQ(freq);
|
||||
|
|
@ -772,22 +768,19 @@ static int stm32f4_i2c_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(i2c_dev->base);
|
||||
|
||||
irq_event = irq_of_parse_and_map(np, 0);
|
||||
if (!irq_event) {
|
||||
dev_err(&pdev->dev, "IRQ event missing or invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!irq_event)
|
||||
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||
"IRQ event missing or invalid\n");
|
||||
|
||||
irq_error = irq_of_parse_and_map(np, 1);
|
||||
if (!irq_error) {
|
||||
dev_err(&pdev->dev, "IRQ error missing or invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!irq_error)
|
||||
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||
"IRQ error missing or invalid\n");
|
||||
|
||||
i2c_dev->clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
||||
if (IS_ERR(i2c_dev->clk)) {
|
||||
dev_err(&pdev->dev, "Failed to enable clock\n");
|
||||
return PTR_ERR(i2c_dev->clk);
|
||||
}
|
||||
if (IS_ERR(i2c_dev->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(i2c_dev->clk),
|
||||
"Failed to enable clock\n");
|
||||
|
||||
rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
|
||||
if (IS_ERR(rst))
|
||||
|
|
@ -807,19 +800,15 @@ static int stm32f4_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
ret = devm_request_irq(&pdev->dev, irq_event, stm32f4_i2c_isr_event, 0,
|
||||
pdev->name, i2c_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to request irq event %i\n",
|
||||
irq_event);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"Failed to request irq event %i\n", irq_event);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, irq_error, stm32f4_i2c_isr_error, 0,
|
||||
pdev->name, i2c_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to request irq error %i\n",
|
||||
irq_error);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"Failed to request irq error %i\n", irq_error);
|
||||
|
||||
ret = stm32f4_i2c_hw_config(i2c_dev);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -481,28 +481,22 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
|
|||
int ret = 0;
|
||||
|
||||
specs = stm32f7_get_specs(setup->speed_freq);
|
||||
if (specs == ERR_PTR(-EINVAL)) {
|
||||
dev_err(i2c_dev->dev, "speed out of bound {%d}\n",
|
||||
setup->speed_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (specs == ERR_PTR(-EINVAL))
|
||||
return dev_err_probe(i2c_dev->dev, -EINVAL, "speed out of bound {%d}\n",
|
||||
setup->speed_freq);
|
||||
|
||||
if ((setup->rise_time > specs->rise_max) ||
|
||||
(setup->fall_time > specs->fall_max)) {
|
||||
dev_err(i2c_dev->dev,
|
||||
"timings out of bound Rise{%d>%d}/Fall{%d>%d}\n",
|
||||
setup->rise_time, specs->rise_max,
|
||||
setup->fall_time, specs->fall_max);
|
||||
return -EINVAL;
|
||||
}
|
||||
(setup->fall_time > specs->fall_max))
|
||||
return dev_err_probe(i2c_dev->dev, -EINVAL,
|
||||
"timings out of bound Rise{%d>%d}/Fall{%d>%d}\n",
|
||||
setup->rise_time, specs->rise_max,
|
||||
setup->fall_time, specs->fall_max);
|
||||
|
||||
i2c_dev->dnf = DIV_ROUND_CLOSEST(i2c_dev->dnf_dt, i2cclk);
|
||||
if (i2c_dev->dnf > STM32F7_I2C_DNF_MAX) {
|
||||
dev_err(i2c_dev->dev,
|
||||
"DNF out of bound %d/%d\n",
|
||||
i2c_dev->dnf * i2cclk, STM32F7_I2C_DNF_MAX * i2cclk);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (i2c_dev->dnf > STM32F7_I2C_DNF_MAX)
|
||||
return dev_err_probe(i2c_dev->dev, -EINVAL,
|
||||
"DNF out of bound %d/%d\n", i2c_dev->dnf * i2cclk,
|
||||
STM32F7_I2C_DNF_MAX * i2cclk);
|
||||
|
||||
/* Analog and Digital Filters */
|
||||
af_delay_min =
|
||||
|
|
@ -567,8 +561,7 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
|
|||
}
|
||||
|
||||
if (list_empty(&solutions)) {
|
||||
dev_err(i2c_dev->dev, "no Prescaler solution\n");
|
||||
ret = -EPERM;
|
||||
ret = dev_err_probe(i2c_dev->dev, -EPERM, "no Prescaler solution\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
|
@ -624,8 +617,7 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
|
|||
}
|
||||
|
||||
if (!s) {
|
||||
dev_err(i2c_dev->dev, "no solution at all\n");
|
||||
ret = -EPERM;
|
||||
ret = dev_err_probe(i2c_dev->dev, -EPERM, "no solution at all\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
|
@ -674,11 +666,9 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
|
|||
|
||||
i2c_parse_fw_timings(i2c_dev->dev, t, false);
|
||||
|
||||
if (t->bus_freq_hz > I2C_MAX_FAST_MODE_PLUS_FREQ) {
|
||||
dev_err(i2c_dev->dev, "Invalid bus speed (%i>%i)\n",
|
||||
t->bus_freq_hz, I2C_MAX_FAST_MODE_PLUS_FREQ);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (t->bus_freq_hz > I2C_MAX_FAST_MODE_PLUS_FREQ)
|
||||
return dev_err_probe(i2c_dev->dev, -EINVAL, "Invalid bus speed (%i>%i)\n",
|
||||
t->bus_freq_hz, I2C_MAX_FAST_MODE_PLUS_FREQ);
|
||||
|
||||
setup->speed_freq = t->bus_freq_hz;
|
||||
i2c_dev->setup.rise_time = t->scl_rise_ns;
|
||||
|
|
@ -686,10 +676,8 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
|
|||
i2c_dev->dnf_dt = t->digital_filter_width_ns;
|
||||
setup->clock_src = clk_get_rate(i2c_dev->clk);
|
||||
|
||||
if (!setup->clock_src) {
|
||||
dev_err(i2c_dev->dev, "clock rate is 0\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!setup->clock_src)
|
||||
return dev_err_probe(i2c_dev->dev, -EINVAL, "clock rate is 0\n");
|
||||
|
||||
if (!of_property_read_bool(i2c_dev->dev->of_node, "i2c-digital-filter"))
|
||||
i2c_dev->dnf_dt = STM32F7_I2C_DNF_DEFAULT;
|
||||
|
|
@ -701,8 +689,8 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
|
|||
ret = stm32f7_i2c_compute_timing(i2c_dev, setup,
|
||||
&i2c_dev->timing);
|
||||
if (ret) {
|
||||
dev_err(i2c_dev->dev,
|
||||
"failed to compute I2C timings.\n");
|
||||
dev_err_probe(i2c_dev->dev, ret,
|
||||
"failed to compute I2C timings.\n");
|
||||
if (setup->speed_freq <= I2C_MAX_STANDARD_MODE_FREQ)
|
||||
break;
|
||||
setup->speed_freq =
|
||||
|
|
@ -713,10 +701,8 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
|
|||
}
|
||||
} while (ret);
|
||||
|
||||
if (ret) {
|
||||
dev_err(i2c_dev->dev, "Impossible to compute I2C timings.\n");
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(i2c_dev->dev, ret, "Impossible to compute I2C timings.\n");
|
||||
|
||||
dev_dbg(i2c_dev->dev, "I2C Speed(%i), Clk Source(%i)\n",
|
||||
setup->speed_freq, setup->clock_src);
|
||||
|
|
@ -2175,10 +2161,8 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
setup = of_device_get_match_data(&pdev->dev);
|
||||
if (!setup) {
|
||||
dev_err(&pdev->dev, "Can't get device data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!setup)
|
||||
return dev_err_probe(&pdev->dev, -ENODEV, "Can't get device data\n");
|
||||
i2c_dev->setup = *setup;
|
||||
|
||||
i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
|
|
@ -2279,7 +2263,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
ret = dev_pm_set_wake_irq(i2c_dev->dev, irq_event);
|
||||
if (ret) {
|
||||
dev_err(i2c_dev->dev, "Failed to set wake up irq\n");
|
||||
dev_err_probe(i2c_dev->dev, ret, "Failed to set wake up irq\n");
|
||||
goto clr_wakeup_capable;
|
||||
}
|
||||
}
|
||||
|
|
@ -2305,9 +2289,8 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
|||
if (i2c_dev->smbus_mode) {
|
||||
ret = stm32f7_i2c_enable_smbus_host(i2c_dev);
|
||||
if (ret) {
|
||||
dev_err(i2c_dev->dev,
|
||||
"failed to enable SMBus Host-Notify protocol (%d)\n",
|
||||
ret);
|
||||
dev_err_probe(i2c_dev->dev, ret,
|
||||
"failed to enable SMBus Host-Notify protocol\n");
|
||||
goto i2c_adapter_remove;
|
||||
}
|
||||
}
|
||||
|
|
@ -2315,9 +2298,8 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
|||
if (of_property_read_bool(pdev->dev.of_node, "smbus-alert")) {
|
||||
ret = stm32f7_i2c_enable_smbus_alert(i2c_dev);
|
||||
if (ret) {
|
||||
dev_err(i2c_dev->dev,
|
||||
"failed to enable SMBus alert protocol (%d)\n",
|
||||
ret);
|
||||
dev_err_probe(i2c_dev->dev, ret,
|
||||
"failed to enable SMBus alert protocol\n");
|
||||
goto i2c_disable_smbus_host;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -194,22 +194,16 @@ static int p2wi_probe(struct platform_device *pdev)
|
|||
int ret;
|
||||
|
||||
of_property_read_u32(np, "clock-frequency", &clk_freq);
|
||||
if (clk_freq > P2WI_MAX_FREQ) {
|
||||
dev_err(dev,
|
||||
"required clock-frequency (%u Hz) is too high (max = 6MHz)",
|
||||
clk_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (clk_freq > P2WI_MAX_FREQ)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"required clock-frequency (%u Hz) is too high (max = 6MHz)",
|
||||
clk_freq);
|
||||
|
||||
if (clk_freq == 0) {
|
||||
dev_err(dev, "clock-frequency is set to 0 in DT\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (clk_freq == 0)
|
||||
return dev_err_probe(dev, -EINVAL, "clock-frequency is set to 0 in DT\n");
|
||||
|
||||
if (of_get_child_count(np) > 1) {
|
||||
dev_err(dev, "P2WI only supports one target device\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (of_get_child_count(np) > 1)
|
||||
return dev_err_probe(dev, -EINVAL, "P2WI only supports one target device\n");
|
||||
|
||||
p2wi = devm_kzalloc(dev, sizeof(struct p2wi), GFP_KERNEL);
|
||||
if (!p2wi)
|
||||
|
|
@ -226,11 +220,9 @@ static int p2wi_probe(struct platform_device *pdev)
|
|||
childnp = of_get_next_available_child(np, NULL);
|
||||
if (childnp) {
|
||||
ret = of_property_read_u32(childnp, "reg", &target_addr);
|
||||
if (ret) {
|
||||
dev_err(dev, "invalid target address on node %pOF\n",
|
||||
childnp);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"invalid target address on node %pOF\n", childnp);
|
||||
|
||||
p2wi->target_addr = target_addr;
|
||||
}
|
||||
|
|
@ -245,26 +237,20 @@ static int p2wi_probe(struct platform_device *pdev)
|
|||
return irq;
|
||||
|
||||
p2wi->clk = devm_clk_get_enabled(dev, NULL);
|
||||
if (IS_ERR(p2wi->clk)) {
|
||||
ret = PTR_ERR(p2wi->clk);
|
||||
dev_err(dev, "failed to enable clk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(p2wi->clk))
|
||||
return dev_err_probe(dev, PTR_ERR(p2wi->clk),
|
||||
"failed to enable clk\n");
|
||||
|
||||
parent_clk_freq = clk_get_rate(p2wi->clk);
|
||||
|
||||
p2wi->rstc = devm_reset_control_get_exclusive(dev, NULL);
|
||||
if (IS_ERR(p2wi->rstc)) {
|
||||
dev_err(dev, "failed to retrieve reset controller: %pe\n",
|
||||
p2wi->rstc);
|
||||
return PTR_ERR(p2wi->rstc);
|
||||
}
|
||||
if (IS_ERR(p2wi->rstc))
|
||||
return dev_err_probe(dev, PTR_ERR(p2wi->rstc),
|
||||
"failed to retrieve reset controller\n");
|
||||
|
||||
ret = reset_control_deassert(p2wi->rstc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to deassert reset line: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to deassert reset line\n");
|
||||
|
||||
init_completion(&p2wi->complete);
|
||||
p2wi->adapter.dev.parent = dev;
|
||||
|
|
@ -276,8 +262,7 @@ static int p2wi_probe(struct platform_device *pdev)
|
|||
|
||||
ret = devm_request_irq(dev, irq, p2wi_interrupt, 0, pdev->name, p2wi);
|
||||
if (ret) {
|
||||
dev_err(dev, "can't register interrupt handler irq%d: %d\n",
|
||||
irq, ret);
|
||||
dev_err_probe(dev, ret, "can't register interrupt handler irq%d\n", irq);
|
||||
goto err_reset_assert;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ struct tegra_i2c_regs {
|
|||
unsigned int master_reset_cntrl;
|
||||
unsigned int mst_fifo_control;
|
||||
unsigned int mst_fifo_status;
|
||||
unsigned int fairness_arb;
|
||||
unsigned int sw_mutex;
|
||||
};
|
||||
|
||||
|
|
@ -272,6 +273,7 @@ static const struct tegra_i2c_regs tegra264_i2c_regs = {
|
|||
.master_reset_cntrl = 0x0a8,
|
||||
.mst_fifo_control = 0x0b4,
|
||||
.mst_fifo_status = 0x0b8,
|
||||
.fairness_arb = 0x0e8,
|
||||
.sw_mutex = 0x0ec,
|
||||
};
|
||||
|
||||
|
|
@ -300,6 +302,7 @@ static const struct tegra_i2c_regs tegra410_i2c_regs = {
|
|||
.master_reset_cntrl = 0x0ac,
|
||||
.mst_fifo_control = 0x0b8,
|
||||
.mst_fifo_status = 0x0bc,
|
||||
.fairness_arb = 0x0ec,
|
||||
.sw_mutex = 0x0f0,
|
||||
};
|
||||
|
||||
|
|
@ -379,6 +382,7 @@ enum tegra_i2c_variant {
|
|||
* timing settings.
|
||||
* @enable_hs_mode_support: Enable support for high speed (HS) mode transfers.
|
||||
* @has_mutex: Has mutex register for mutual exclusion with other firmwares or VMs.
|
||||
* @has_fairarb_reg: Has fairness arbitration register for SMBUS/MCTP support.
|
||||
* @variant: This represents the I2C controller variant.
|
||||
* @regs: Register offsets for the specific SoC variant.
|
||||
*/
|
||||
|
|
@ -412,6 +416,7 @@ struct tegra_i2c_hw_feature {
|
|||
bool has_interface_timing_reg;
|
||||
bool enable_hs_mode_support;
|
||||
bool has_mutex;
|
||||
bool has_fairarb_reg;
|
||||
enum tegra_i2c_variant variant;
|
||||
const struct tegra_i2c_regs *regs;
|
||||
};
|
||||
|
|
@ -436,6 +441,7 @@ struct tegra_i2c_hw_feature {
|
|||
* @msg_read: indicates that the transfer is a read access
|
||||
* @timings: i2c timings information like bus frequency
|
||||
* @multimaster_mode: indicates that I2C controller is in multi-master mode
|
||||
* @is_mctp: indicates that the I2C controller is used as an MCTP controller
|
||||
* @dma_chan: DMA channel
|
||||
* @dma_phys: handle to DMA resources
|
||||
* @dma_buf: pointer to allocated DMA buffer
|
||||
|
|
@ -476,6 +482,7 @@ struct tegra_i2c_dev {
|
|||
void *dma_buf;
|
||||
|
||||
bool multimaster_mode;
|
||||
bool is_mctp;
|
||||
bool atomic_mode;
|
||||
bool dma_mode;
|
||||
bool msg_read;
|
||||
|
|
@ -709,15 +716,15 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev)
|
|||
goto err_out;
|
||||
}
|
||||
|
||||
i2c_dev->dma_dev = i2c_dev->dma_chan->device->dev;
|
||||
i2c_dev->dma_dev = dmaengine_get_dma_device(i2c_dev->dma_chan);
|
||||
i2c_dev->dma_buf_size = i2c_dev->hw->quirks->max_write_len +
|
||||
I2C_PACKET_HEADER_SIZE;
|
||||
|
||||
dma_buf = dma_alloc_coherent(i2c_dev->dma_dev, i2c_dev->dma_buf_size,
|
||||
&dma_phys, GFP_KERNEL | __GFP_NOWARN);
|
||||
if (!dma_buf) {
|
||||
dev_err(i2c_dev->dev, "failed to allocate DMA buffer\n");
|
||||
err = -ENOMEM;
|
||||
err = dev_err_probe(i2c_dev->dev, -ENOMEM,
|
||||
"failed to allocate DMA buffer\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
|
|
@ -729,8 +736,7 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev)
|
|||
err_out:
|
||||
tegra_i2c_release_dma(i2c_dev);
|
||||
if (err != -EPROBE_DEFER) {
|
||||
dev_err(i2c_dev->dev, "cannot use DMA: %d\n", err);
|
||||
dev_err(i2c_dev->dev, "falling back to PIO\n");
|
||||
dev_err(i2c_dev->dev, "cannot use DMA, falling back to PIO\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -911,6 +917,10 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
|
|||
if (IS_VI(i2c_dev))
|
||||
tegra_i2c_vi_init(i2c_dev);
|
||||
|
||||
/* Disable fairness arbitration if not an MCTP controller */
|
||||
if (i2c_dev->hw->has_fairarb_reg && !i2c_dev->is_mctp)
|
||||
i2c_writel(i2c_dev, 0, i2c_dev->hw->regs->fairness_arb);
|
||||
|
||||
if (i2c_dev->hw->enable_hs_mode_support)
|
||||
max_bus_freq_hz = I2C_MAX_HIGH_SPEED_MODE_FREQ;
|
||||
else
|
||||
|
|
@ -1778,6 +1788,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
|
|||
.has_interface_timing_reg = false,
|
||||
.enable_hs_mode_support = false,
|
||||
.has_mutex = false,
|
||||
.has_fairarb_reg = false,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra20_i2c_regs,
|
||||
};
|
||||
|
|
@ -1811,6 +1822,7 @@ static const struct tegra_i2c_hw_feature tegra20_dvc_i2c_hw = {
|
|||
.has_interface_timing_reg = false,
|
||||
.enable_hs_mode_support = false,
|
||||
.has_mutex = false,
|
||||
.has_fairarb_reg = false,
|
||||
.variant = TEGRA_I2C_VARIANT_DVC,
|
||||
.regs = &tegra20_dvc_i2c_regs,
|
||||
};
|
||||
|
|
@ -1844,6 +1856,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
|
|||
.has_interface_timing_reg = false,
|
||||
.enable_hs_mode_support = false,
|
||||
.has_mutex = false,
|
||||
.has_fairarb_reg = false,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra20_i2c_regs,
|
||||
};
|
||||
|
|
@ -1876,6 +1889,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
|
|||
.has_interface_timing_reg = false,
|
||||
.enable_hs_mode_support = false,
|
||||
.has_mutex = false,
|
||||
.has_fairarb_reg = false,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra20_i2c_regs,
|
||||
};
|
||||
|
|
@ -1908,6 +1922,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
|
|||
.has_interface_timing_reg = true,
|
||||
.enable_hs_mode_support = false,
|
||||
.has_mutex = false,
|
||||
.has_fairarb_reg = false,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra20_i2c_regs,
|
||||
};
|
||||
|
|
@ -1940,6 +1955,7 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
|
|||
.has_interface_timing_reg = true,
|
||||
.enable_hs_mode_support = false,
|
||||
.has_mutex = false,
|
||||
.has_fairarb_reg = false,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra20_i2c_regs,
|
||||
};
|
||||
|
|
@ -1973,6 +1989,7 @@ static const struct tegra_i2c_hw_feature tegra210_vi_i2c_hw = {
|
|||
.has_interface_timing_reg = true,
|
||||
.enable_hs_mode_support = false,
|
||||
.has_mutex = false,
|
||||
.has_fairarb_reg = false,
|
||||
.variant = TEGRA_I2C_VARIANT_VI,
|
||||
.regs = &tegra210_vi_i2c_regs,
|
||||
};
|
||||
|
|
@ -2006,6 +2023,7 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
|
|||
.has_interface_timing_reg = true,
|
||||
.enable_hs_mode_support = false,
|
||||
.has_mutex = false,
|
||||
.has_fairarb_reg = false,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra20_i2c_regs,
|
||||
};
|
||||
|
|
@ -2040,6 +2058,7 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
|
|||
.has_interface_timing_reg = true,
|
||||
.enable_hs_mode_support = true,
|
||||
.has_mutex = false,
|
||||
.has_fairarb_reg = false,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra20_i2c_regs,
|
||||
};
|
||||
|
|
@ -2074,6 +2093,7 @@ static const struct tegra_i2c_hw_feature tegra256_i2c_hw = {
|
|||
.has_interface_timing_reg = true,
|
||||
.enable_hs_mode_support = true,
|
||||
.has_mutex = true,
|
||||
.has_fairarb_reg = true,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra264_i2c_regs,
|
||||
};
|
||||
|
|
@ -2108,6 +2128,7 @@ static const struct tegra_i2c_hw_feature tegra264_i2c_hw = {
|
|||
.has_interface_timing_reg = true,
|
||||
.enable_hs_mode_support = true,
|
||||
.has_mutex = true,
|
||||
.has_fairarb_reg = true,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra264_i2c_regs,
|
||||
};
|
||||
|
|
@ -2142,6 +2163,7 @@ static const struct tegra_i2c_hw_feature tegra410_i2c_hw = {
|
|||
.has_interface_timing_reg = true,
|
||||
.enable_hs_mode_support = true,
|
||||
.has_mutex = true,
|
||||
.has_fairarb_reg = true,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra410_i2c_regs,
|
||||
};
|
||||
|
|
@ -2174,6 +2196,7 @@ static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev)
|
|||
|
||||
multi_mode = device_property_read_bool(i2c_dev->dev, "multi-master");
|
||||
i2c_dev->multimaster_mode = multi_mode;
|
||||
i2c_dev->is_mctp = device_property_present(i2c_dev->dev, "mctp-controller");
|
||||
}
|
||||
|
||||
static int tegra_i2c_init_clocks(struct tegra_i2c_dev *i2c_dev)
|
||||
|
|
@ -2207,7 +2230,7 @@ static int tegra_i2c_init_clocks(struct tegra_i2c_dev *i2c_dev)
|
|||
|
||||
err = clk_enable(i2c_dev->div_clk);
|
||||
if (err) {
|
||||
dev_err(i2c_dev->dev, "failed to enable div-clk: %d\n", err);
|
||||
dev_err_probe(i2c_dev->dev, err, "failed to enable div-clk\n");
|
||||
goto unprepare_clocks;
|
||||
}
|
||||
|
||||
|
|
@ -2233,7 +2256,7 @@ static int tegra_i2c_init_hardware(struct tegra_i2c_dev *i2c_dev)
|
|||
|
||||
ret = pm_runtime_get_sync(i2c_dev->dev);
|
||||
if (ret < 0)
|
||||
dev_err(i2c_dev->dev, "runtime resume failed: %d\n", ret);
|
||||
dev_err_probe(i2c_dev->dev, ret, "runtime resume failed\n");
|
||||
else
|
||||
ret = tegra_i2c_init(i2c_dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -254,9 +254,8 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface,
|
|||
dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
|
||||
|
||||
if (usb_write(&dev->adapter, CMD_SET_DELAY, delay, 0, NULL, 0) != 0) {
|
||||
dev_err(&dev->adapter.dev,
|
||||
"failure setting delay to %dus\n", delay);
|
||||
retval = -EIO;
|
||||
retval = dev_err_probe(&dev->adapter.dev, -EIO,
|
||||
"failure setting delay to %dus\n", delay);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,8 +84,11 @@ static int i2c_acpi_resource_count(struct acpi_resource *ares, void *data)
|
|||
* i2c_acpi_client_count - Count the number of I2cSerialBus resources
|
||||
* @adev: ACPI device
|
||||
*
|
||||
* Returns the number of I2cSerialBus resources in the ACPI-device's
|
||||
* Return:
|
||||
* The number of I2cSerialBus resources in the ACPI-device's
|
||||
* resource-list; or a negative error code.
|
||||
*
|
||||
* Specifically returns -ENOENT when no resources found.
|
||||
*/
|
||||
int i2c_acpi_client_count(struct acpi_device *adev)
|
||||
{
|
||||
|
|
@ -97,7 +100,7 @@ int i2c_acpi_client_count(struct acpi_device *adev)
|
|||
return ret;
|
||||
|
||||
acpi_dev_free_resource_list(&r);
|
||||
return count;
|
||||
return count ?: -ENOENT;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_acpi_client_count);
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@
|
|||
static DEFINE_MUTEX(core_lock);
|
||||
static DEFINE_IDR(i2c_adapter_idr);
|
||||
|
||||
static void i2c_deregister_clients(struct i2c_adapter *adap);
|
||||
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);
|
||||
|
||||
static DEFINE_STATIC_KEY_FALSE(i2c_trace_msg_key);
|
||||
|
|
@ -1106,8 +1107,8 @@ EXPORT_SYMBOL(i2c_find_device_by_fwnode);
|
|||
|
||||
|
||||
static const struct i2c_device_id dummy_id[] = {
|
||||
{ "dummy", },
|
||||
{ "smbus_host_notify", },
|
||||
{ .name = "dummy" },
|
||||
{ .name = "smbus_host_notify" },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
@ -1515,23 +1516,48 @@ int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_handle_smbus_host_notify);
|
||||
|
||||
static int i2c_allocate_adapter_id(struct i2c_adapter *adap)
|
||||
{
|
||||
int id, start, end;
|
||||
|
||||
if (adap->nr == -1) {
|
||||
start = __i2c_first_dynamic_bus_num;
|
||||
end = 0;
|
||||
} else {
|
||||
start = adap->nr;
|
||||
end = adap->nr + 1;
|
||||
}
|
||||
|
||||
mutex_lock(&core_lock);
|
||||
id = idr_alloc(&i2c_adapter_idr, NULL, start, end, GFP_KERNEL);
|
||||
mutex_unlock(&core_lock);
|
||||
if (id < 0) {
|
||||
if (adap->nr != -1 && id == -ENOSPC)
|
||||
id = -EBUSY;
|
||||
pr_err("adapter '%s': failed to allocate id: %d\n", adap->name, id);
|
||||
return id;
|
||||
}
|
||||
|
||||
adap->nr = id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_register_adapter(struct i2c_adapter *adap)
|
||||
{
|
||||
int res = -EINVAL;
|
||||
int res;
|
||||
|
||||
/* Can't register until after driver model init */
|
||||
if (WARN_ON(!is_registered)) {
|
||||
res = -EAGAIN;
|
||||
goto out_list;
|
||||
}
|
||||
if (WARN_ON(!is_registered))
|
||||
return -EAGAIN;
|
||||
|
||||
/* Sanity checks */
|
||||
if (WARN(!adap->name[0], "i2c adapter has no name"))
|
||||
goto out_list;
|
||||
return -EINVAL;
|
||||
|
||||
if (!adap->algo) {
|
||||
pr_err("adapter '%s': no algo supplied!\n", adap->name);
|
||||
goto out_list;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!adap->lock_ops)
|
||||
|
|
@ -1552,14 +1578,25 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
|
|||
if (res) {
|
||||
pr_err("adapter '%s': can't create Host Notify IRQs (%d)\n",
|
||||
adap->name, res);
|
||||
goto out_list;
|
||||
return res;
|
||||
}
|
||||
|
||||
dev_set_name(&adap->dev, "i2c-%d", adap->nr);
|
||||
res = i2c_allocate_adapter_id(adap);
|
||||
if (res)
|
||||
goto err_remove_irq_domain;
|
||||
|
||||
res = dev_set_name(&adap->dev, "i2c-%d", adap->nr);
|
||||
if (res)
|
||||
goto err_free_id;
|
||||
|
||||
adap->dev.bus = &i2c_bus_type;
|
||||
adap->dev.type = &i2c_adapter_type;
|
||||
device_initialize(&adap->dev);
|
||||
|
||||
res = i2c_init_recovery(adap);
|
||||
if (res == -EPROBE_DEFER)
|
||||
goto err_put_adap;
|
||||
|
||||
/*
|
||||
* This adapter can be used as a parent immediately after device_add(),
|
||||
* setup runtime-pm (especially ignore-children) before hand.
|
||||
|
|
@ -1569,22 +1606,21 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
|
|||
pm_suspend_ignore_children(&adap->dev, true);
|
||||
pm_runtime_enable(&adap->dev);
|
||||
|
||||
adap->debugfs = debugfs_create_dir(dev_name(&adap->dev), i2c_debugfs_root);
|
||||
|
||||
mutex_lock(&core_lock);
|
||||
idr_replace(&i2c_adapter_idr, adap, adap->nr);
|
||||
mutex_unlock(&core_lock);
|
||||
|
||||
res = device_add(&adap->dev);
|
||||
if (res) {
|
||||
pr_err("adapter '%s': can't register device (%d)\n", adap->name, res);
|
||||
put_device(&adap->dev);
|
||||
goto out_list;
|
||||
goto err_replace_id;
|
||||
}
|
||||
|
||||
adap->debugfs = debugfs_create_dir(dev_name(&adap->dev), i2c_debugfs_root);
|
||||
|
||||
res = i2c_setup_smbus_alert(adap);
|
||||
if (res)
|
||||
goto out_reg;
|
||||
|
||||
res = i2c_init_recovery(adap);
|
||||
if (res == -EPROBE_DEFER)
|
||||
goto out_reg;
|
||||
goto err_deregister_clients;
|
||||
|
||||
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
|
||||
|
||||
|
|
@ -1603,38 +1639,29 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
|
|||
|
||||
return 0;
|
||||
|
||||
out_reg:
|
||||
err_deregister_clients:
|
||||
i2c_deregister_clients(adap);
|
||||
device_del(&adap->dev);
|
||||
err_replace_id:
|
||||
mutex_lock(&core_lock);
|
||||
idr_replace(&i2c_adapter_idr, NULL, adap->nr);
|
||||
mutex_unlock(&core_lock);
|
||||
debugfs_remove_recursive(adap->debugfs);
|
||||
pm_runtime_disable(&adap->dev);
|
||||
err_put_adap:
|
||||
init_completion(&adap->dev_released);
|
||||
device_unregister(&adap->dev);
|
||||
put_device(&adap->dev);
|
||||
wait_for_completion(&adap->dev_released);
|
||||
out_list:
|
||||
err_free_id:
|
||||
mutex_lock(&core_lock);
|
||||
idr_remove(&i2c_adapter_idr, adap->nr);
|
||||
mutex_unlock(&core_lock);
|
||||
err_remove_irq_domain:
|
||||
i2c_host_notify_irq_teardown(adap);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* __i2c_add_numbered_adapter - i2c_add_numbered_adapter where nr is never -1
|
||||
* @adap: the adapter to register (with adap->nr initialized)
|
||||
* Context: can sleep
|
||||
*
|
||||
* See i2c_add_numbered_adapter() for details.
|
||||
*/
|
||||
static int __i2c_add_numbered_adapter(struct i2c_adapter *adap)
|
||||
{
|
||||
int id;
|
||||
|
||||
mutex_lock(&core_lock);
|
||||
id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1, GFP_KERNEL);
|
||||
mutex_unlock(&core_lock);
|
||||
if (WARN(id < 0, "couldn't get idr"))
|
||||
return id == -ENOSPC ? -EBUSY : id;
|
||||
|
||||
return i2c_register_adapter(adap);
|
||||
}
|
||||
|
||||
/**
|
||||
* i2c_add_adapter - declare i2c adapter, use dynamic bus number
|
||||
* @adapter: the adapter to add
|
||||
|
|
@ -1655,17 +1682,8 @@ int i2c_add_adapter(struct i2c_adapter *adapter)
|
|||
int id;
|
||||
|
||||
id = of_alias_get_id(dev->of_node, "i2c");
|
||||
if (id >= 0) {
|
||||
adapter->nr = id;
|
||||
return __i2c_add_numbered_adapter(adapter);
|
||||
}
|
||||
|
||||
mutex_lock(&core_lock);
|
||||
id = idr_alloc(&i2c_adapter_idr, adapter,
|
||||
__i2c_first_dynamic_bus_num, 0, GFP_KERNEL);
|
||||
mutex_unlock(&core_lock);
|
||||
if (WARN(id < 0, "couldn't get idr"))
|
||||
return id;
|
||||
if (id < 0)
|
||||
id = -1;
|
||||
|
||||
adapter->nr = id;
|
||||
|
||||
|
|
@ -1701,7 +1719,7 @@ int i2c_add_numbered_adapter(struct i2c_adapter *adap)
|
|||
if (adap->nr == -1) /* -1 means dynamically assign bus id */
|
||||
return i2c_add_adapter(adap);
|
||||
|
||||
return __i2c_add_numbered_adapter(adap);
|
||||
return i2c_register_adapter(adap);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
|
||||
|
||||
|
|
@ -1743,29 +1761,10 @@ static int __process_removed_adapter(struct device_driver *d, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* i2c_del_adapter - unregister I2C adapter
|
||||
* @adap: the adapter being unregistered
|
||||
* Context: can sleep
|
||||
*
|
||||
* This unregisters an I2C adapter which was previously registered
|
||||
* by @i2c_add_adapter or @i2c_add_numbered_adapter.
|
||||
*/
|
||||
void i2c_del_adapter(struct i2c_adapter *adap)
|
||||
static void i2c_deregister_clients(struct i2c_adapter *adap)
|
||||
{
|
||||
struct i2c_adapter *found;
|
||||
struct i2c_client *client, *next;
|
||||
|
||||
/* First make sure that this adapter was ever added */
|
||||
mutex_lock(&core_lock);
|
||||
found = idr_find(&i2c_adapter_idr, adap->nr);
|
||||
mutex_unlock(&core_lock);
|
||||
if (found != adap) {
|
||||
pr_debug("attempting to delete unregistered adapter [%s]\n", adap->name);
|
||||
return;
|
||||
}
|
||||
|
||||
i2c_acpi_remove_space_handler(adap);
|
||||
/* Tell drivers about this removal */
|
||||
mutex_lock(&core_lock);
|
||||
bus_for_each_drv(&i2c_bus_type, NULL, adap,
|
||||
|
|
@ -1791,6 +1790,34 @@ void i2c_del_adapter(struct i2c_adapter *adap)
|
|||
* them up properly, so we give them a chance to do that first. */
|
||||
device_for_each_child(&adap->dev, NULL, __unregister_client);
|
||||
device_for_each_child(&adap->dev, NULL, __unregister_dummy);
|
||||
}
|
||||
|
||||
/**
|
||||
* i2c_del_adapter - unregister I2C adapter
|
||||
* @adap: the adapter being unregistered
|
||||
* Context: can sleep
|
||||
*
|
||||
* This unregisters an I2C adapter which was previously registered
|
||||
* by @i2c_add_adapter or @i2c_add_numbered_adapter.
|
||||
*/
|
||||
void i2c_del_adapter(struct i2c_adapter *adap)
|
||||
{
|
||||
struct i2c_adapter *found;
|
||||
|
||||
/* First make sure that this adapter was ever added */
|
||||
mutex_lock(&core_lock);
|
||||
found = idr_find(&i2c_adapter_idr, adap->nr);
|
||||
if (found == adap)
|
||||
idr_replace(&i2c_adapter_idr, NULL, adap->nr);
|
||||
mutex_unlock(&core_lock);
|
||||
if (found != adap) {
|
||||
pr_debug("attempting to delete unregistered adapter [%s]\n", adap->name);
|
||||
return;
|
||||
}
|
||||
|
||||
i2c_acpi_remove_space_handler(adap);
|
||||
|
||||
i2c_deregister_clients(adap);
|
||||
|
||||
/* device name is gone after device_unregister */
|
||||
dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
|
||||
|
|
|
|||
|
|
@ -191,14 +191,14 @@ static void i2c_slave_eeprom_remove(struct i2c_client *client)
|
|||
}
|
||||
|
||||
static const struct i2c_device_id i2c_slave_eeprom_id[] = {
|
||||
{ "slave-24c02", I2C_SLAVE_DEVICE_MAGIC(2048 / 8, 0) },
|
||||
{ "slave-24c02ro", I2C_SLAVE_DEVICE_MAGIC(2048 / 8, I2C_SLAVE_FLAG_RO) },
|
||||
{ "slave-24c32", I2C_SLAVE_DEVICE_MAGIC(32768 / 8, I2C_SLAVE_FLAG_ADDR16) },
|
||||
{ "slave-24c32ro", I2C_SLAVE_DEVICE_MAGIC(32768 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
|
||||
{ "slave-24c64", I2C_SLAVE_DEVICE_MAGIC(65536 / 8, I2C_SLAVE_FLAG_ADDR16) },
|
||||
{ "slave-24c64ro", I2C_SLAVE_DEVICE_MAGIC(65536 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
|
||||
{ "slave-24c512", I2C_SLAVE_DEVICE_MAGIC(524288 / 8, I2C_SLAVE_FLAG_ADDR16) },
|
||||
{ "slave-24c512ro", I2C_SLAVE_DEVICE_MAGIC(524288 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
|
||||
{ .name = "slave-24c02", .driver_data = I2C_SLAVE_DEVICE_MAGIC(2048 / 8, 0) },
|
||||
{ .name = "slave-24c02ro", .driver_data = I2C_SLAVE_DEVICE_MAGIC(2048 / 8, I2C_SLAVE_FLAG_RO) },
|
||||
{ .name = "slave-24c32", .driver_data = I2C_SLAVE_DEVICE_MAGIC(32768 / 8, I2C_SLAVE_FLAG_ADDR16) },
|
||||
{ .name = "slave-24c32ro", .driver_data = I2C_SLAVE_DEVICE_MAGIC(32768 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
|
||||
{ .name = "slave-24c64", .driver_data = I2C_SLAVE_DEVICE_MAGIC(65536 / 8, I2C_SLAVE_FLAG_ADDR16) },
|
||||
{ .name = "slave-24c64ro", .driver_data = I2C_SLAVE_DEVICE_MAGIC(65536 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
|
||||
{ .name = "slave-24c512", .driver_data = I2C_SLAVE_DEVICE_MAGIC(524288 / 8, I2C_SLAVE_FLAG_ADDR16) },
|
||||
{ .name = "slave-24c512ro", .driver_data = I2C_SLAVE_DEVICE_MAGIC(524288 / 8, I2C_SLAVE_FLAG_ADDR16 | I2C_SLAVE_FLAG_RO) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, i2c_slave_eeprom_id);
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ static void i2c_slave_testunit_remove(struct i2c_client *client)
|
|||
}
|
||||
|
||||
static const struct i2c_device_id i2c_slave_testunit_id[] = {
|
||||
{ "slave-testunit" },
|
||||
{ .name = "slave-testunit" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, i2c_slave_testunit_id);
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ static void smbalert_remove(struct i2c_client *ara)
|
|||
}
|
||||
|
||||
static const struct i2c_device_id smbalert_ids[] = {
|
||||
{ "smbus_alert" },
|
||||
{ .name = "smbus_alert" },
|
||||
{ /* LIST END */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, smbalert_ids);
|
||||
|
|
|
|||
|
|
@ -191,8 +191,8 @@ static int ltc4306_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
|
|||
}
|
||||
|
||||
static const struct i2c_device_id ltc4306_id[] = {
|
||||
{ "ltc4305", ltc_4305 },
|
||||
{ "ltc4306", ltc_4306 },
|
||||
{ .name = "ltc4305", .driver_data = ltc_4305 },
|
||||
{ .name = "ltc4306", .driver_data = ltc_4306 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ltc4306_id);
|
||||
|
|
|
|||
|
|
@ -74,8 +74,8 @@ struct pca9541 {
|
|||
};
|
||||
|
||||
static const struct i2c_device_id pca9541_id[] = {
|
||||
{ "pca9541" },
|
||||
{}
|
||||
{ .name = "pca9541" },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, pca9541_id);
|
||||
|
|
|
|||
|
|
@ -250,24 +250,24 @@ static const struct chip_desc chips[] = {
|
|||
};
|
||||
|
||||
static const struct i2c_device_id pca954x_id[] = {
|
||||
{ "max7356", max_7356 },
|
||||
{ "max7357", max_7357 },
|
||||
{ "max7358", max_7358 },
|
||||
{ "max7367", max_7367 },
|
||||
{ "max7368", max_7368 },
|
||||
{ "max7369", max_7369 },
|
||||
{ "pca9540", pca_9540 },
|
||||
{ "pca9542", pca_9542 },
|
||||
{ "pca9543", pca_9543 },
|
||||
{ "pca9544", pca_9544 },
|
||||
{ "pca9545", pca_9545 },
|
||||
{ "pca9546", pca_9546 },
|
||||
{ "pca9547", pca_9547 },
|
||||
{ "pca9548", pca_9548 },
|
||||
{ "pca9846", pca_9846 },
|
||||
{ "pca9847", pca_9847 },
|
||||
{ "pca9848", pca_9848 },
|
||||
{ "pca9849", pca_9849 },
|
||||
{ .name = "max7356", .driver_data = max_7356 },
|
||||
{ .name = "max7357", .driver_data = max_7357 },
|
||||
{ .name = "max7358", .driver_data = max_7358 },
|
||||
{ .name = "max7367", .driver_data = max_7367 },
|
||||
{ .name = "max7368", .driver_data = max_7368 },
|
||||
{ .name = "max7369", .driver_data = max_7369 },
|
||||
{ .name = "pca9540", .driver_data = pca_9540 },
|
||||
{ .name = "pca9542", .driver_data = pca_9542 },
|
||||
{ .name = "pca9543", .driver_data = pca_9543 },
|
||||
{ .name = "pca9544", .driver_data = pca_9544 },
|
||||
{ .name = "pca9545", .driver_data = pca_9545 },
|
||||
{ .name = "pca9546", .driver_data = pca_9546 },
|
||||
{ .name = "pca9547", .driver_data = pca_9547 },
|
||||
{ .name = "pca9548", .driver_data = pca_9548 },
|
||||
{ .name = "pca9846", .driver_data = pca_9846 },
|
||||
{ .name = "pca9847", .driver_data = pca_9847 },
|
||||
{ .name = "pca9848", .driver_data = pca_9848 },
|
||||
{ .name = "pca9849", .driver_data = pca_9849 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pca954x_id);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_data/i2c-mux-reg.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -75,37 +74,34 @@ static int i2c_mux_reg_deselect(struct i2c_mux_core *muxc, u32 chan)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int i2c_mux_reg_probe_dt(struct regmux *mux,
|
||||
struct platform_device *pdev)
|
||||
static int i2c_mux_reg_probe_fw(struct regmux *mux, struct device *dev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device_node *adapter_np, *child;
|
||||
struct fwnode_handle *fwnode, *child;
|
||||
struct i2c_adapter *adapter;
|
||||
struct resource res;
|
||||
unsigned *values;
|
||||
int i = 0;
|
||||
int ret, i = 0;
|
||||
|
||||
if (!np)
|
||||
if (!dev_fwnode(dev))
|
||||
return -ENODEV;
|
||||
|
||||
adapter_np = of_parse_phandle(np, "i2c-parent", 0);
|
||||
if (!adapter_np) {
|
||||
dev_err(&pdev->dev, "Cannot parse i2c-parent\n");
|
||||
fwnode = fwnode_find_reference(dev_fwnode(dev), "i2c-parent", 0);
|
||||
if (IS_ERR(fwnode)) {
|
||||
dev_err(dev, "missing 'i2c-parent' property\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
adapter = of_find_i2c_adapter_by_node(adapter_np);
|
||||
of_node_put(adapter_np);
|
||||
|
||||
adapter = i2c_find_adapter_by_fwnode(fwnode);
|
||||
fwnode_handle_put(fwnode);
|
||||
if (!adapter)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
mux->data.parent = i2c_adapter_id(adapter);
|
||||
put_device(&adapter->dev);
|
||||
|
||||
mux->data.n_values = of_get_child_count(np);
|
||||
if (of_property_read_bool(np, "little-endian")) {
|
||||
mux->data.n_values = device_get_child_node_count(dev);
|
||||
if (device_property_read_bool(dev, "little-endian")) {
|
||||
mux->data.little_endian = true;
|
||||
} else if (of_property_read_bool(np, "big-endian")) {
|
||||
} else if (device_property_read_bool(dev, "big-endian")) {
|
||||
mux->data.little_endian = false;
|
||||
} else {
|
||||
#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : \
|
||||
|
|
@ -118,40 +114,35 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
|
|||
#error Endianness not defined?
|
||||
#endif
|
||||
}
|
||||
mux->data.write_only = of_property_read_bool(np, "write-only");
|
||||
mux->data.write_only = device_property_read_bool(dev, "write-only");
|
||||
|
||||
values = devm_kcalloc(&pdev->dev,
|
||||
mux->data.n_values, sizeof(*mux->data.values),
|
||||
values = devm_kcalloc(dev, mux->data.n_values, sizeof(*mux->data.values),
|
||||
GFP_KERNEL);
|
||||
if (!values)
|
||||
return -ENOMEM;
|
||||
|
||||
for_each_child_of_node(np, child) {
|
||||
of_property_read_u32(child, "reg", values + i);
|
||||
device_for_each_child_node(dev, child) {
|
||||
if (is_acpi_device_node(child)) {
|
||||
ret = acpi_get_local_address(ACPI_HANDLE_FWNODE(child),
|
||||
&values[i]);
|
||||
if (ret) {
|
||||
fwnode_handle_put(child);
|
||||
return dev_err_probe(dev, ret,
|
||||
"Cannot get address\n");
|
||||
}
|
||||
} else {
|
||||
fwnode_property_read_u32(child, "reg", &values[i]);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
mux->data.values = values;
|
||||
|
||||
if (!of_property_read_u32(np, "idle-state", &mux->data.idle))
|
||||
if (!device_property_read_u32(dev, "idle-state", &mux->data.idle))
|
||||
mux->data.idle_in_use = true;
|
||||
|
||||
/* map address from "reg" if exists */
|
||||
if (of_address_to_resource(np, 0, &res) == 0) {
|
||||
mux->data.reg_size = resource_size(&res);
|
||||
mux->data.reg = devm_ioremap_resource(&pdev->dev, &res);
|
||||
if (IS_ERR(mux->data.reg))
|
||||
return PTR_ERR(mux->data.reg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int i2c_mux_reg_probe_dt(struct regmux *mux,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int i2c_mux_reg_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
|
@ -169,34 +160,29 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
|
|||
memcpy(&mux->data, dev_get_platdata(&pdev->dev),
|
||||
sizeof(mux->data));
|
||||
} else {
|
||||
ret = i2c_mux_reg_probe_dt(mux, pdev);
|
||||
ret = i2c_mux_reg_probe_fw(mux, &pdev->dev);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"Error parsing device tree");
|
||||
"Error parsing firmware description\n");
|
||||
}
|
||||
|
||||
parent = i2c_get_adapter(mux->data.parent);
|
||||
if (!parent)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
if (!mux->data.reg) {
|
||||
dev_info(&pdev->dev,
|
||||
"Register not set, using platform resource\n");
|
||||
mux->data.reg = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(mux->data.reg)) {
|
||||
ret = PTR_ERR(mux->data.reg);
|
||||
goto err_put_parent;
|
||||
}
|
||||
if (IS_ERR(mux->data.reg))
|
||||
return PTR_ERR(mux->data.reg);
|
||||
mux->data.reg_size = resource_size(res);
|
||||
}
|
||||
|
||||
if (mux->data.reg_size != 4 && mux->data.reg_size != 2 &&
|
||||
mux->data.reg_size != 1) {
|
||||
dev_err(&pdev->dev, "Invalid register size\n");
|
||||
ret = -EINVAL;
|
||||
goto err_put_parent;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
parent = i2c_get_adapter(mux->data.parent);
|
||||
if (!parent)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, 0, 0,
|
||||
i2c_mux_reg_select, NULL);
|
||||
if (!muxc) {
|
||||
|
|
|
|||
|
|
@ -215,37 +215,37 @@ AT24_CHIP_DATA(at24_data_24c2048, 2097152 / 8, AT24_FLAG_ADDR16);
|
|||
AT24_CHIP_DATA(at24_data_INT3499, 8192 / 8, 0);
|
||||
|
||||
static const struct i2c_device_id at24_ids[] = {
|
||||
{ "24c00", (kernel_ulong_t)&at24_data_24c00 },
|
||||
{ "24c01", (kernel_ulong_t)&at24_data_24c01 },
|
||||
{ "24cs01", (kernel_ulong_t)&at24_data_24cs01 },
|
||||
{ "24c02", (kernel_ulong_t)&at24_data_24c02 },
|
||||
{ "24cs02", (kernel_ulong_t)&at24_data_24cs02 },
|
||||
{ "24mac402", (kernel_ulong_t)&at24_data_24mac402 },
|
||||
{ "24mac602", (kernel_ulong_t)&at24_data_24mac602 },
|
||||
{ "24aa025e48", (kernel_ulong_t)&at24_data_24aa025e48 },
|
||||
{ "24aa025e64", (kernel_ulong_t)&at24_data_24aa025e64 },
|
||||
{ "spd", (kernel_ulong_t)&at24_data_spd },
|
||||
{ "24c02-vaio", (kernel_ulong_t)&at24_data_24c02_vaio },
|
||||
{ "24c04", (kernel_ulong_t)&at24_data_24c04 },
|
||||
{ "24cs04", (kernel_ulong_t)&at24_data_24cs04 },
|
||||
{ "24c08", (kernel_ulong_t)&at24_data_24c08 },
|
||||
{ "24cs08", (kernel_ulong_t)&at24_data_24cs08 },
|
||||
{ "24c16", (kernel_ulong_t)&at24_data_24c16 },
|
||||
{ "24cs16", (kernel_ulong_t)&at24_data_24cs16 },
|
||||
{ "24c32", (kernel_ulong_t)&at24_data_24c32 },
|
||||
{ "24c32d-wl", (kernel_ulong_t)&at24_data_24c32d_wlp },
|
||||
{ "24cs32", (kernel_ulong_t)&at24_data_24cs32 },
|
||||
{ "24c64", (kernel_ulong_t)&at24_data_24c64 },
|
||||
{ "24c64-wl", (kernel_ulong_t)&at24_data_24c64d_wlp },
|
||||
{ "24cs64", (kernel_ulong_t)&at24_data_24cs64 },
|
||||
{ "24c128", (kernel_ulong_t)&at24_data_24c128 },
|
||||
{ "24c256", (kernel_ulong_t)&at24_data_24c256 },
|
||||
{ "24256e-wl", (kernel_ulong_t)&at24_data_24256e_wlp },
|
||||
{ "24c512", (kernel_ulong_t)&at24_data_24c512 },
|
||||
{ "24c1024", (kernel_ulong_t)&at24_data_24c1024 },
|
||||
{ "24c1025", (kernel_ulong_t)&at24_data_24c1025 },
|
||||
{ "24c2048", (kernel_ulong_t)&at24_data_24c2048 },
|
||||
{ "at24", 0 },
|
||||
{ .name = "24c00", .driver_data = (kernel_ulong_t)&at24_data_24c00 },
|
||||
{ .name = "24c01", .driver_data = (kernel_ulong_t)&at24_data_24c01 },
|
||||
{ .name = "24cs01", .driver_data = (kernel_ulong_t)&at24_data_24cs01 },
|
||||
{ .name = "24c02", .driver_data = (kernel_ulong_t)&at24_data_24c02 },
|
||||
{ .name = "24cs02", .driver_data = (kernel_ulong_t)&at24_data_24cs02 },
|
||||
{ .name = "24mac402", .driver_data = (kernel_ulong_t)&at24_data_24mac402 },
|
||||
{ .name = "24mac602", .driver_data = (kernel_ulong_t)&at24_data_24mac602 },
|
||||
{ .name = "24aa025e48", .driver_data = (kernel_ulong_t)&at24_data_24aa025e48 },
|
||||
{ .name = "24aa025e64", .driver_data = (kernel_ulong_t)&at24_data_24aa025e64 },
|
||||
{ .name = "spd", .driver_data = (kernel_ulong_t)&at24_data_spd },
|
||||
{ .name = "24c02-vaio", .driver_data = (kernel_ulong_t)&at24_data_24c02_vaio },
|
||||
{ .name = "24c04", .driver_data = (kernel_ulong_t)&at24_data_24c04 },
|
||||
{ .name = "24cs04", .driver_data = (kernel_ulong_t)&at24_data_24cs04 },
|
||||
{ .name = "24c08", .driver_data = (kernel_ulong_t)&at24_data_24c08 },
|
||||
{ .name = "24cs08", .driver_data = (kernel_ulong_t)&at24_data_24cs08 },
|
||||
{ .name = "24c16", .driver_data = (kernel_ulong_t)&at24_data_24c16 },
|
||||
{ .name = "24cs16", .driver_data = (kernel_ulong_t)&at24_data_24cs16 },
|
||||
{ .name = "24c32", .driver_data = (kernel_ulong_t)&at24_data_24c32 },
|
||||
{ .name = "24c32d-wl", .driver_data = (kernel_ulong_t)&at24_data_24c32d_wlp },
|
||||
{ .name = "24cs32", .driver_data = (kernel_ulong_t)&at24_data_24cs32 },
|
||||
{ .name = "24c64", .driver_data = (kernel_ulong_t)&at24_data_24c64 },
|
||||
{ .name = "24c64-wl", .driver_data = (kernel_ulong_t)&at24_data_24c64d_wlp },
|
||||
{ .name = "24cs64", .driver_data = (kernel_ulong_t)&at24_data_24cs64 },
|
||||
{ .name = "24c128", .driver_data = (kernel_ulong_t)&at24_data_24c128 },
|
||||
{ .name = "24c256", .driver_data = (kernel_ulong_t)&at24_data_24c256 },
|
||||
{ .name = "24256e-wl", .driver_data = (kernel_ulong_t)&at24_data_24256e_wlp },
|
||||
{ .name = "24c512", .driver_data = (kernel_ulong_t)&at24_data_24c512 },
|
||||
{ .name = "24c1024", .driver_data = (kernel_ulong_t)&at24_data_24c1024 },
|
||||
{ .name = "24c1025", .driver_data = (kernel_ulong_t)&at24_data_24c1025 },
|
||||
{ .name = "24c2048", .driver_data = (kernel_ulong_t)&at24_data_24c2048 },
|
||||
{ .name = "at24", .driver_data = 0 },
|
||||
{ /* END OF LIST */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, at24_ids);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user