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

Pull i2c updates from Wolfram Sang:

 - new drivers for Silicon Labs CP2615 and the HiSilicon I2C unit

 - bigger refactoring for the MPC driver

 - support for full software nodes - no need to work around with only
   properties anymore

 - we now have 'devm_i2c_add_adapter', too

 - sub-system wide fixes for the RPM refcounting problem which often
   caused a leak when an error was encountered during probe

 - the rest is usual driver updates and improvements

* 'i2c/for-5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (77 commits)
  i2c: mediatek: Use scl_int_delay_ns to compensate clock-stretching
  i2c: mediatek: Fix wrong dma sync flag
  i2c: mediatek: Fix send master code at more than 1MHz
  i2c: sh7760: fix IRQ error path
  i2c: i801: Add support for Intel Alder Lake PCH-M
  i2c: core: Fix spacing error by checkpatch
  i2c: s3c2410: simplify getting of_device_id match data
  i2c: nomadik: Fix space errors
  i2c: iop3xx: Fix coding style issues
  i2c: amd8111: Fix coding style issues
  i2c: mpc: Drop duplicate message from devm_platform_ioremap_resource()
  i2c: mpc: Use device_get_match_data() helper
  i2c: mpc: Remove CONFIG_PM_SLEEP ifdeffery
  i2c: mpc: Use devm_clk_get_optional()
  i2c: mpc: Update license and copyright
  i2c: mpc: Interrupt driven transfer
  i2c: sh7760: add IRQ check
  i2c: rcar: add IRQ check
  i2c: mlxbf: add IRQ check
  i2c: jz4780: add IRQ check
  ...
This commit is contained in:
Linus Torvalds
2021-04-30 13:01:02 -07:00
56 changed files with 2084 additions and 773 deletions

View File

@@ -1,62 +0,0 @@
* I2C
Required properties :
- reg : Offset and length of the register set for the device
- compatible : should be "fsl,CHIP-i2c" where CHIP is the name of a
compatible processor, e.g. mpc8313, mpc8543, mpc8544, mpc5121,
mpc5200 or mpc5200b. For the mpc5121, an additional node
"fsl,mpc5121-i2c-ctrl" is required as shown in the example below.
Recommended properties :
- interrupts : <a b> where a is the interrupt number and b is a
field that represents an encoding of the sense and level
information for the interrupt. This should be encoded based on
the information in section 2) depending on the type of interrupt
controller you have.
- fsl,preserve-clocking : boolean; if defined, the clock settings
from the bootloader are preserved (not touched).
- clock-frequency : desired I2C bus clock frequency in Hz.
- fsl,timeout : I2C bus timeout in microseconds.
Examples :
/* MPC5121 based board */
i2c@1740 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,mpc5121-i2c", "fsl-i2c";
reg = <0x1740 0x20>;
interrupts = <11 0x8>;
interrupt-parent = <&ipic>;
clock-frequency = <100000>;
};
i2ccontrol@1760 {
compatible = "fsl,mpc5121-i2c-ctrl";
reg = <0x1760 0x8>;
};
/* MPC5200B based board */
i2c@3d00 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c";
reg = <0x3d00 0x40>;
interrupts = <2 15 0>;
interrupt-parent = <&mpc5200_pic>;
fsl,preserve-clocking;
};
/* MPC8544 base board */
i2c@3100 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,mpc8544-i2c", "fsl-i2c";
reg = <0x3100 0x100>;
interrupts = <43 2>;
interrupt-parent = <&mpic>;
clock-frequency = <400000>;
fsl,timeout = <10000>;
};

View File

@@ -0,0 +1,91 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/i2c-mpc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: I2C-Bus adapter for MPC824x/83xx/85xx/86xx/512x/52xx SoCs
maintainers:
- Chris Packham <chris.packham@alliedtelesis.co.nz>
allOf:
- $ref: /schemas/i2c/i2c-controller.yaml#
properties:
compatible:
oneOf:
- items:
- enum:
- mpc5200-i2c
- fsl,mpc5200-i2c
- fsl,mpc5121-i2c
- fsl,mpc8313-i2c
- fsl,mpc8543-i2c
- fsl,mpc8544-i2c
- const: fsl-i2c
- items:
- const: fsl,mpc5200b-i2c
- const: fsl,mpc5200-i2c
- const: fsl-i2c
reg:
maxItems: 1
interrupts:
maxItems: 1
fsl,preserve-clocking:
$ref: /schemas/types.yaml#/definitions/flag
description: |
if defined, the clock settings from the bootloader are
preserved (not touched)
fsl,timeout:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
I2C bus timeout in microseconds
required:
- compatible
- reg
- interrupts
unevaluatedProperties: false
examples:
- |
/* MPC5121 based board */
i2c@1740 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,mpc5121-i2c", "fsl-i2c";
reg = <0x1740 0x20>;
interrupts = <11 0x8>;
interrupt-parent = <&ipic>;
clock-frequency = <100000>;
};
/* MPC5200B based board */
i2c@3d00 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,mpc5200b-i2c", "fsl,mpc5200-i2c", "fsl-i2c";
reg = <0x3d00 0x40>;
interrupts = <2 15 0>;
interrupt-parent = <&mpc5200_pic>;
fsl,preserve-clocking;
};
/* MPC8544 base board */
i2c@3100 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,mpc8544-i2c", "fsl-i2c";
reg = <0x3100 0x100>;
interrupts = <43 2>;
interrupt-parent = <&mpic>;
clock-frequency = <400000>;
fsl,timeout = <10000>;
};
...

