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:
Linus Torvalds 2026-06-16 07:43:29 +05:30
commit 2779759c09
40 changed files with 1173 additions and 500 deletions

View File

@ -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>;
};
};

View File

@ -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

View File

@ -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:

View 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>;
};
};

View File

@ -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

View File

@ -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
{ }

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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");

View File

@ -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)

View File

@ -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;

View File

@ -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),
},

View File

@ -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,

View File

@ -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);

View File

@ -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);

View 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");

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -74,8 +74,8 @@ struct pca9541 {
};
static const struct i2c_device_id pca9541_id[] = {
{ "pca9541" },
{}
{ .name = "pca9541" },
{ }
};
MODULE_DEVICE_TABLE(i2c, pca9541_id);

View File

@ -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);

View File

@ -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) {

View File

@ -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);