View File

@@ -4662,6 +4662,11 @@ F: drivers/counter/
F: include/linux/counter.h
F: include/linux/counter_enum.h
CP2615 I2C DRIVER
M: Bence Csókás <bence98@sch.bme.hu>
S: Maintained
F: drivers/i2c/busses/i2c-cp2615.c
CPMAC ETHERNET DRIVER
M: Florian Fainelli <f.fainelli@gmail.com>
L: netdev@vger.kernel.org
@@ -7235,6 +7240,13 @@ S: Maintained
F: Documentation/devicetree/bindings/i2c/i2c-imx-lpi2c.yaml
F: drivers/i2c/busses/i2c-imx-lpi2c.c
FREESCALE MPC I2C DRIVER
M: Chris Packham <chris.packham@alliedtelesis.co.nz>
L: linux-i2c@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/i2c/i2c-mpc.yaml
F: drivers/i2c/busses/i2c-mpc.c
FREESCALE QORIQ DPAA ETHERNET DRIVER
M: Madalin Bucur <madalin.bucur@nxp.com>
L: netdev@vger.kernel.org
@@ -8157,6 +8169,13 @@ F: drivers/crypto/hisilicon/hpre/hpre.h
F: drivers/crypto/hisilicon/hpre/hpre_crypto.c
F: drivers/crypto/hisilicon/hpre/hpre_main.c
HISILICON I2C CONTROLLER DRIVER
M: Yicong Yang <yangyicong@hisilicon.com>
L: linux-i2c@vger.kernel.org
S: Maintained
W: https://www.hisilicon.com
F: drivers/i2c/busses/i2c-hisi.c
HISILICON LPC BUS DRIVER
M: john.garry@huawei.com
S: Maintained

View File

@@ -454,6 +454,10 @@ static const struct property_entry da830_evm_i2c_eeprom_properties[] = {
{ }
};
static const struct software_node da830_evm_i2c_eeprom_node = {
.properties = da830_evm_i2c_eeprom_properties,
};
static int __init da830_evm_ui_expander_setup(struct i2c_client *client,
int gpio, unsigned ngpio, void *context)
{
@@ -485,7 +489,7 @@ static struct pcf857x_platform_data __initdata da830_evm_ui_expander_info = {
static struct i2c_board_info __initdata da830_evm_i2c_devices[] = {
{
I2C_BOARD_INFO("24c256", 0x50),
.properties = da830_evm_i2c_eeprom_properties,
.swnode = &da830_evm_i2c_eeprom_node,
},
{
I2C_BOARD_INFO("tlv320aic3x", 0x18),

View File

@@ -232,10 +232,14 @@ static const struct property_entry eeprom_properties[] = {
{ }
};
static const struct software_node eeprom_node = {
.properties = eeprom_properties,
};
static struct i2c_board_info i2c_info[] = {
{
I2C_BOARD_INFO("24c256", 0x50),
.properties = eeprom_properties,
.swnode = &eeprom_node,
},
{
I2C_BOARD_INFO("tlv320aic3x", 0x18),

View File

@@ -541,6 +541,10 @@ static const struct property_entry eeprom_properties[] = {
{ }
};
static const struct software_node eeprom_node = {
.properties = eeprom_properties,
};
/*
* MSP430 supports RTC, card detection, input from IR remote, and
* a bit more. It triggers interrupts on GPIO(7) from pressing
@@ -647,7 +651,7 @@ static struct i2c_board_info __initdata i2c_info[] = {
},
{
I2C_BOARD_INFO("24c256", 0x50),
.properties = eeprom_properties,
.swnode = &eeprom_node,
},
{
I2C_BOARD_INFO("tlv320aic33", 0x1b),

View File

@@ -362,6 +362,10 @@ static const struct property_entry eeprom_properties[] = {
PROPERTY_ENTRY_U32("pagesize", 64),
{ }
};
static const struct software_node eeprom_node = {
.properties = eeprom_properties,
};
#endif
static u8 dm646x_iis_serializer_direction[] = {
@@ -430,7 +434,7 @@ static void evm_init_cpld(void)
static struct i2c_board_info __initdata i2c_info[] = {
{
I2C_BOARD_INFO("24c256", 0x50),
.properties = eeprom_properties,
.swnode = &eeprom_node,
},
{
I2C_BOARD_INFO("pcf8574a", 0x38),

View File

@@ -197,6 +197,10 @@ static const struct property_entry mityomapl138_fd_chip_properties[] = {
{ }
};
static const struct software_node mityomapl138_fd_chip_node = {
.properties = mityomapl138_fd_chip_properties,
};
static struct davinci_i2c_platform_data mityomap_i2c_0_pdata = {
.bus_freq = 100, /* kHz */
.bus_delay = 0, /* usec */
@@ -323,7 +327,7 @@ static struct i2c_board_info __initdata mityomap_tps65023_info[] = {
},
{
I2C_BOARD_INFO("24c02", 0x50),
.properties = mityomapl138_fd_chip_properties,
.swnode = &mityomapl138_fd_chip_node,
},
};

View File

@@ -84,10 +84,14 @@ static const struct property_entry eeprom_properties[] = {
{ }
};
static const struct software_node eeprom_node = {
.properties = eeprom_properties,
};
static struct i2c_board_info __initdata i2c_info[] = {
{
I2C_BOARD_INFO("24c64", 0x50),
.properties = eeprom_properties,
.swnode = &eeprom_node,
},
/* Other I2C devices:
* MSP430, addr 0x23 (not used)

View File

@@ -332,11 +332,15 @@ static const struct property_entry mistral_at24_properties[] = {
{ }
};
static const struct software_node mistral_at24_node = {
.properties = mistral_at24_properties,
};
static struct i2c_board_info __initdata mistral_i2c_board_info[] = {
{
/* NOTE: powered from LCD supply */
I2C_BOARD_INFO("24c04", 0x50),
.properties = mistral_at24_properties,
.swnode = &mistral_at24_node,
},
/* TODO when driver support is ready:
* - optionally ov9640 camera sensor at 0x30

View File

@@ -794,6 +794,10 @@ static const struct property_entry pca9500_eeprom_properties[] = {
{ }
};
static const struct software_node pca9500_eeprom_node = {
.properties = pca9500_eeprom_properties,
};
/**
* stargate2_reset_bluetooth() reset the bluecore to ensure consistent state
**/
@@ -929,7 +933,7 @@ static struct i2c_board_info __initdata stargate2_i2c_board_info[] = {
}, {
.type = "24c02",
.addr = 0x57,
.properties = pca9500_eeprom_properties,
.swnode = &pca9500_eeprom_node,
}, {
.type = "max1238",
.addr = 0x35,

View File

@@ -542,10 +542,14 @@ static const struct property_entry mini2440_at24_properties[] = {
{ }
};
static const struct software_node mini2440_at24_node = {
.properties = mini2440_at24_properties,
};
static struct i2c_board_info mini2440_i2c_devs[] __initdata = {
{
I2C_BOARD_INFO("24c08", 0x50),
.properties = mini2440_at24_properties,
.swnode = &mini2440_at24_node,
},
};

View File

@@ -645,6 +645,16 @@ config I2C_HIGHLANDER
This driver can also be built as a module. If so, the module
will be called i2c-highlander.
config I2C_HISI
tristate "HiSilicon I2C controller"
depends on ARM64 || COMPILE_TEST
help
Say Y here if you want to have Hisilicon I2C controller support
available on the Kunpeng Server.
This driver can also be built as a module. If so, the module
will be called i2c-hisi.
config I2C_IBM_IIC
tristate "IBM PPC 4xx on-chip I2C interface"
depends on 4xx
@@ -1199,6 +1209,16 @@ config I2C_DLN2
This driver can also be built as a module. If so, the module
will be called i2c-dln2.
config I2C_CP2615
tristate "Silicon Labs CP2615 USB sound card and I2C adapter"
depends on USB
help
If you say yes to this option, support will be included for Silicon
Labs CP2615's I2C interface.
This driver can also be built as a module. If so, the module
will be called i2c-cp2615.
config I2C_PARPORT
tristate "Parallel port adapter"
depends on PARPORT

View File

@@ -63,6 +63,7 @@ obj-$(CONFIG_I2C_EMEV2) += i2c-emev2.o
obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o
obj-$(CONFIG_I2C_HISI) += i2c-hisi.o
obj-$(CONFIG_I2C_HIX5HD2) += i2c-hix5hd2.o
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
obj-$(CONFIG_I2C_IMG) += i2c-img-scb.o
@@ -123,6 +124,7 @@ obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o
# External I2C/SMBus adapter drivers
obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
obj-$(CONFIG_I2C_DLN2) += i2c-dln2.o
obj-$(CONFIG_I2C_CP2615) += i2c-cp2615.o
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
obj-$(CONFIG_I2C_ROBOTFUZZ_OSIF) += i2c-robotfuzz-osif.o
obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o

View File

@@ -186,9 +186,9 @@ static int amd_ec_write(struct amd_smbus *smbus, unsigned char address,
#define AMD_SMB_PRTCL_PEC 0x80
static s32 amd8111_access(struct i2c_adapter * adap, u16 addr,
static s32 amd8111_access(struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write, u8 command, int size,
union i2c_smbus_data * data)
union i2c_smbus_data *data)
{
struct amd_smbus *smbus = adap->algo_data;
unsigned char protocol, len, pec, temp[2];
@@ -199,130 +199,130 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr,
pec = (flags & I2C_CLIENT_PEC) ? AMD_SMB_PRTCL_PEC : 0;
switch (size) {
case I2C_SMBUS_QUICK:
protocol |= AMD_SMB_PRTCL_QUICK;
read_write = I2C_SMBUS_WRITE;
break;
case I2C_SMBUS_QUICK:
protocol |= AMD_SMB_PRTCL_QUICK;
read_write = I2C_SMBUS_WRITE;
break;
case I2C_SMBUS_BYTE:
if (read_write == I2C_SMBUS_WRITE) {
status = amd_ec_write(smbus, AMD_SMB_CMD,
command);
if (status)
return status;
}
protocol |= AMD_SMB_PRTCL_BYTE;
break;
case I2C_SMBUS_BYTE_DATA:
status = amd_ec_write(smbus, AMD_SMB_CMD, command);
case I2C_SMBUS_BYTE:
if (read_write == I2C_SMBUS_WRITE) {
status = amd_ec_write(smbus, AMD_SMB_CMD,
command);
if (status)
return status;
if (read_write == I2C_SMBUS_WRITE) {
status = amd_ec_write(smbus, AMD_SMB_DATA,
data->byte);
if (status)
return status;
}
protocol |= AMD_SMB_PRTCL_BYTE_DATA;
break;
}
protocol |= AMD_SMB_PRTCL_BYTE;
break;
case I2C_SMBUS_WORD_DATA:
status = amd_ec_write(smbus, AMD_SMB_CMD, command);
if (status)
return status;
if (read_write == I2C_SMBUS_WRITE) {
status = amd_ec_write(smbus, AMD_SMB_DATA,
data->word & 0xff);
if (status)
return status;
status = amd_ec_write(smbus, AMD_SMB_DATA + 1,
data->word >> 8);
if (status)
return status;
}
protocol |= AMD_SMB_PRTCL_WORD_DATA | pec;
break;
case I2C_SMBUS_BLOCK_DATA:
status = amd_ec_write(smbus, AMD_SMB_CMD, command);
if (status)
return status;
if (read_write == I2C_SMBUS_WRITE) {
len = min_t(u8, data->block[0],
I2C_SMBUS_BLOCK_MAX);
status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
if (status)
return status;
for (i = 0; i < len; i++) {
status =
amd_ec_write(smbus, AMD_SMB_DATA + i,
data->block[i + 1]);
if (status)
return status;
}
}
protocol |= AMD_SMB_PRTCL_BLOCK_DATA | pec;
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
len = min_t(u8, data->block[0],
I2C_SMBUS_BLOCK_MAX);
status = amd_ec_write(smbus, AMD_SMB_CMD, command);
if (status)
return status;
status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
if (status)
return status;
if (read_write == I2C_SMBUS_WRITE)
for (i = 0; i < len; i++) {
status =
amd_ec_write(smbus, AMD_SMB_DATA + i,
data->block[i + 1]);
if (status)
return status;
}
protocol |= AMD_SMB_PRTCL_I2C_BLOCK_DATA;
break;
case I2C_SMBUS_PROC_CALL:
status = amd_ec_write(smbus, AMD_SMB_CMD, command);
if (status)
return status;
case I2C_SMBUS_BYTE_DATA:
status = amd_ec_write(smbus, AMD_SMB_CMD, command);
if (status)
return status;
if (read_write == I2C_SMBUS_WRITE) {
status = amd_ec_write(smbus, AMD_SMB_DATA,
data->word & 0xff);
data->byte);
if (status)
return status;
}
protocol |= AMD_SMB_PRTCL_BYTE_DATA;
break;
case I2C_SMBUS_WORD_DATA:
status = amd_ec_write(smbus, AMD_SMB_CMD, command);
if (status)
return status;
if (read_write == I2C_SMBUS_WRITE) {
status = amd_ec_write(smbus, AMD_SMB_DATA,
data->word & 0xff);
if (status)
return status;
status = amd_ec_write(smbus, AMD_SMB_DATA + 1,
data->word >> 8);
data->word >> 8);
if (status)
return status;
protocol = AMD_SMB_PRTCL_PROC_CALL | pec;
read_write = I2C_SMBUS_READ;
break;
}
protocol |= AMD_SMB_PRTCL_WORD_DATA | pec;
break;
case I2C_SMBUS_BLOCK_PROC_CALL:
case I2C_SMBUS_BLOCK_DATA:
status = amd_ec_write(smbus, AMD_SMB_CMD, command);
if (status)
return status;
if (read_write == I2C_SMBUS_WRITE) {
len = min_t(u8, data->block[0],
I2C_SMBUS_BLOCK_MAX - 1);
status = amd_ec_write(smbus, AMD_SMB_CMD, command);
if (status)
return status;
I2C_SMBUS_BLOCK_MAX);
status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
if (status)
return status;
for (i = 0; i < len; i++) {
status = amd_ec_write(smbus, AMD_SMB_DATA + i,
data->block[i + 1]);
status =
amd_ec_write(smbus, AMD_SMB_DATA + i,
data->block[i + 1]);
if (status)
return status;
}
protocol = AMD_SMB_PRTCL_BLOCK_PROC_CALL | pec;
read_write = I2C_SMBUS_READ;
break;
}
protocol |= AMD_SMB_PRTCL_BLOCK_DATA | pec;
break;
default:
dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
return -EOPNOTSUPP;
case I2C_SMBUS_I2C_BLOCK_DATA:
len = min_t(u8, data->block[0],
I2C_SMBUS_BLOCK_MAX);
status = amd_ec_write(smbus, AMD_SMB_CMD, command);
if (status)
return status;
status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
if (status)
return status;
if (read_write == I2C_SMBUS_WRITE)
for (i = 0; i < len; i++) {
status =
amd_ec_write(smbus, AMD_SMB_DATA + i,
data->block[i + 1]);
if (status)
return status;
}
protocol |= AMD_SMB_PRTCL_I2C_BLOCK_DATA;
break;
case I2C_SMBUS_PROC_CALL:
status = amd_ec_write(smbus, AMD_SMB_CMD, command);
if (status)
return status;
status = amd_ec_write(smbus, AMD_SMB_DATA,
data->word & 0xff);
if (status)
return status;
status = amd_ec_write(smbus, AMD_SMB_DATA + 1,
data->word >> 8);
if (status)
return status;
protocol = AMD_SMB_PRTCL_PROC_CALL | pec;
read_write = I2C_SMBUS_READ;
break;
case I2C_SMBUS_BLOCK_PROC_CALL:
len = min_t(u8, data->block[0],
I2C_SMBUS_BLOCK_MAX - 1);
status = amd_ec_write(smbus, AMD_SMB_CMD, command);
if (status)
return status;
status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
if (status)
return status;
for (i = 0; i < len; i++) {
status = amd_ec_write(smbus, AMD_SMB_DATA + i,
data->block[i + 1]);
if (status)
return status;
}
protocol = AMD_SMB_PRTCL_BLOCK_PROC_CALL | pec;
read_write = I2C_SMBUS_READ;
break;
default:
dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
return -EOPNOTSUPP;
}
status = amd_ec_write(smbus, AMD_SMB_ADDR, addr << 1);
@@ -357,40 +357,40 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr,
return 0;
switch (size) {
case I2C_SMBUS_BYTE:
case I2C_SMBUS_BYTE_DATA:
status = amd_ec_read(smbus, AMD_SMB_DATA, &data->byte);
if (status)
return status;
break;
case I2C_SMBUS_BYTE:
case I2C_SMBUS_BYTE_DATA:
status = amd_ec_read(smbus, AMD_SMB_DATA, &data->byte);
if (status)
return status;
break;
case I2C_SMBUS_WORD_DATA:
case I2C_SMBUS_PROC_CALL:
status = amd_ec_read(smbus, AMD_SMB_DATA, temp + 0);
if (status)
return status;
status = amd_ec_read(smbus, AMD_SMB_DATA + 1, temp + 1);
if (status)
return status;
data->word = (temp[1] << 8) | temp[0];
break;
case I2C_SMBUS_WORD_DATA:
case I2C_SMBUS_PROC_CALL:
status = amd_ec_read(smbus, AMD_SMB_DATA, temp + 0);
if (status)
return status;
status = amd_ec_read(smbus, AMD_SMB_DATA + 1, temp + 1);
if (status)
return status;
data->word = (temp[1] << 8) | temp[0];
break;
case I2C_SMBUS_BLOCK_DATA:
case I2C_SMBUS_BLOCK_PROC_CALL:
status = amd_ec_read(smbus, AMD_SMB_BCNT, &len);
case I2C_SMBUS_BLOCK_DATA:
case I2C_SMBUS_BLOCK_PROC_CALL:
status = amd_ec_read(smbus, AMD_SMB_BCNT, &len);
if (status)
return status;
len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
fallthrough;
case I2C_SMBUS_I2C_BLOCK_DATA:
for (i = 0; i < len; i++) {
status = amd_ec_read(smbus, AMD_SMB_DATA + i,
data->block + i + 1);
if (status)
return status;
len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
fallthrough;
case I2C_SMBUS_I2C_BLOCK_DATA:
for (i = 0; i < len; i++) {
status = amd_ec_read(smbus, AMD_SMB_DATA + i,
data->block + i + 1);
if (status)
return status;
}
data->block[0] = len;
break;
}
data->block[0] = len;
break;
}
return 0;

View File

@@ -22,7 +22,6 @@
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/version.h>
#define N_DATA_REGS 8

View File

@@ -789,7 +789,7 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
bool change_role = false;
#endif
ret = pm_runtime_get_sync(id->dev);
ret = pm_runtime_resume_and_get(id->dev);
if (ret < 0)
return ret;
@@ -911,7 +911,7 @@ static int cdns_reg_slave(struct i2c_client *slave)
if (slave->flags & I2C_CLIENT_TEN)
return -EAFNOSUPPORT;
ret = pm_runtime_get_sync(id->dev);
ret = pm_runtime_resume_and_get(id->dev);
if (ret < 0)
return ret;
@@ -1200,7 +1200,10 @@ static int cdns_i2c_probe(struct platform_device *pdev)
if (IS_ERR(id->membase))
return PTR_ERR(id->membase);
id->irq = platform_get_irq(pdev, 0);
ret = platform_get_irq(pdev, 0);
if (ret < 0)
return ret;
id->irq = ret;
id->adap.owner = THIS_MODULE;
id->adap.dev.of_node = pdev->dev.of_node;

View File

@@ -280,6 +280,10 @@ static const struct property_entry bq24190_props[] = {
{ }
};
static const struct software_node bq24190_node = {
.properties = bq24190_props,
};
static struct regulator_consumer_supply fusb302_consumer = {
.supply = "vbus",
/* Must match fusb302 dev_name in intel_cht_int33fe.c */
@@ -308,7 +312,7 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
.type = "bq24190",
.addr = 0x6b,
.dev_name = "bq24190",
.properties = bq24190_props,
.swnode = &bq24190_node,
.platform_data = &bq24190_pdata,
};
int ret, reg, irq;

View File

@@ -0,0 +1,330 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* i2c support for Silicon Labs' CP2615 Digital Audio Bridge
*
* (c) 2021, Bence Csókás <bence98@sch.bme.hu>
*/
#include <linux/errno.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/usb.h>
/** CP2615 I/O Protocol implementation */
#define CP2615_VID 0x10c4
#define CP2615_PID 0xeac1
#define IOP_EP_IN 0x82
#define IOP_EP_OUT 0x02
#define IOP_IFN 1
#define IOP_ALTSETTING 2
#define MAX_IOP_SIZE 64
#define MAX_IOP_PAYLOAD_SIZE (MAX_IOP_SIZE - 6)
#define MAX_I2C_SIZE (MAX_IOP_PAYLOAD_SIZE - 4)
enum cp2615_iop_msg_type {
iop_GetAccessoryInfo = 0xD100,
iop_AccessoryInfo = 0xA100,
iop_GetPortConfiguration = 0xD203,
iop_PortConfiguration = 0xA203,
iop_DoI2cTransfer = 0xD400,
iop_I2cTransferResult = 0xA400,
iop_GetSerialState = 0xD501,
iop_SerialState = 0xA501
};
struct __packed cp2615_iop_msg {
__be16 preamble, length, msg;
u8 data[MAX_IOP_PAYLOAD_SIZE];
};
#define PART_ID_A01 0x1400
#define PART_ID_A02 0x1500
struct __packed cp2615_iop_accessory_info {
__be16 part_id, option_id, proto_ver;
};
struct __packed cp2615_i2c_transfer {
u8 tag, i2caddr, read_len, write_len;
u8 data[MAX_I2C_SIZE];
};
/* Possible values for struct cp2615_i2c_transfer_result.status */
enum cp2615_i2c_status {
/* Writing to the internal EEPROM failed, because it is locked */
CP2615_CFG_LOCKED = -6,
/* read_len or write_len out of range */
CP2615_INVALID_PARAM = -4,
/* I2C slave did not ACK in time */
CP2615_TIMEOUT,
/* I2C bus busy */
CP2615_BUS_BUSY,
/* I2C bus error (ie. device NAK'd the request) */
CP2615_BUS_ERROR,
CP2615_SUCCESS
};
struct __packed cp2615_i2c_transfer_result {
u8 tag, i2caddr;
s8 status;
u8 read_len;
u8 data[MAX_I2C_SIZE];
};
static int cp2615_init_iop_msg(struct cp2615_iop_msg *ret, enum cp2615_iop_msg_type msg,
const void *data, size_t data_len)
{
if (data_len > MAX_IOP_PAYLOAD_SIZE)
return -EFBIG;
if (!ret)
return -EINVAL;
ret->preamble = 0x2A2A;
ret->length = htons(data_len + 6);
ret->msg = htons(msg);
if (data && data_len)
memcpy(&ret->data, data, data_len);
return 0;
}
static int cp2615_init_i2c_msg(struct cp2615_iop_msg *ret, const struct cp2615_i2c_transfer *data)
{
return cp2615_init_iop_msg(ret, iop_DoI2cTransfer, data, 4 + data->write_len);
}
/* Translates status codes to Linux errno's */
static int cp2615_check_status(enum cp2615_i2c_status status)
{
switch (status) {
case CP2615_SUCCESS:
return 0;
case CP2615_BUS_ERROR:
return -ENXIO;
case CP2615_BUS_BUSY:
return -EAGAIN;
case CP2615_TIMEOUT:
return -ETIMEDOUT;
case CP2615_INVALID_PARAM:
return -EINVAL;
case CP2615_CFG_LOCKED:
return -EPERM;
}
/* Unknown error code */
return -EPROTO;
}
/** Driver code */
static int
cp2615_i2c_send(struct usb_interface *usbif, struct cp2615_i2c_transfer *i2c_w)
{
struct cp2615_iop_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL);
struct usb_device *usbdev = interface_to_usbdev(usbif);
int res = cp2615_init_i2c_msg(msg, i2c_w);
if (!res)
res = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, IOP_EP_OUT),
msg, ntohs(msg->length), NULL, 0);
kfree(msg);
return res;
}
static int
cp2615_i2c_recv(struct usb_interface *usbif, unsigned char tag, void *buf)
{
struct cp2615_iop_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL);
struct cp2615_i2c_transfer_result *i2c_r = (struct cp2615_i2c_transfer_result *)&msg->data;
struct usb_device *usbdev = interface_to_usbdev(usbif);
int res = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, IOP_EP_IN),
msg, sizeof(struct cp2615_iop_msg), NULL, 0);
if (res < 0) {
kfree(msg);
return res;
}
if (msg->msg != htons(iop_I2cTransferResult) || i2c_r->tag != tag) {
kfree(msg);
return -EIO;
}
res = cp2615_check_status(i2c_r->status);
if (!res)
memcpy(buf, &i2c_r->data, i2c_r->read_len);
kfree(msg);
return res;
}
/* Checks if the IOP is functional by querying the part's ID */
static int cp2615_check_iop(struct usb_interface *usbif)
{
struct cp2615_iop_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL);
struct cp2615_iop_accessory_info *info = (struct cp2615_iop_accessory_info *)&msg->data;
struct usb_device *usbdev = interface_to_usbdev(usbif);
int res = cp2615_init_iop_msg(msg, iop_GetAccessoryInfo, NULL, 0);
if (res)
goto out;
res = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, IOP_EP_OUT),
msg, ntohs(msg->length), NULL, 0);
if (res)
goto out;
res = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, IOP_EP_IN),
msg, sizeof(struct cp2615_iop_msg), NULL, 0);
if (res)
goto out;
if (msg->msg != htons(iop_AccessoryInfo)) {
res = -EIO;
goto out;
}
switch (ntohs(info->part_id)) {
case PART_ID_A01:
dev_dbg(&usbif->dev, "Found A01 part. (WARNING: errata exists!)\n");
break;
case PART_ID_A02:
dev_dbg(&usbif->dev, "Found good A02 part.\n");
break;
default:
dev_warn(&usbif->dev, "Unknown part ID %04X\n", ntohs(info->part_id));
}
out:
kfree(msg);
return res;
}
static int
cp2615_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
struct usb_interface *usbif = adap->algo_data;
int i = 0, ret = 0;
struct i2c_msg *msg;
struct cp2615_i2c_transfer i2c_w = {0};
dev_dbg(&usbif->dev, "Doing %d I2C transactions\n", num);
for (; !ret && i < num; i++) {
msg = &msgs[i];
i2c_w.tag = 0xdd;
i2c_w.i2caddr = i2c_8bit_addr_from_msg(msg);
if (msg->flags & I2C_M_RD) {
i2c_w.read_len = msg->len;
i2c_w.write_len = 0;
} else {
i2c_w.read_len = 0;
i2c_w.write_len = msg->len;
memcpy(&i2c_w.data, msg->buf, i2c_w.write_len);
}
ret = cp2615_i2c_send(usbif, &i2c_w);
if (ret)
break;
ret = cp2615_i2c_recv(usbif, i2c_w.tag, msg->buf);
}
if (ret < 0)
return ret;
return i;
}
static u32
cp2615_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static const struct i2c_algorithm cp2615_i2c_algo = {
.master_xfer = cp2615_i2c_master_xfer,
.functionality = cp2615_i2c_func,
};
/*
* This chip has some limitations: one is that the USB endpoint
* can only receive 64 bytes/transfer, that leaves 54 bytes for
* the I2C transfer. On top of that, EITHER read_len OR write_len
* may be zero, but not both. If both are non-zero, the adapter
* issues a write followed by a read. And the chip does not
* support repeated START between the write and read phases.
*/
static struct i2c_adapter_quirks cp2615_i2c_quirks = {
.max_write_len = MAX_I2C_SIZE,
.max_read_len = MAX_I2C_SIZE,
.flags = I2C_AQ_COMB_WRITE_THEN_READ | I2C_AQ_NO_ZERO_LEN | I2C_AQ_NO_REP_START,
.max_comb_1st_msg_len = MAX_I2C_SIZE,
.max_comb_2nd_msg_len = MAX_I2C_SIZE
};
static void
cp2615_i2c_remove(struct usb_interface *usbif)
{
struct i2c_adapter *adap = usb_get_intfdata(usbif);
usb_set_intfdata(usbif, NULL);
i2c_del_adapter(adap);
}
static int
cp2615_i2c_probe(struct usb_interface *usbif, const struct usb_device_id *id)
{
int ret = 0;
struct i2c_adapter *adap;
struct usb_device *usbdev = interface_to_usbdev(usbif);
ret = usb_set_interface(usbdev, IOP_IFN, IOP_ALTSETTING);
if (ret)
return ret;
ret = cp2615_check_iop(usbif);
if (ret)
return ret;
adap = devm_kzalloc(&usbif->dev, sizeof(struct i2c_adapter), GFP_KERNEL);
if (!adap)
return -ENOMEM;
strncpy(adap->name, usbdev->serial, sizeof(adap->name) - 1);
adap->owner = THIS_MODULE;
adap->dev.parent = &usbif->dev;
adap->dev.of_node = usbif->dev.of_node;
adap->timeout = HZ;
adap->algo = &cp2615_i2c_algo;
adap->quirks = &cp2615_i2c_quirks;
adap->algo_data = usbif;
ret = i2c_add_adapter(adap);
if (ret)
return ret;
usb_set_intfdata(usbif, adap);
return 0;
}
static const struct usb_device_id id_table[] = {
{ USB_DEVICE_INTERFACE_NUMBER(CP2615_VID, CP2615_PID, IOP_IFN) },
{ }
};
MODULE_DEVICE_TABLE(usb, id_table);
static struct usb_driver cp2615_i2c_driver = {
.name = "i2c-cp2615",
.probe = cp2615_i2c_probe,
.disconnect = cp2615_i2c_remove,
.id_table = id_table,
};
module_usb_driver(cp2615_i2c_driver);
MODULE_AUTHOR("Bence Csókás <bence98@sch.bme.hu>");
MODULE_DESCRIPTION("CP2615 I2C bus driver");
MODULE_LICENSE("GPL");

View File

@@ -150,6 +150,9 @@ int i2c_dw_init_regmap(struct dw_i2c_dev *dev)
reg = readl(dev->base + DW_IC_COMP_TYPE);
i2c_dw_release_lock(dev);
if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU)
map_cfg.max_register = AMD_UCSI_INTR_REG;
if (reg == swab32(DW_IC_COMP_TYPE_VALUE)) {
map_cfg.reg_read = dw_reg_read_swab;
map_cfg.reg_write = dw_reg_write_swab;

Some files were not shown because too many files have changed in this diff Show More