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
commit 592fa9532d
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;

View File

@ -295,8 +295,16 @@ struct dw_i2c_dev {
#define MODEL_MSCC_OCELOT BIT(8)
#define MODEL_BAIKAL_BT1 BIT(9)
#define MODEL_AMD_NAVI_GPU BIT(10)
#define MODEL_MASK GENMASK(11, 8)
/*
* Enable UCSI interrupt by writing 0xd at register
* offset 0x474 specified in hardware specification.
*/
#define AMD_UCSI_INTR_REG 0x474
#define AMD_UCSI_INTR_EN 0xd
int i2c_dw_init_regmap(struct dw_i2c_dev *dev);
u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset);
u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset);

View File

@ -23,6 +23,10 @@
#include "i2c-designware-core.h"
#define AMD_TIMEOUT_MIN_US 25
#define AMD_TIMEOUT_MAX_US 250
#define AMD_MASTERCFG_MASK GENMASK(15, 0)
static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
{
/* Configure Tx/Rx FIFO threshold levels */
@ -35,10 +39,10 @@ static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
{
const char *mode_str, *fp_str = "";
u32 comp_param1;
u32 sda_falling_time, scl_falling_time;
struct i2c_timings *t = &dev->timings;
const char *fp_str = "";
u32 ic_clk;
int ret;
@ -78,7 +82,7 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
* difference is the timing parameter values since the registers are
* the same.
*/
if (t->bus_freq_hz == 1000000) {
if (t->bus_freq_hz == I2C_MAX_FAST_MODE_PLUS_FREQ) {
/*
* Check are Fast Mode Plus parameters available. Calculate
* SCL timing parameters for Fast Mode Plus if not set.
@ -154,22 +158,10 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
ret = i2c_dw_set_sda_hold(dev);
if (ret)
goto out;
return ret;
switch (dev->master_cfg & DW_IC_CON_SPEED_MASK) {
case DW_IC_CON_SPEED_STD:
mode_str = "Standard Mode";
break;
case DW_IC_CON_SPEED_HIGH:
mode_str = "High Speed Mode";
break;
default:
mode_str = "Fast Mode";
}
dev_dbg(dev->dev, "Bus speed: %s%s\n", mode_str, fp_str);
out:
return ret;
dev_dbg(dev->dev, "Bus speed: %s\n", i2c_freq_mode_string(t->bus_freq_hz));
return 0;
}
/**
@ -260,6 +252,108 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_MASTER_MASK);
}
static int i2c_dw_check_stopbit(struct dw_i2c_dev *dev)
{
u32 val;
int ret;
ret = regmap_read_poll_timeout(dev->map, DW_IC_INTR_STAT, val,
!(val & DW_IC_INTR_STOP_DET),
1100, 20000);
if (ret)
dev_err(dev->dev, "i2c timeout error %d\n", ret);
return ret;
}
static int i2c_dw_status(struct dw_i2c_dev *dev)
{
int status;
status = i2c_dw_wait_bus_not_busy(dev);
if (status)
return status;
return i2c_dw_check_stopbit(dev);
}
/*
* Initiate and continue master read/write transaction with polling
* based transfer routine afterward write messages into the Tx buffer.
*/
static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, int num_msgs)
{
struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
int msg_wrt_idx, msg_itr_lmt, buf_len, data_idx;
int cmd = 0, status;
u8 *tx_buf;
u32 val;
/*
* In order to enable the interrupt for UCSI i.e. AMD NAVI GPU card,
* it is mandatory to set the right value in specific register
* (offset:0x474) as per the hardware IP specification.
*/
regmap_write(dev->map, AMD_UCSI_INTR_REG, AMD_UCSI_INTR_EN);
dev->msgs = msgs;
dev->msgs_num = num_msgs;
i2c_dw_xfer_init(dev);
i2c_dw_disable_int(dev);
/* Initiate messages read/write transaction */
for (msg_wrt_idx = 0; msg_wrt_idx < num_msgs; msg_wrt_idx++) {
tx_buf = msgs[msg_wrt_idx].buf;
buf_len = msgs[msg_wrt_idx].len;
if (!(msgs[msg_wrt_idx].flags & I2C_M_RD))
regmap_write(dev->map, DW_IC_TX_TL, buf_len - 1);
/*
* Initiate the i2c read/write transaction of buffer length,
* and poll for bus busy status. For the last message transfer,
* update the command with stopbit enable.
*/
for (msg_itr_lmt = buf_len; msg_itr_lmt > 0; msg_itr_lmt--) {
if (msg_wrt_idx == num_msgs - 1 && msg_itr_lmt == 1)
cmd |= BIT(9);
if (msgs[msg_wrt_idx].flags & I2C_M_RD) {
/* Due to hardware bug, need to write the same command twice. */
regmap_write(dev->map, DW_IC_DATA_CMD, 0x100);
regmap_write(dev->map, DW_IC_DATA_CMD, 0x100 | cmd);
if (cmd) {
regmap_write(dev->map, DW_IC_TX_TL, 2 * (buf_len - 1));
regmap_write(dev->map, DW_IC_RX_TL, 2 * (buf_len - 1));
/*
* Need to check the stop bit. However, it cannot be
* detected from the registers so we check it always
* when read/write the last byte.
*/
status = i2c_dw_status(dev);
if (status)
return status;
for (data_idx = 0; data_idx < buf_len; data_idx++) {
regmap_read(dev->map, DW_IC_DATA_CMD, &val);
tx_buf[data_idx] = val;
}
status = i2c_dw_check_stopbit(dev);
if (status)
return status;
}
} else {
regmap_write(dev->map, DW_IC_DATA_CMD, *tx_buf++ | cmd);
usleep_range(AMD_TIMEOUT_MIN_US, AMD_TIMEOUT_MAX_US);
}
}
status = i2c_dw_check_stopbit(dev);
if (status)
return status;
}
return 0;
}
/*
* Initiate (and continue) low level master read/write transaction.
* This function is only called from i2c_dw_isr, and pumping i2c_msg
@ -463,6 +557,16 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
pm_runtime_get_sync(dev->dev);
/*
* Initiate I2C message transfer when AMD NAVI GPU card is enabled,
* As it is polling based transfer mechanism, which does not support
* interrupt based functionalities of existing DesignWare driver.
*/
if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU) {
ret = amd_i2c_dw_xfer_quirk(adap, msgs, num);
goto done_nolock;
}
if (dev_WARN_ONCE(dev->dev, dev->suspended, "Transfer while suspended\n")) {
ret = -ESHUTDOWN;
goto done_nolock;
@ -739,6 +843,20 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev)
return 0;
}
static int amd_i2c_adap_quirk(struct dw_i2c_dev *dev)
{
struct i2c_adapter *adap = &dev->adapter;
int ret;
pm_runtime_get_noresume(dev->dev);
ret = i2c_add_numbered_adapter(adap);
if (ret)
dev_err(dev->dev, "Failed to add adapter: %d\n", ret);
pm_runtime_put_noidle(dev->dev);
return ret;
}
int i2c_dw_probe_master(struct dw_i2c_dev *dev)
{
struct i2c_adapter *adap = &dev->adapter;
@ -775,6 +893,9 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
adap->dev.parent = dev->dev;
i2c_set_adapdata(adap, dev);
if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU)
return amd_i2c_adap_quirk(dev);
if (dev->flags & ACCESS_NO_IRQ_SUSPEND) {
irq_flags = IRQF_NO_SUSPEND;
} else {

View File

@ -26,6 +26,7 @@
#include "i2c-designware-core.h"
#define DRIVER_NAME "i2c-designware-pci"
#define AMD_CLK_RATE_HZ 100000
enum dw_pci_ctl_id_t {
medfield,
@ -34,6 +35,7 @@ enum dw_pci_ctl_id_t {
cherrytrail,
haswell,
elkhartlake,
navi_amd,
};
struct dw_scl_sda_cfg {
@ -78,11 +80,23 @@ static struct dw_scl_sda_cfg hsw_config = {
.sda_hold = 0x9,
};
/* NAVI-AMD HCNT/LCNT/SDA hold time */
static struct dw_scl_sda_cfg navi_amd_config = {
.ss_hcnt = 0x1ae,
.ss_lcnt = 0x23a,
.sda_hold = 0x9,
};
static u32 mfld_get_clk_rate_khz(struct dw_i2c_dev *dev)
{
return 25000;
}
static u32 navi_amd_get_clk_rate_khz(struct dw_i2c_dev *dev)
{
return AMD_CLK_RATE_HZ;
}
static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
{
struct dw_i2c_dev *dev = dev_get_drvdata(&pdev->dev);
@ -104,6 +118,35 @@ static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
return -ENODEV;
}
/*
* TODO find a better way how to deduplicate instantiation
* of USB PD slave device from nVidia GPU driver.
*/
static int navi_amd_register_client(struct dw_i2c_dev *dev)
{
struct i2c_board_info info;
memset(&info, 0, sizeof(struct i2c_board_info));
strscpy(info.type, "ccgx-ucsi", I2C_NAME_SIZE);
info.addr = 0x08;
info.irq = dev->irq;
dev->slave = i2c_new_client_device(&dev->adapter, &info);
if (IS_ERR(dev->slave))
return PTR_ERR(dev->slave);
return 0;
}
static int navi_amd_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
{
struct dw_i2c_dev *dev = dev_get_drvdata(&pdev->dev);
dev->flags |= MODEL_AMD_NAVI_GPU;
dev->timings.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ;
return 0;
}
static int mrfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
{
/*
@ -155,6 +198,12 @@ static struct dw_pci_controller dw_pci_controllers[] = {
.bus_num = -1,
.get_clk_rate_khz = ehl_get_clk_rate_khz,
},
[navi_amd] = {
.bus_num = -1,
.scl_sda_cfg = &navi_amd_config,
.setup = navi_amd_setup,
.get_clk_rate_khz = navi_amd_get_clk_rate_khz,
},
};
#ifdef CONFIG_PM
@ -274,6 +323,14 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
return r;
}
if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU) {
r = navi_amd_register_client(dev);
if (r) {
dev_err(dev->dev, "register client failed with %d\n", r);
return r;
}
}
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
@ -337,6 +394,10 @@ static const struct pci_device_id i2_designware_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x4bbe), elkhartlake },
{ PCI_VDEVICE(INTEL, 0x4bbf), elkhartlake },
{ PCI_VDEVICE(INTEL, 0x4bc0), elkhartlake },
{ PCI_VDEVICE(ATI, 0x7314), navi_amd },
{ PCI_VDEVICE(ATI, 0x73a4), navi_amd },
{ PCI_VDEVICE(ATI, 0x73e4), navi_amd },
{ PCI_VDEVICE(ATI, 0x73c4), navi_amd },
{ 0,}
};
MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids);

View File

@ -395,7 +395,10 @@ static int em_i2c_probe(struct platform_device *pdev)
em_i2c_reset(&priv->adap);
priv->irq = platform_get_irq(pdev, 0);
ret = platform_get_irq(pdev, 0);
if (ret < 0)
goto err_clk;
priv->irq = ret;
ret = devm_request_irq(&pdev->dev, priv->irq, em_i2c_irq_handler, 0,
"em_i2c", priv);
if (ret)

View File

@ -0,0 +1,504 @@
// SPDX-License-Identifier: GPL-2.0
/*
* HiSilicon I2C Controller Driver for Kunpeng SoC
*
* Copyright (c) 2021 HiSilicon Technologies Co., Ltd.
*/
#include <linux/bits.h>
#include <linux/bitfield.h>
#include <linux/completion.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#define HISI_I2C_FRAME_CTRL 0x0000
#define HISI_I2C_FRAME_CTRL_SPEED_MODE GENMASK(1, 0)
#define HISI_I2C_FRAME_CTRL_ADDR_TEN BIT(2)
#define HISI_I2C_SLV_ADDR 0x0004
#define HISI_I2C_SLV_ADDR_VAL GENMASK(9, 0)
#define HISI_I2C_SLV_ADDR_GC_S_MODE BIT(10)
#define HISI_I2C_SLV_ADDR_GC_S_EN BIT(11)
#define HISI_I2C_CMD_TXDATA 0x0008
#define HISI_I2C_CMD_TXDATA_DATA GENMASK(7, 0)
#define HISI_I2C_CMD_TXDATA_RW BIT(8)
#define HISI_I2C_CMD_TXDATA_P_EN BIT(9)
#define HISI_I2C_CMD_TXDATA_SR_EN BIT(10)
#define HISI_I2C_RXDATA 0x000c
#define HISI_I2C_RXDATA_DATA GENMASK(7, 0)
#define HISI_I2C_SS_SCL_HCNT 0x0010
#define HISI_I2C_SS_SCL_LCNT 0x0014
#define HISI_I2C_FS_SCL_HCNT 0x0018
#define HISI_I2C_FS_SCL_LCNT 0x001c
#define HISI_I2C_HS_SCL_HCNT 0x0020
#define HISI_I2C_HS_SCL_LCNT 0x0024
#define HISI_I2C_FIFO_CTRL 0x0028
#define HISI_I2C_FIFO_RX_CLR BIT(0)
#define HISI_I2C_FIFO_TX_CLR BIT(1)
#define HISI_I2C_FIFO_RX_AF_THRESH GENMASK(7, 2)
#define HISI_I2C_FIFO_TX_AE_THRESH GENMASK(13, 8)
#define HISI_I2C_FIFO_STATE 0x002c
#define HISI_I2C_FIFO_STATE_RX_RERR BIT(0)
#define HISI_I2C_FIFO_STATE_RX_WERR BIT(1)
#define HISI_I2C_FIFO_STATE_RX_EMPTY BIT(3)
#define HISI_I2C_FIFO_STATE_TX_RERR BIT(6)
#define HISI_I2C_FIFO_STATE_TX_WERR BIT(7)
#define HISI_I2C_FIFO_STATE_TX_FULL BIT(11)
#define HISI_I2C_SDA_HOLD 0x0030
#define HISI_I2C_SDA_HOLD_TX GENMASK(15, 0)
#define HISI_I2C_SDA_HOLD_RX GENMASK(23, 16)
#define HISI_I2C_FS_SPK_LEN 0x0038
#define HISI_I2C_FS_SPK_LEN_CNT GENMASK(7, 0)
#define HISI_I2C_HS_SPK_LEN 0x003c
#define HISI_I2C_HS_SPK_LEN_CNT GENMASK(7, 0)
#define HISI_I2C_INT_MSTAT 0x0044
#define HISI_I2C_INT_CLR 0x0048
#define HISI_I2C_INT_MASK 0x004C
#define HISI_I2C_TRANS_STATE 0x0050
#define HISI_I2C_TRANS_ERR 0x0054
#define HISI_I2C_VERSION 0x0058
#define HISI_I2C_INT_ALL GENMASK(4, 0)
#define HISI_I2C_INT_TRANS_CPLT BIT(0)
#define HISI_I2C_INT_TRANS_ERR BIT(1)
#define HISI_I2C_INT_FIFO_ERR BIT(2)
#define HISI_I2C_INT_RX_FULL BIT(3)
#define HISI_I2C_INT_TX_EMPTY BIT(4)
#define HISI_I2C_INT_ERR \
(HISI_I2C_INT_TRANS_ERR | HISI_I2C_INT_FIFO_ERR)
#define HISI_I2C_STD_SPEED_MODE 0
#define HISI_I2C_FAST_SPEED_MODE 1
#define HISI_I2C_HIGH_SPEED_MODE 2
#define HISI_I2C_TX_FIFO_DEPTH 64
#define HISI_I2C_RX_FIFO_DEPTH 64
#define HISI_I2C_TX_F_AE_THRESH 1
#define HISI_I2C_RX_F_AF_THRESH 60
#define HZ_PER_KHZ 1000
#define NSEC_TO_CYCLES(ns, clk_rate_khz) \
DIV_ROUND_UP_ULL((clk_rate_khz) * (ns), NSEC_PER_MSEC)
struct hisi_i2c_controller {
struct i2c_adapter adapter;
void __iomem *iobase;
struct device *dev;
int irq;
/* Intermediates for recording the transfer process */
struct completion *completion;
struct i2c_msg *msgs;
int msg_num;
int msg_tx_idx;
int buf_tx_idx;
int msg_rx_idx;
int buf_rx_idx;
u16 tar_addr;
u32 xfer_err;
/* I2C bus configuration */
struct i2c_timings t;
u32 clk_rate_khz;
u32 spk_len;
};
static void hisi_i2c_enable_int(struct hisi_i2c_controller *ctlr, u32 mask)
{
writel_relaxed(mask, ctlr->iobase + HISI_I2C_INT_MASK);
}
static void hisi_i2c_disable_int(struct hisi_i2c_controller *ctlr, u32 mask)
{
writel_relaxed((~mask) & HISI_I2C_INT_ALL, ctlr->iobase + HISI_I2C_INT_MASK);
}
static void hisi_i2c_clear_int(struct hisi_i2c_controller *ctlr, u32 mask)
{
writel_relaxed(mask, ctlr->iobase + HISI_I2C_INT_CLR);
}
static void hisi_i2c_handle_errors(struct hisi_i2c_controller *ctlr)
{
u32 int_err = ctlr->xfer_err, reg;
if (int_err & HISI_I2C_INT_FIFO_ERR) {
reg = readl(ctlr->iobase + HISI_I2C_FIFO_STATE);
if (reg & HISI_I2C_FIFO_STATE_RX_RERR)
dev_err(ctlr->dev, "rx fifo error read\n");
if (reg & HISI_I2C_FIFO_STATE_RX_WERR)
dev_err(ctlr->dev, "rx fifo error write\n");
if (reg & HISI_I2C_FIFO_STATE_TX_RERR)
dev_err(ctlr->dev, "tx fifo error read\n");
if (reg & HISI_I2C_FIFO_STATE_TX_WERR)
dev_err(ctlr->dev, "tx fifo error write\n");
}
}
static int hisi_i2c_start_xfer(struct hisi_i2c_controller *ctlr)
{
struct i2c_msg *msg = ctlr->msgs;
u32 reg;
reg = readl(ctlr->iobase + HISI_I2C_FRAME_CTRL);
reg &= ~HISI_I2C_FRAME_CTRL_ADDR_TEN;
if (msg->flags & I2C_M_TEN)
reg |= HISI_I2C_FRAME_CTRL_ADDR_TEN;
writel(reg, ctlr->iobase + HISI_I2C_FRAME_CTRL);
reg = readl(ctlr->iobase + HISI_I2C_SLV_ADDR);
reg &= ~HISI_I2C_SLV_ADDR_VAL;
reg |= FIELD_PREP(HISI_I2C_SLV_ADDR_VAL, msg->addr);
writel(reg, ctlr->iobase + HISI_I2C_SLV_ADDR);
reg = readl(ctlr->iobase + HISI_I2C_FIFO_CTRL);
reg |= HISI_I2C_FIFO_RX_CLR | HISI_I2C_FIFO_TX_CLR;
writel(reg, ctlr->iobase + HISI_I2C_FIFO_CTRL);
reg &= ~(HISI_I2C_FIFO_RX_CLR | HISI_I2C_FIFO_TX_CLR);
writel(reg, ctlr->iobase + HISI_I2C_FIFO_CTRL);
hisi_i2c_clear_int(ctlr, HISI_I2C_INT_ALL);
hisi_i2c_enable_int(ctlr, HISI_I2C_INT_ALL);
return 0;
}
static void hisi_i2c_reset_xfer(struct hisi_i2c_controller *ctlr)
{
ctlr->msg_num = 0;
ctlr->xfer_err = 0;
ctlr->msg_tx_idx = 0;
ctlr->msg_rx_idx = 0;
ctlr->buf_tx_idx = 0;
ctlr->buf_rx_idx = 0;
}
/*
* Initialize the transfer information and start the I2C bus transfer.
* We only configure the transfer and do some pre/post works here, and
* wait for the transfer done. The major transfer process is performed
* in the IRQ handler.
*/
static int hisi_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num)
{
struct hisi_i2c_controller *ctlr = i2c_get_adapdata(adap);
DECLARE_COMPLETION_ONSTACK(done);
int ret = num;
hisi_i2c_reset_xfer(ctlr);
ctlr->completion = &done;
ctlr->msg_num = num;
ctlr->msgs = msgs;
hisi_i2c_start_xfer(ctlr);
if (!wait_for_completion_timeout(ctlr->completion, adap->timeout)) {
hisi_i2c_disable_int(ctlr, HISI_I2C_INT_ALL);
synchronize_irq(ctlr->irq);
i2c_recover_bus(&ctlr->adapter);
dev_err(ctlr->dev, "bus transfer timeout\n");
ret = -EIO;
}
if (ctlr->xfer_err) {
hisi_i2c_handle_errors(ctlr);
ret = -EIO;
}
hisi_i2c_reset_xfer(ctlr);
ctlr->completion = NULL;
return ret;
}
static u32 hisi_i2c_functionality(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
}
static const struct i2c_algorithm hisi_i2c_algo = {
.master_xfer = hisi_i2c_master_xfer,
.functionality = hisi_i2c_functionality,
};
static int hisi_i2c_read_rx_fifo(struct hisi_i2c_controller *ctlr)
{
struct i2c_msg *cur_msg;
u32 fifo_state;
while (ctlr->msg_rx_idx < ctlr->msg_num) {
cur_msg = ctlr->msgs + ctlr->msg_rx_idx;
if (!(cur_msg->flags & I2C_M_RD)) {
ctlr->msg_rx_idx++;
continue;
}
fifo_state = readl(ctlr->iobase + HISI_I2C_FIFO_STATE);
while (!(fifo_state & HISI_I2C_FIFO_STATE_RX_EMPTY) &&
ctlr->buf_rx_idx < cur_msg->len) {
cur_msg->buf[ctlr->buf_rx_idx++] = readl(ctlr->iobase + HISI_I2C_RXDATA);
fifo_state = readl(ctlr->iobase + HISI_I2C_FIFO_STATE);
}
if (ctlr->buf_rx_idx == cur_msg->len) {
ctlr->buf_rx_idx = 0;
ctlr->msg_rx_idx++;
}
if (fifo_state & HISI_I2C_FIFO_STATE_RX_EMPTY)
break;
}
return 0;
}
static void hisi_i2c_xfer_msg(struct hisi_i2c_controller *ctlr)
{
int max_write = HISI_I2C_TX_FIFO_DEPTH;
bool need_restart = false, last_msg;
struct i2c_msg *cur_msg;
u32 cmd, fifo_state;
while (ctlr->msg_tx_idx < ctlr->msg_num) {
cur_msg = ctlr->msgs + ctlr->msg_tx_idx;
last_msg = (ctlr->msg_tx_idx == ctlr->msg_num - 1);
/* Signal the SR bit when we start transferring a new message */
if (ctlr->msg_tx_idx && !ctlr->buf_tx_idx)
need_restart = true;
fifo_state = readl(ctlr->iobase + HISI_I2C_FIFO_STATE);
while (!(fifo_state & HISI_I2C_FIFO_STATE_TX_FULL) &&
ctlr->buf_tx_idx < cur_msg->len && max_write) {
cmd = 0;
if (need_restart) {
cmd |= HISI_I2C_CMD_TXDATA_SR_EN;
need_restart = false;
}
/* Signal the STOP bit at the last frame of the last message */
if (ctlr->buf_tx_idx == cur_msg->len - 1 && last_msg)
cmd |= HISI_I2C_CMD_TXDATA_P_EN;
if (cur_msg->flags & I2C_M_RD)
cmd |= HISI_I2C_CMD_TXDATA_RW;
else
cmd |= FIELD_PREP(HISI_I2C_CMD_TXDATA_DATA,
cur_msg->buf[ctlr->buf_tx_idx]);
writel(cmd, ctlr->iobase + HISI_I2C_CMD_TXDATA);
ctlr->buf_tx_idx++;
max_write--;
fifo_state = readl(ctlr->iobase + HISI_I2C_FIFO_STATE);
}
/* Update the transfer index after per message transfer is done. */
if (ctlr->buf_tx_idx == cur_msg->len) {
ctlr->buf_tx_idx = 0;
ctlr->msg_tx_idx++;
}
if ((fifo_state & HISI_I2C_FIFO_STATE_TX_FULL) ||
max_write == 0)
break;
}
}
static irqreturn_t hisi_i2c_irq(int irq, void *context)
{
struct hisi_i2c_controller *ctlr = context;
u32 int_stat;
int_stat = readl(ctlr->iobase + HISI_I2C_INT_MSTAT);
hisi_i2c_clear_int(ctlr, int_stat);
if (!(int_stat & HISI_I2C_INT_ALL))
return IRQ_NONE;
if (int_stat & HISI_I2C_INT_TX_EMPTY)
hisi_i2c_xfer_msg(ctlr);
if (int_stat & HISI_I2C_INT_ERR) {
ctlr->xfer_err = int_stat;
goto out;
}
/* Drain the rx fifo before finish the transfer */
if (int_stat & (HISI_I2C_INT_TRANS_CPLT | HISI_I2C_INT_RX_FULL))
hisi_i2c_read_rx_fifo(ctlr);
out:
if (int_stat & HISI_I2C_INT_TRANS_CPLT || ctlr->xfer_err) {
hisi_i2c_disable_int(ctlr, HISI_I2C_INT_ALL);
hisi_i2c_clear_int(ctlr, HISI_I2C_INT_ALL);
complete(ctlr->completion);
}
return IRQ_HANDLED;
}
/*
* Helper function for calculating and configuring the HIGH and LOW
* periods of SCL clock. The caller will pass the ratio of the
* counts (divide / divisor) according to the target speed mode,
* and the target registers.
*/
static void hisi_i2c_set_scl(struct hisi_i2c_controller *ctlr,
u32 divide, u32 divisor,
u32 reg_hcnt, u32 reg_lcnt)
{
u32 total_cnt, t_scl_hcnt, t_scl_lcnt, scl_fall_cnt, scl_rise_cnt;
u32 scl_hcnt, scl_lcnt;
/* Total SCL clock cycles per speed period */
total_cnt = DIV_ROUND_UP_ULL(ctlr->clk_rate_khz * HZ_PER_KHZ, ctlr->t.bus_freq_hz);
/* Total HIGH level SCL clock cycles including edges */
t_scl_hcnt = DIV_ROUND_UP_ULL(total_cnt * divide, divisor);
/* Total LOW level SCL clock cycles including edges */
t_scl_lcnt = total_cnt - t_scl_hcnt;
/* Fall edge SCL clock cycles */
scl_fall_cnt = NSEC_TO_CYCLES(ctlr->t.scl_fall_ns, ctlr->clk_rate_khz);
/* Rise edge SCL clock cycles */
scl_rise_cnt = NSEC_TO_CYCLES(ctlr->t.scl_rise_ns, ctlr->clk_rate_khz);
/* Calculated HIGH and LOW periods of SCL clock */
scl_hcnt = t_scl_hcnt - ctlr->spk_len - 7 - scl_fall_cnt;
scl_lcnt = t_scl_lcnt - 1 - scl_rise_cnt;
writel(scl_hcnt, ctlr->iobase + reg_hcnt);
writel(scl_lcnt, ctlr->iobase + reg_lcnt);
}
static void hisi_i2c_configure_bus(struct hisi_i2c_controller *ctlr)
{
u32 reg, sda_hold_cnt, speed_mode;
i2c_parse_fw_timings(ctlr->dev, &ctlr->t, true);
ctlr->spk_len = NSEC_TO_CYCLES(ctlr->t.digital_filter_width_ns, ctlr->clk_rate_khz);
switch (ctlr->t.bus_freq_hz) {
case I2C_MAX_FAST_MODE_FREQ:
speed_mode = HISI_I2C_FAST_SPEED_MODE;
hisi_i2c_set_scl(ctlr, 26, 76, HISI_I2C_FS_SCL_HCNT, HISI_I2C_FS_SCL_LCNT);
break;
case I2C_MAX_HIGH_SPEED_MODE_FREQ:
speed_mode = HISI_I2C_HIGH_SPEED_MODE;
hisi_i2c_set_scl(ctlr, 6, 22, HISI_I2C_HS_SCL_HCNT, HISI_I2C_HS_SCL_LCNT);
break;
case I2C_MAX_STANDARD_MODE_FREQ:
default:
speed_mode = HISI_I2C_STD_SPEED_MODE;
/* For default condition force the bus speed to standard mode. */
ctlr->t.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ;
hisi_i2c_set_scl(ctlr, 40, 87, HISI_I2C_SS_SCL_HCNT, HISI_I2C_SS_SCL_LCNT);
break;
}
reg = readl(ctlr->iobase + HISI_I2C_FRAME_CTRL);
reg &= ~HISI_I2C_FRAME_CTRL_SPEED_MODE;
reg |= FIELD_PREP(HISI_I2C_FRAME_CTRL_SPEED_MODE, speed_mode);
writel(reg, ctlr->iobase + HISI_I2C_FRAME_CTRL);
sda_hold_cnt = NSEC_TO_CYCLES(ctlr->t.sda_hold_ns, ctlr->clk_rate_khz);
reg = FIELD_PREP(HISI_I2C_SDA_HOLD_TX, sda_hold_cnt);
writel(reg, ctlr->iobase + HISI_I2C_SDA_HOLD);
writel(ctlr->spk_len, ctlr->iobase + HISI_I2C_FS_SPK_LEN);
reg = FIELD_PREP(HISI_I2C_FIFO_RX_AF_THRESH, HISI_I2C_RX_F_AF_THRESH);
reg |= FIELD_PREP(HISI_I2C_FIFO_TX_AE_THRESH, HISI_I2C_TX_F_AE_THRESH);
writel(reg, ctlr->iobase + HISI_I2C_FIFO_CTRL);
}
static int hisi_i2c_probe(struct platform_device *pdev)
{
struct hisi_i2c_controller *ctlr;
struct device *dev = &pdev->dev;
struct i2c_adapter *adapter;
u64 clk_rate_hz;
u32 hw_version;
int ret;
ctlr = devm_kzalloc(dev, sizeof(*ctlr), GFP_KERNEL);
if (!ctlr)
return -ENOMEM;
ctlr->iobase = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ctlr->iobase))
return PTR_ERR(ctlr->iobase);
ctlr->irq = platform_get_irq(pdev, 0);
if (ctlr->irq < 0)
return ctlr->irq;
ctlr->dev = dev;
hisi_i2c_disable_int(ctlr, HISI_I2C_INT_ALL);
ret = devm_request_irq(dev, ctlr->irq, hisi_i2c_irq, 0, "hisi-i2c", ctlr);
if (ret) {
dev_err(dev, "failed to request irq handler, ret = %d\n", ret);
return ret;
}
ret = device_property_read_u64(dev, "clk_rate", &clk_rate_hz);
if (ret) {
dev_err(dev, "failed to get clock frequency, ret = %d\n", ret);
return ret;
}
ctlr->clk_rate_khz = DIV_ROUND_UP_ULL(clk_rate_hz, HZ_PER_KHZ);
hisi_i2c_configure_bus(ctlr);
adapter = &ctlr->adapter;
snprintf(adapter->name, sizeof(adapter->name),
"HiSilicon I2C Controller %s", dev_name(dev));
adapter->owner = THIS_MODULE;
adapter->algo = &hisi_i2c_algo;
adapter->dev.parent = dev;
i2c_set_adapdata(adapter, ctlr);
ret = devm_i2c_add_adapter(dev, adapter);
if (ret)
return ret;
hw_version = readl(ctlr->iobase + HISI_I2C_VERSION);
dev_info(ctlr->dev, "speed mode is %s. hw version 0x%x\n",
i2c_freq_mode_string(ctlr->t.bus_freq_hz), hw_version);
return 0;
}
static const struct acpi_device_id hisi_i2c_acpi_ids[] = {
{ "HISI03D1", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, hisi_i2c_acpi_ids);
static struct platform_driver hisi_i2c_driver = {
.probe = hisi_i2c_probe,
.driver = {
.name = "hisi-i2c",
.acpi_match_table = hisi_i2c_acpi_ids,
},
};
module_platform_driver(hisi_i2c_driver);
MODULE_AUTHOR("Yicong Yang <yangyicong@hisilicon.com>");
MODULE_DESCRIPTION("HiSilicon I2C Controller Driver");
MODULE_LICENSE("GPL");

View File

@ -73,6 +73,7 @@
* Comet Lake-V (PCH) 0xa3a3 32 hard yes yes yes
* Alder Lake-S (PCH) 0x7aa3 32 hard yes yes yes
* Alder Lake-P (PCH) 0x51a3 32 hard yes yes yes
* Alder Lake-M (PCH) 0x54a3 32 hard yes yes yes
*
* Features supported by this driver:
* Software PEC no
@ -230,6 +231,7 @@
#define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS 0x4b23
#define PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS 0x4da3
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_P_SMBUS 0x51a3
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_M_SMBUS 0x54a3
#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4
#define PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS 0x7aa3
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
@ -1087,6 +1089,7 @@ static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ALDER_LAKE_P_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ALDER_LAKE_M_SMBUS) },
{ 0, }
};
@ -1771,6 +1774,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
case PCI_DEVICE_ID_INTEL_EBG_SMBUS:
case PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS:
case PCI_DEVICE_ID_INTEL_ALDER_LAKE_P_SMBUS:
case PCI_DEVICE_ID_INTEL_ALDER_LAKE_M_SMBUS:
priv->features |= FEATURE_BLOCK_PROC;
priv->features |= FEATURE_I2C_BLOCK_READ;
priv->features |= FEATURE_IRQ;

View File

@ -54,7 +54,6 @@ struct icy_i2c {
void __iomem *reg_s0;
void __iomem *reg_s1;
struct fwnode_handle *ltc2990_fwnode;
struct i2c_client *ltc2990_client;
};
@ -115,6 +114,10 @@ static const struct property_entry icy_ltc2990_props[] = {
{ }
};
static const struct software_node icy_ltc2990_node = {
.properties = icy_ltc2990_props,
};
static int icy_probe(struct zorro_dev *z,
const struct zorro_device_id *ent)
{
@ -123,6 +126,7 @@ static int icy_probe(struct zorro_dev *z,
struct fwnode_handle *new_fwnode;
struct i2c_board_info ltc2990_info = {
.type = "ltc2990",
.swnode = &icy_ltc2990_node,
};
i2c = devm_kzalloc(&z->dev, sizeof(*i2c), GFP_KERNEL);
@ -174,26 +178,10 @@ static int icy_probe(struct zorro_dev *z,
*
* See property_entry above for in1, in2, temp3.
*/
new_fwnode = fwnode_create_software_node(icy_ltc2990_props, NULL);
if (IS_ERR(new_fwnode)) {
dev_info(&z->dev, "Failed to create fwnode for LTC2990, error: %ld\n",
PTR_ERR(new_fwnode));
} else {
/*
* Store the fwnode so we can destroy it on .remove().
* Only store it on success, as fwnode_remove_software_node()
* is NULL safe, but not PTR_ERR safe.
*/
i2c->ltc2990_fwnode = new_fwnode;
ltc2990_info.fwnode = new_fwnode;
i2c->ltc2990_client =
i2c_new_scanned_device(&i2c->adapter,
&ltc2990_info,
icy_ltc2990_addresses,
NULL);
}
i2c->ltc2990_client = i2c_new_scanned_device(&i2c->adapter,
&ltc2990_info,
icy_ltc2990_addresses,
NULL);
return 0;
}
@ -202,8 +190,6 @@ static void icy_remove(struct zorro_dev *z)
struct icy_i2c *i2c = dev_get_drvdata(&z->dev);
i2c_unregister_device(i2c->ltc2990_client);
fwnode_remove_software_node(i2c->ltc2990_fwnode);
i2c_del_adapter(&i2c->adapter);
}

View File

@ -1057,7 +1057,7 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
atomic = true;
}
ret = pm_runtime_get_sync(adap->dev.parent);
ret = pm_runtime_resume_and_get(adap->dev.parent);
if (ret < 0)
return ret;
@ -1158,7 +1158,7 @@ static int img_i2c_init(struct img_i2c *i2c)
u32 rev;
int ret;
ret = pm_runtime_get_sync(i2c->adap.dev.parent);
ret = pm_runtime_resume_and_get(i2c->adap.dev.parent);
if (ret < 0)
return ret;

View File

@ -259,7 +259,7 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx)
unsigned int temp;
int ret;
ret = pm_runtime_get_sync(lpi2c_imx->adapter.dev.parent);
ret = pm_runtime_resume_and_get(lpi2c_imx->adapter.dev.parent);
if (ret < 0)
return ret;

View File

@ -801,7 +801,7 @@ static int i2c_imx_reg_slave(struct i2c_client *client)
i2c_imx->last_slave_event = I2C_SLAVE_STOP;
/* Resume */
ret = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
ret = pm_runtime_resume_and_get(i2c_imx->adapter.dev.parent);
if (ret < 0) {
dev_err(&i2c_imx->adapter.dev, "failed to resume i2c controller");
return ret;
@ -1253,7 +1253,7 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter);
int result;
result = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
result = pm_runtime_resume_and_get(i2c_imx->adapter.dev.parent);
if (result < 0)
return result;
@ -1496,7 +1496,7 @@ static int i2c_imx_remove(struct platform_device *pdev)
struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
int irq, ret;
ret = pm_runtime_get_sync(&pdev->dev);
ret = pm_runtime_resume_and_get(&pdev->dev);
if (ret < 0)
return ret;

View File

@ -125,10 +125,12 @@ iop3xx_i2c_error(u32 sr)
int rc = 0;
if ((sr & IOP3XX_ISR_BERRD)) {
if ( !rc ) rc = -I2C_ERR_BERR;
if (!rc)
rc = -I2C_ERR_BERR;
}
if ((sr & IOP3XX_ISR_ALD)) {
if ( !rc ) rc = -I2C_ERR_ALD;
if (!rc)
rc = -I2C_ERR_ALD;
}
return rc;
}
@ -151,12 +153,12 @@ iop3xx_i2c_get_srstat(struct i2c_algo_iop3xx_data *iop3xx_adap)
* sleep until interrupted, then recover and analyse the SR
* saved by handler
*/
typedef int (* compare_func)(unsigned test, unsigned mask);
typedef int (*compare_func)(unsigned test, unsigned mask);
/* returns 1 on correct comparison */
static int
iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap,
unsigned flags, unsigned* status,
unsigned flags, unsigned *status,
compare_func compare)
{
unsigned sr = 0;
@ -167,7 +169,7 @@ iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap,
do {
interrupted = wait_event_interruptible_timeout (
iop3xx_adap->waitq,
(done = compare( sr = iop3xx_i2c_get_srstat(iop3xx_adap) ,flags )),
(done = compare(sr = iop3xx_i2c_get_srstat(iop3xx_adap), flags)),
1 * HZ
);
if ((rc = iop3xx_i2c_error(sr)) < 0) {
@ -177,7 +179,7 @@ iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap,
*status = sr;
return -ETIMEDOUT;
}
} while(!done);
} while (!done);
*status = sr;
@ -204,7 +206,7 @@ iop3xx_i2c_wait_tx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
{
return iop3xx_i2c_wait_event(
iop3xx_adap,
IOP3XX_ISR_TXEMPTY | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD,
IOP3XX_ISR_TXEMPTY | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD,
status, any_bits_set);
}
@ -226,7 +228,7 @@ iop3xx_i2c_wait_idle(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
static int
iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap,
struct i2c_msg* msg)
struct i2c_msg *msg)
{
unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
int status;
@ -273,7 +275,7 @@ iop3xx_i2c_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte,
}
static int
iop3xx_i2c_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char* byte,
iop3xx_i2c_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char *byte,
int stop)
{
unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
@ -305,7 +307,7 @@ iop3xx_i2c_writebytes(struct i2c_adapter *i2c_adap, const char *buf, int count)
int rc = 0;
for (ii = 0; rc == 0 && ii != count; ++ii)
rc = iop3xx_i2c_write_byte(iop3xx_adap, buf[ii], ii==count-1);
rc = iop3xx_i2c_write_byte(iop3xx_adap, buf[ii], ii == count-1);
return rc;
}
@ -317,7 +319,7 @@ iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count)
int rc = 0;
for (ii = 0; rc == 0 && ii != count; ++ii)
rc = iop3xx_i2c_read_byte(iop3xx_adap, &buf[ii], ii==count-1);
rc = iop3xx_i2c_read_byte(iop3xx_adap, &buf[ii], ii == count-1);
return rc;
}
@ -330,7 +332,7 @@ iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count)
* condition.
*/
static int
iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg)
iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg *pmsg)
{
struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
int rc;
@ -369,7 +371,7 @@ iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
iop3xx_i2c_transaction_cleanup(iop3xx_adap);
if(ret)
if (ret)
return ret;
return im;

View File

@ -825,7 +825,10 @@ static int jz4780_i2c_probe(struct platform_device *pdev)
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0x0);
i2c->irq = platform_get_irq(pdev, 0);
ret = platform_get_irq(pdev, 0);
if (ret < 0)
goto err;
i2c->irq = ret;
ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0,
dev_name(&pdev->dev), i2c);
if (ret)

View File

@ -172,12 +172,6 @@
#define MLXBF_I2C_SMBUS_THIGH_MAX_TBUF 0x14
#define MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT 0x18
enum {
MLXBF_I2C_TIMING_100KHZ = 100000,
MLXBF_I2C_TIMING_400KHZ = 400000,
MLXBF_I2C_TIMING_1000KHZ = 1000000,
};
/*
* Defines SMBus operating frequency and core clock frequency.
* According to ADB files, default values are compliant to 100KHz SMBus
@ -1202,7 +1196,7 @@ static int mlxbf_i2c_init_timings(struct platform_device *pdev,
ret = device_property_read_u32(dev, "clock-frequency", &config_khz);
if (ret < 0)
config_khz = MLXBF_I2C_TIMING_100KHZ;
config_khz = I2C_MAX_STANDARD_MODE_FREQ;
switch (config_khz) {
default:
@ -1210,15 +1204,15 @@ static int mlxbf_i2c_init_timings(struct platform_device *pdev,
pr_warn("Illegal value %d: defaulting to 100 KHz\n",
config_khz);
fallthrough;
case MLXBF_I2C_TIMING_100KHZ:
case I2C_MAX_STANDARD_MODE_FREQ:
config_idx = MLXBF_I2C_TIMING_CONFIG_100KHZ;
break;
case MLXBF_I2C_TIMING_400KHZ:
case I2C_MAX_FAST_MODE_FREQ:
config_idx = MLXBF_I2C_TIMING_CONFIG_400KHZ;
break;
case MLXBF_I2C_TIMING_1000KHZ:
case I2C_MAX_FAST_MODE_PLUS_FREQ:
config_idx = MLXBF_I2C_TIMING_CONFIG_1000KHZ;
break;
}
@ -2376,6 +2370,8 @@ static int mlxbf_i2c_probe(struct platform_device *pdev)
mlxbf_i2c_init_slave(pdev, priv);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
ret = devm_request_irq(dev, irq, mlxbf_smbus_irq,
IRQF_ONESHOT | IRQF_SHARED | IRQF_PROBE_SHARED,
dev_name(dev), priv);

View File

@ -1,16 +1,11 @@
// SPDX-License-Identifier: GPL-2.0
/*
* (C) Copyright 2003-2004
* Humboldt Solutions Ltd, adrian@humboldt.co.uk.
* This is a combined i2c adapter and algorithm driver for the
* MPC107/Tsi107 PowerPC northbridge and processors that include
* the same I2C unit (8240, 8245, 85xx).
*
* Release 0.8
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
* Copyright (C) 2003-2004 Humboldt Solutions Ltd, adrian@humboldt.co.uk
* Copyright (C) 2021 Allied Telesis Labs
*/
#include <linux/kernel.h>
@ -19,6 +14,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/clk.h>
@ -58,18 +54,50 @@
#define CSR_MIF 0x02
#define CSR_RXAK 0x01
enum mpc_i2c_action {
MPC_I2C_ACTION_START = 1,
MPC_I2C_ACTION_RESTART,
MPC_I2C_ACTION_READ_BEGIN,
MPC_I2C_ACTION_READ_BYTE,
MPC_I2C_ACTION_WRITE,
MPC_I2C_ACTION_STOP,
__MPC_I2C_ACTION_CNT
};
static const char * const action_str[] = {
"invalid",
"start",
"restart",
"read begin",
"read",
"write",
"stop",
};
static_assert(ARRAY_SIZE(action_str) == __MPC_I2C_ACTION_CNT);
struct mpc_i2c {
struct device *dev;
void __iomem *base;
u32 interrupt;
wait_queue_head_t queue;
wait_queue_head_t waitq;
spinlock_t lock;
struct i2c_adapter adap;
int irq;
u32 real_clk;
#ifdef CONFIG_PM_SLEEP
u8 fdr, dfsrr;
#endif
struct clk *clk_per;
u32 cntl_bits;
enum mpc_i2c_action action;
struct i2c_msg *msgs;
int num_msgs;
int curr_msg;
u32 byte_posn;
u32 block;
int rc;
int expect_rxack;
};
struct mpc_i2c_divider {
@ -86,19 +114,6 @@ static inline void writeccr(struct mpc_i2c *i2c, u32 x)
writeb(x, i2c->base + MPC_I2C_CR);
}
static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
{
struct mpc_i2c *i2c = dev_id;
if (readb(i2c->base + MPC_I2C_SR) & CSR_MIF) {
/* Read again to allow register to stabilise */
i2c->interrupt = readb(i2c->base + MPC_I2C_SR);
writeb(0, i2c->base + MPC_I2C_SR);
wake_up(&i2c->queue);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
/* Sometimes 9th clock pulse isn't generated, and slave doesn't release
* the bus, because it wants to send ACK.
* Following sequence of enabling/disabling and sending start/stop generates
@ -121,61 +136,6 @@ static void mpc_i2c_fixup(struct mpc_i2c *i2c)
}
}
static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
{
unsigned long orig_jiffies = jiffies;
u32 cmd_err;
int result = 0;
if (!i2c->irq) {
while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
schedule();
if (time_after(jiffies, orig_jiffies + timeout)) {
dev_dbg(i2c->dev, "timeout\n");
writeccr(i2c, 0);
result = -ETIMEDOUT;
break;
}
}
cmd_err = readb(i2c->base + MPC_I2C_SR);
writeb(0, i2c->base + MPC_I2C_SR);
} else {
/* Interrupt mode */
result = wait_event_timeout(i2c->queue,
(i2c->interrupt & CSR_MIF), timeout);
if (unlikely(!(i2c->interrupt & CSR_MIF))) {
dev_dbg(i2c->dev, "wait timeout\n");
writeccr(i2c, 0);
result = -ETIMEDOUT;
}
cmd_err = i2c->interrupt;
i2c->interrupt = 0;
}
if (result < 0)
return result;
if (!(cmd_err & CSR_MCF)) {
dev_dbg(i2c->dev, "unfinished\n");
return -EIO;
}
if (cmd_err & CSR_MAL) {
dev_dbg(i2c->dev, "MAL\n");
return -EAGAIN;
}
if (writing && (cmd_err & CSR_RXAK)) {
dev_dbg(i2c->dev, "No RXAK\n");
/* generate stop */
writeccr(i2c, CCR_MEN);
return -ENXIO;
}
return 0;
}
#if defined(CONFIG_PPC_MPC52xx) || defined(CONFIG_PPC_MPC512x)
static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = {
{20, 0x20}, {22, 0x21}, {24, 0x22}, {26, 0x23},
@ -415,7 +375,7 @@ static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
}
*real_clk = fsl_get_sys_freq() / prescaler / div->divider;
return div ? (int)div->fdr : -EINVAL;
return (int)div->fdr;
}
static void mpc_i2c_setup_8xxx(struct device_node *node,
@ -450,168 +410,209 @@ static void mpc_i2c_setup_8xxx(struct device_node *node,
}
#endif /* CONFIG_FSL_SOC */
static void mpc_i2c_start(struct mpc_i2c *i2c)
static void mpc_i2c_finish(struct mpc_i2c *i2c, int rc)
{
/* Clear arbitration */
writeb(0, i2c->base + MPC_I2C_SR);
/* Start with MEN */
writeccr(i2c, CCR_MEN);
i2c->rc = rc;
i2c->block = 0;
i2c->cntl_bits = CCR_MEN;
writeccr(i2c, i2c->cntl_bits);
wake_up(&i2c->waitq);
}
static void mpc_i2c_stop(struct mpc_i2c *i2c)
static void mpc_i2c_do_action(struct mpc_i2c *i2c)
{
writeccr(i2c, CCR_MEN);
}
struct i2c_msg *msg = &i2c->msgs[i2c->curr_msg];
int dir = 0;
int recv_len = 0;
u8 byte;
static int mpc_write(struct mpc_i2c *i2c, int target,
const u8 *data, int length, int restart)
{
int i, result;
unsigned timeout = i2c->adap.timeout;
u32 flags = restart ? CCR_RSTA : 0;
dev_dbg(i2c->dev, "action = %s\n", action_str[i2c->action]);
/* Start as master */
writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
/* Write target byte */
writeb((target << 1), i2c->base + MPC_I2C_DR);
i2c->cntl_bits &= ~(CCR_RSTA | CCR_MTX | CCR_TXAK);
result = i2c_wait(i2c, timeout, 1);
if (result < 0)
return result;
if (msg->flags & I2C_M_RD)
dir = 1;
if (msg->flags & I2C_M_RECV_LEN)
recv_len = 1;
for (i = 0; i < length; i++) {
/* Write data byte */
writeb(data[i], i2c->base + MPC_I2C_DR);
switch (i2c->action) {
case MPC_I2C_ACTION_RESTART:
i2c->cntl_bits |= CCR_RSTA;
fallthrough;
result = i2c_wait(i2c, timeout, 1);
if (result < 0)
return result;
}
case MPC_I2C_ACTION_START:
i2c->cntl_bits |= CCR_MSTA | CCR_MTX;
writeccr(i2c, i2c->cntl_bits);
writeb((msg->addr << 1) | dir, i2c->base + MPC_I2C_DR);
i2c->expect_rxack = 1;
i2c->action = dir ? MPC_I2C_ACTION_READ_BEGIN : MPC_I2C_ACTION_WRITE;
break;
return 0;
}
case MPC_I2C_ACTION_READ_BEGIN:
if (msg->len) {
if (msg->len == 1 && !(msg->flags & I2C_M_RECV_LEN))
i2c->cntl_bits |= CCR_TXAK;
static int mpc_read(struct mpc_i2c *i2c, int target,
u8 *data, int length, int restart, bool recv_len)
{
unsigned timeout = i2c->adap.timeout;
int i, result;
u32 flags = restart ? CCR_RSTA : 0;
writeccr(i2c, i2c->cntl_bits);
/* Dummy read */
readb(i2c->base + MPC_I2C_DR);
}
i2c->action = MPC_I2C_ACTION_READ_BYTE;
break;
/* Switch to read - restart */
writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
/* Write target address byte - this time with the read flag set */
writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);
result = i2c_wait(i2c, timeout, 1);
if (result < 0)
return result;
if (length) {
if (length == 1 && !recv_len)
writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
else
writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA);
/* Dummy read */
readb(i2c->base + MPC_I2C_DR);
}
for (i = 0; i < length; i++) {
u8 byte;
result = i2c_wait(i2c, timeout, 0);
if (result < 0)
return result;
/*
* For block reads, we have to know the total length (1st byte)
* before we can determine if we are done.
*/
if (i || !recv_len) {
/* Generate txack on next to last byte */
if (i == length - 2)
writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA
| CCR_TXAK);
case MPC_I2C_ACTION_READ_BYTE:
if (i2c->byte_posn || !recv_len) {
/* Generate Tx ACK on next to last byte */
if (i2c->byte_posn == msg->len - 2)
i2c->cntl_bits |= CCR_TXAK;
/* Do not generate stop on last byte */
if (i == length - 1)
writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA
| CCR_MTX);
if (i2c->byte_posn == msg->len - 1)
i2c->cntl_bits |= CCR_MTX;
writeccr(i2c, i2c->cntl_bits);
}
byte = readb(i2c->base + MPC_I2C_DR);
/*
* Adjust length if first received byte is length.
* The length is 1 length byte plus actually data length
*/
if (i == 0 && recv_len) {
if (byte == 0 || byte > I2C_SMBUS_BLOCK_MAX)
return -EPROTO;
length += byte;
if (i2c->byte_posn == 0 && recv_len) {
if (byte == 0 || byte > I2C_SMBUS_BLOCK_MAX) {
mpc_i2c_finish(i2c, -EPROTO);
return;
}
msg->len += byte;
/*
* For block reads, generate txack here if data length
* For block reads, generate Tx ACK here if data length
* is 1 byte (total length is 2 bytes).
*/
if (length == 2)
writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA
| CCR_TXAK);
if (msg->len == 2) {
i2c->cntl_bits |= CCR_TXAK;
writeccr(i2c, i2c->cntl_bits);
}
}
data[i] = byte;
dev_dbg(i2c->dev, "%s %02x\n", action_str[i2c->action], byte);
msg->buf[i2c->byte_posn++] = byte;
break;
case MPC_I2C_ACTION_WRITE:
dev_dbg(i2c->dev, "%s %02x\n", action_str[i2c->action],
msg->buf[i2c->byte_posn]);
writeb(msg->buf[i2c->byte_posn++], i2c->base + MPC_I2C_DR);
i2c->expect_rxack = 1;
break;
case MPC_I2C_ACTION_STOP:
mpc_i2c_finish(i2c, 0);
break;
default:
WARN(1, "Unexpected action %d\n", i2c->action);
break;
}
return length;
if (msg->len == i2c->byte_posn) {
i2c->curr_msg++;
i2c->byte_posn = 0;
if (i2c->curr_msg == i2c->num_msgs) {
i2c->action = MPC_I2C_ACTION_STOP;
/*
* We don't get another interrupt on read so
* finish the transfer now
*/
if (dir)
mpc_i2c_finish(i2c, 0);
} else {
i2c->action = MPC_I2C_ACTION_RESTART;
}
}
}
static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
static void mpc_i2c_do_intr(struct mpc_i2c *i2c, u8 status)
{
struct i2c_msg *pmsg;
int i;
int ret = 0;
unsigned long orig_jiffies = jiffies;
struct mpc_i2c *i2c = i2c_get_adapdata(adap);
spin_lock(&i2c->lock);
mpc_i2c_start(i2c);
/* Allow bus up to 1s to become not busy */
while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
if (signal_pending(current)) {
dev_dbg(i2c->dev, "Interrupted\n");
writeccr(i2c, 0);
return -EINTR;
}
if (time_after(jiffies, orig_jiffies + HZ)) {
u8 status = readb(i2c->base + MPC_I2C_SR);
dev_dbg(i2c->dev, "timeout\n");
if ((status & (CSR_MCF | CSR_MBB | CSR_RXAK)) != 0) {
writeb(status & ~CSR_MAL,
i2c->base + MPC_I2C_SR);
mpc_i2c_fixup(i2c);
}
return -EIO;
}
schedule();
if (!(status & CSR_MCF)) {
dev_dbg(i2c->dev, "unfinished\n");
mpc_i2c_finish(i2c, -EIO);
goto out;
}
for (i = 0; ret >= 0 && i < num; i++) {
pmsg = &msgs[i];
dev_dbg(i2c->dev,
"Doing %s %d bytes to 0x%02x - %d of %d messages\n",
pmsg->flags & I2C_M_RD ? "read" : "write",
pmsg->len, pmsg->addr, i + 1, num);
if (pmsg->flags & I2C_M_RD) {
bool recv_len = pmsg->flags & I2C_M_RECV_LEN;
ret = mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i,
recv_len);
if (recv_len && ret > 0)
pmsg->len = ret;
} else {
ret =
mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
}
if (status & CSR_MAL) {
dev_dbg(i2c->dev, "arbitration lost\n");
mpc_i2c_finish(i2c, -EAGAIN);
goto out;
}
mpc_i2c_stop(i2c); /* Initiate STOP */
if (i2c->expect_rxack && (status & CSR_RXAK)) {
dev_dbg(i2c->dev, "no Rx ACK\n");
mpc_i2c_finish(i2c, -ENXIO);
goto out;
}
i2c->expect_rxack = 0;
mpc_i2c_do_action(i2c);
out:
spin_unlock(&i2c->lock);
}
static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
{
struct mpc_i2c *i2c = dev_id;
u8 status;
status = readb(i2c->base + MPC_I2C_SR);
if (status & CSR_MIF) {
writeb(0, i2c->base + MPC_I2C_SR);
mpc_i2c_do_intr(i2c, status);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
static int mpc_i2c_wait_for_completion(struct mpc_i2c *i2c)
{
long time_left;
time_left = wait_event_timeout(i2c->waitq, !i2c->block, i2c->adap.timeout);
if (!time_left)
return -ETIMEDOUT;
if (time_left < 0)
return time_left;
return 0;
}
static int mpc_i2c_execute_msg(struct mpc_i2c *i2c)
{
unsigned long orig_jiffies;
unsigned long flags;
int ret;
spin_lock_irqsave(&i2c->lock, flags);
i2c->curr_msg = 0;
i2c->rc = 0;
i2c->byte_posn = 0;
i2c->block = 1;
i2c->action = MPC_I2C_ACTION_START;
i2c->cntl_bits = CCR_MEN | CCR_MIEN;
writeb(0, i2c->base + MPC_I2C_SR);
writeccr(i2c, i2c->cntl_bits);
mpc_i2c_do_action(i2c);
spin_unlock_irqrestore(&i2c->lock, flags);
ret = mpc_i2c_wait_for_completion(i2c);
if (ret)
i2c->rc = ret;
if (i2c->rc == -EIO || i2c->rc == -EAGAIN || i2c->rc == -ETIMEDOUT)
i2c_recover_bus(&i2c->adap);
orig_jiffies = jiffies;
/* Wait until STOP is seen, allow up to 1 s */
while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
@ -622,13 +623,41 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
if ((status & (CSR_MCF | CSR_MBB | CSR_RXAK)) != 0) {
writeb(status & ~CSR_MAL,
i2c->base + MPC_I2C_SR);
mpc_i2c_fixup(i2c);
i2c_recover_bus(&i2c->adap);
}
return -EIO;
}
cond_resched();
}
return (ret < 0) ? ret : num;
return i2c->rc;
}
static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
int rc, ret = num;
struct mpc_i2c *i2c = i2c_get_adapdata(adap);
int i;
dev_dbg(i2c->dev, "num = %d\n", num);
for (i = 0; i < num; i++)
dev_dbg(i2c->dev, " addr = %02x, flags = %02x, len = %d, %*ph\n",
msgs[i].addr, msgs[i].flags, msgs[i].len,
msgs[i].flags & I2C_M_RD ? 0 : msgs[i].len,
msgs[i].buf);
WARN_ON(i2c->msgs != NULL);
i2c->msgs = msgs;
i2c->num_msgs = num;
rc = mpc_i2c_execute_msg(i2c);
if (rc < 0)
ret = rc;
i2c->num_msgs = 0;
i2c->msgs = NULL;
return ret;
}
static u32 mpc_functionality(struct i2c_adapter *adap)
@ -637,6 +666,15 @@ static u32 mpc_functionality(struct i2c_adapter *adap)
| I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL;
}
static int fsl_i2c_bus_recovery(struct i2c_adapter *adap)
{
struct mpc_i2c *i2c = i2c_get_adapdata(adap);
mpc_i2c_fixup(i2c);
return 0;
}
static const struct i2c_algorithm mpc_algo = {
.master_xfer = mpc_xfer,
.functionality = mpc_functionality,
@ -648,63 +686,61 @@ static struct i2c_adapter mpc_ops = {
.timeout = HZ,
};
static const struct of_device_id mpc_i2c_of_match[];
static struct i2c_bus_recovery_info fsl_i2c_recovery_info = {
.recover_bus = fsl_i2c_bus_recovery,
};
static int fsl_i2c_probe(struct platform_device *op)
{
const struct of_device_id *match;
const struct mpc_i2c_data *data;
struct mpc_i2c *i2c;
const u32 *prop;
u32 clock = MPC_I2C_CLOCK_LEGACY;
int result = 0;
int plen;
struct resource res;
struct clk *clk;
int err;
match = of_match_device(mpc_i2c_of_match, &op->dev);
if (!match)
return -EINVAL;
i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
i2c = devm_kzalloc(&op->dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
i2c->dev = &op->dev; /* for debug and error output */
init_waitqueue_head(&i2c->queue);
init_waitqueue_head(&i2c->waitq);
spin_lock_init(&i2c->lock);
i2c->base = of_iomap(op->dev.of_node, 0);
if (!i2c->base) {
dev_err(i2c->dev, "failed to map controller\n");
result = -ENOMEM;
goto fail_map;
}
i2c->base = devm_platform_ioremap_resource(op, 0);
if (IS_ERR(i2c->base))
return PTR_ERR(i2c->base);
i2c->irq = irq_of_parse_and_map(op->dev.of_node, 0);
if (i2c->irq) { /* no i2c->irq implies polling */
result = request_irq(i2c->irq, mpc_i2c_isr,
IRQF_SHARED, "i2c-mpc", i2c);
if (result < 0) {
dev_err(i2c->dev, "failed to attach interrupt\n");
goto fail_request;
}
i2c->irq = platform_get_irq(op, 0);
if (i2c->irq < 0)
return i2c->irq;
result = devm_request_irq(&op->dev, i2c->irq, mpc_i2c_isr,
IRQF_SHARED, "i2c-mpc", i2c);
if (result < 0) {
dev_err(i2c->dev, "failed to attach interrupt\n");
return result;
}
/*
* enable clock for the I2C peripheral (non fatal),
* keep a reference upon successful allocation
*/
clk = devm_clk_get(&op->dev, NULL);
if (!IS_ERR(clk)) {
err = clk_prepare_enable(clk);
if (err) {
dev_err(&op->dev, "failed to enable clock\n");
goto fail_request;
} else {
i2c->clk_per = clk;
}
clk = devm_clk_get_optional(&op->dev, NULL);
if (IS_ERR(clk))
return PTR_ERR(clk);
err = clk_prepare_enable(clk);
if (err) {
dev_err(&op->dev, "failed to enable clock\n");
return err;
}
i2c->clk_per = clk;
if (of_property_read_bool(op->dev.of_node, "fsl,preserve-clocking")) {
clock = MPC_I2C_CLOCK_PRESERVE;
} else {
@ -714,8 +750,8 @@ static int fsl_i2c_probe(struct platform_device *op)
clock = *prop;
}
if (match->data) {
const struct mpc_i2c_data *data = match->data;
data = device_get_match_data(&op->dev);
if (data) {
data->setup(op->dev.of_node, i2c, clock);
} else {
/* Backwards compatibility */
@ -731,31 +767,25 @@ static int fsl_i2c_probe(struct platform_device *op)
}
dev_info(i2c->dev, "timeout %u us\n", mpc_ops.timeout * 1000000 / HZ);
platform_set_drvdata(op, i2c);
i2c->adap = mpc_ops;
of_address_to_resource(op->dev.of_node, 0, &res);
scnprintf(i2c->adap.name, sizeof(i2c->adap.name),
"MPC adapter at 0x%llx", (unsigned long long)res.start);
i2c_set_adapdata(&i2c->adap, i2c);
"MPC adapter (%s)", of_node_full_name(op->dev.of_node));
i2c->adap.dev.parent = &op->dev;
i2c->adap.nr = op->id;
i2c->adap.dev.of_node = of_node_get(op->dev.of_node);
i2c->adap.bus_recovery_info = &fsl_i2c_recovery_info;
platform_set_drvdata(op, i2c);
i2c_set_adapdata(&i2c->adap, i2c);
result = i2c_add_adapter(&i2c->adap);
if (result < 0)
result = i2c_add_numbered_adapter(&i2c->adap);
if (result)
goto fail_add;
return result;
return 0;
fail_add:
if (i2c->clk_per)
clk_disable_unprepare(i2c->clk_per);
free_irq(i2c->irq, i2c);
fail_request:
irq_dispose_mapping(i2c->irq);
iounmap(i2c->base);
fail_map:
kfree(i2c);
clk_disable_unprepare(i2c->clk_per);
return result;
};
@ -765,20 +795,12 @@ static int fsl_i2c_remove(struct platform_device *op)
i2c_del_adapter(&i2c->adap);
if (i2c->clk_per)
clk_disable_unprepare(i2c->clk_per);
clk_disable_unprepare(i2c->clk_per);
if (i2c->irq)
free_irq(i2c->irq, i2c);
irq_dispose_mapping(i2c->irq);
iounmap(i2c->base);
kfree(i2c);
return 0;
};
#ifdef CONFIG_PM_SLEEP
static int mpc_i2c_suspend(struct device *dev)
static int __maybe_unused mpc_i2c_suspend(struct device *dev)
{
struct mpc_i2c *i2c = dev_get_drvdata(dev);
@ -788,7 +810,7 @@ static int mpc_i2c_suspend(struct device *dev)
return 0;
}
static int mpc_i2c_resume(struct device *dev)
static int __maybe_unused mpc_i2c_resume(struct device *dev)
{
struct mpc_i2c *i2c = dev_get_drvdata(dev);
@ -797,12 +819,7 @@ static int mpc_i2c_resume(struct device *dev)
return 0;
}
static SIMPLE_DEV_PM_OPS(mpc_i2c_pm_ops, mpc_i2c_suspend, mpc_i2c_resume);
#define MPC_I2C_PM_OPS (&mpc_i2c_pm_ops)
#else
#define MPC_I2C_PM_OPS NULL
#endif
static const struct mpc_i2c_data mpc_i2c_data_512x = {
.setup = mpc_i2c_setup_512x,
@ -845,7 +862,7 @@ static struct platform_driver mpc_i2c_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = mpc_i2c_of_match,
.pm = MPC_I2C_PM_OPS,
.pm = &mpc_i2c_pm_ops,
},
};

View File

@ -231,6 +231,7 @@ struct mtk_i2c {
struct i2c_adapter adap; /* i2c host adapter */
struct device *dev;
struct completion msg_complete;
struct i2c_timings timing_info;
/* set in i2c probe */
void __iomem *base; /* i2c base addr */
@ -479,7 +480,7 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c)
{
u16 control_reg;
if (i2c->dev_comp->dma_sync) {
if (i2c->dev_comp->apdma_sync) {
writel(I2C_DMA_WARM_RST, i2c->pdmabase + OFFSET_RST);
udelay(10);
writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_RST);
@ -564,7 +565,7 @@ static const struct i2c_spec_values *mtk_i2c_get_spec(unsigned int speed)
static int mtk_i2c_max_step_cnt(unsigned int target_speed)
{
if (target_speed > I2C_MAX_FAST_MODE_FREQ)
if (target_speed > I2C_MAX_FAST_MODE_PLUS_FREQ)
return MAX_HS_STEP_CNT_DIV;
else
return MAX_STEP_CNT_DIV;
@ -607,7 +608,8 @@ static int mtk_i2c_check_ac_timing(struct mtk_i2c *i2c,
else
clk_ns = sample_ns / 2;
su_sta_cnt = DIV_ROUND_UP(spec->min_su_sta_ns, clk_ns);
su_sta_cnt = DIV_ROUND_UP(spec->min_su_sta_ns +
i2c->timing_info.scl_int_delay_ns, clk_ns);
if (su_sta_cnt > max_sta_cnt)
return -1;
@ -635,7 +637,7 @@ static int mtk_i2c_check_ac_timing(struct mtk_i2c *i2c,
if (sda_min > sda_max)
return -3;
if (check_speed > I2C_MAX_FAST_MODE_FREQ) {
if (check_speed > I2C_MAX_FAST_MODE_PLUS_FREQ) {
if (i2c->dev_comp->ltiming_adjust) {
i2c->ac_timing.hs = I2C_TIME_DEFAULT_VALUE |
(sample_cnt << 12) | (high_cnt << 8);
@ -850,7 +852,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
control_reg = mtk_i2c_readw(i2c, OFFSET_CONTROL) &
~(I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS);
if ((i2c->speed_hz > I2C_MAX_FAST_MODE_FREQ) || (left_num >= 1))
if ((i2c->speed_hz > I2C_MAX_FAST_MODE_PLUS_FREQ) || (left_num >= 1))
control_reg |= I2C_CONTROL_RS;
if (i2c->op == I2C_MASTER_WRRD)
@ -1067,7 +1069,8 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
}
}
if (i2c->auto_restart && num >= 2 && i2c->speed_hz > I2C_MAX_FAST_MODE_FREQ)
if (i2c->auto_restart && num >= 2 &&
i2c->speed_hz > I2C_MAX_FAST_MODE_PLUS_FREQ)
/* ignore the first restart irq after the master code,
* otherwise the first transfer will be discarded.
*/
@ -1175,6 +1178,8 @@ static int mtk_i2c_parse_dt(struct device_node *np, struct mtk_i2c *i2c)
i2c->use_push_pull =
of_property_read_bool(np, "mediatek,use-push-pull");
i2c_parse_fw_timings(i2c->dev, &i2c->timing_info, true);
return 0;
}

View File

@ -277,7 +277,7 @@ static int init_hw(struct nmk_i2c_dev *dev)
goto exit;
/* disable the controller */
i2c_clr_bit(dev->virtbase + I2C_CR , I2C_CR_PE);
i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
disable_all_interrupts(dev);
@ -525,7 +525,7 @@ static int write_i2c(struct nmk_i2c_dev *dev, u16 flags)
dev->virtbase + I2C_CR);
/* enable the controller */
i2c_set_bit(dev->virtbase + I2C_CR , I2C_CR_PE);
i2c_set_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
init_completion(&dev->xfer_complete);

View File

@ -262,6 +262,10 @@ static const struct property_entry ccgx_props[] = {
{ }
};
static const struct software_node ccgx_node = {
.properties = ccgx_props,
};
static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq)
{
i2cd->gpu_ccgx_ucsi = devm_kzalloc(i2cd->dev,
@ -274,7 +278,7 @@ static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq)
sizeof(i2cd->gpu_ccgx_ucsi->type));
i2cd->gpu_ccgx_ucsi->addr = 0x8;
i2cd->gpu_ccgx_ucsi->irq = irq;
i2cd->gpu_ccgx_ucsi->properties = ccgx_props;
i2cd->gpu_ccgx_ucsi->swnode = &ccgx_node;
i2cd->ccgx_client = i2c_new_client_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
return PTR_ERR_OR_ZERO(i2cd->ccgx_client);
}

View File

@ -1404,9 +1404,9 @@ omap_i2c_probe(struct platform_device *pdev)
pm_runtime_set_autosuspend_delay(omap->dev, OMAP_I2C_PM_TIMEOUT);
pm_runtime_use_autosuspend(omap->dev);
r = pm_runtime_get_sync(omap->dev);
r = pm_runtime_resume_and_get(omap->dev);
if (r < 0)
goto err_free_mem;
goto err_disable_pm;
/*
* Read the Rev hi bit-[15:14] ie scheme this is 1 indicates ver2.
@ -1513,8 +1513,8 @@ err_unuse_clocks:
omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0);
pm_runtime_dont_use_autosuspend(omap->dev);
pm_runtime_put_sync(omap->dev);
err_disable_pm:
pm_runtime_disable(&pdev->dev);
err_free_mem:
return r;
}
@ -1525,7 +1525,7 @@ static int omap_i2c_remove(struct platform_device *pdev)
int ret;
i2c_del_adapter(&omap->adapter);
ret = pm_runtime_get_sync(&pdev->dev);
ret = pm_runtime_resume_and_get(&pdev->dev);
if (ret < 0)
return ret;

View File

@ -76,11 +76,6 @@ static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap,
* but I think the current API makes no sense and I don't want
* any driver that I haven't verified for correctness to go
* anywhere near a pmac i2c bus anyway ...
*
* I'm also not completely sure what kind of phases to do between
* the actual command and the data (what I am _supposed_ to do that
* is). For now, I assume writes are a single stream and reads have
* a repeat start/addr phase (but not stop in between)
*/
case I2C_SMBUS_BLOCK_DATA:
buf = data->block;

View File

@ -569,9 +569,9 @@ static int cci_probe(struct platform_device *pdev)
cci->master[idx].mode = I2C_MODE_STANDARD;
ret = of_property_read_u32(child, "clock-frequency", &val);
if (!ret) {
if (val == 400000)
if (val == I2C_MAX_FAST_MODE_FREQ)
cci->master[idx].mode = I2C_MODE_FAST;
else if (val == 1000000)
else if (val == I2C_MAX_FAST_MODE_PLUS_FREQ)
cci->master[idx].mode = I2C_MODE_FAST_PLUS;
}

View File

@ -141,6 +141,7 @@ struct rcar_i2c_priv {
enum dma_data_direction dma_direction;
struct reset_control *rstc;
bool atomic_xfer;
int irq;
struct i2c_client *host_notify_client;
@ -353,7 +354,9 @@ static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv)
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
rcar_i2c_write(priv, ICMSR, 0);
}
rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND);
if (!priv->atomic_xfer)
rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND);
}
static void rcar_i2c_next_msg(struct rcar_i2c_priv *priv)
@ -418,7 +421,7 @@ static bool rcar_i2c_dma(struct rcar_i2c_priv *priv)
int len;
/* Do various checks to see if DMA is feasible at all */
if (IS_ERR(chan) || msg->len < RCAR_MIN_DMA_LEN ||
if (priv->atomic_xfer || IS_ERR(chan) || msg->len < RCAR_MIN_DMA_LEN ||
!(msg->flags & I2C_M_DMA_SAFE) || (read && priv->flags & ID_P_NO_RXDMA))
return false;
@ -646,7 +649,8 @@ static irqreturn_t rcar_i2c_irq(int irq, struct rcar_i2c_priv *priv, u32 msr)
/* Nack */
if (msr & MNR) {
/* HW automatically sends STOP after received NACK */
rcar_i2c_write(priv, ICMIER, RCAR_IRQ_STOP);
if (!priv->atomic_xfer)
rcar_i2c_write(priv, ICMIER, RCAR_IRQ_STOP);
priv->flags |= ID_NACK;
goto out;
}
@ -667,7 +671,8 @@ out:
if (priv->flags & ID_DONE) {
rcar_i2c_write(priv, ICMIER, 0);
rcar_i2c_write(priv, ICMSR, 0);
wake_up(&priv->wait);
if (!priv->atomic_xfer)
wake_up(&priv->wait);
}
return IRQ_HANDLED;
@ -684,7 +689,8 @@ static irqreturn_t rcar_i2c_gen2_irq(int irq, void *ptr)
/* Only handle interrupts that are currently enabled */
msr = rcar_i2c_read(priv, ICMSR);
msr &= rcar_i2c_read(priv, ICMIER);
if (!priv->atomic_xfer)
msr &= rcar_i2c_read(priv, ICMIER);
return rcar_i2c_irq(irq, priv, msr);
}
@ -696,7 +702,8 @@ static irqreturn_t rcar_i2c_gen3_irq(int irq, void *ptr)
/* Only handle interrupts that are currently enabled */
msr = rcar_i2c_read(priv, ICMSR);
msr &= rcar_i2c_read(priv, ICMIER);
if (!priv->atomic_xfer)
msr &= rcar_i2c_read(priv, ICMIER);
/*
* Clear START or STOP immediately, except for REPSTART after read or
@ -804,6 +811,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
int i, ret;
long time_left;
priv->atomic_xfer = false;
pm_runtime_get_sync(dev);
/* Check bus state before init otherwise bus busy info will be lost */
@ -858,6 +867,68 @@ out:
return ret;
}
static int rcar_i2c_master_xfer_atomic(struct i2c_adapter *adap,
struct i2c_msg *msgs,
int num)
{
struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
struct device *dev = rcar_i2c_priv_to_dev(priv);
unsigned long j;
bool time_left;
int ret;
priv->atomic_xfer = true;
pm_runtime_get_sync(dev);
/* Check bus state before init otherwise bus busy info will be lost */
ret = rcar_i2c_bus_barrier(priv);
if (ret < 0)
goto out;
rcar_i2c_init(priv);
/* init first message */
priv->msg = msgs;
priv->msgs_left = num;
priv->flags = (priv->flags & ID_P_MASK) | ID_FIRST_MSG;
rcar_i2c_prepare_msg(priv);
j = jiffies + num * adap->timeout;
do {
u32 msr = rcar_i2c_read(priv, ICMSR);
msr &= (rcar_i2c_is_recv(priv) ? RCAR_IRQ_RECV : RCAR_IRQ_SEND) | RCAR_IRQ_STOP;
if (msr) {
if (priv->devtype < I2C_RCAR_GEN3)
rcar_i2c_gen2_irq(0, priv);
else
rcar_i2c_gen3_irq(0, priv);
}
time_left = time_before_eq(jiffies, j);
} while (!(priv->flags & ID_DONE) && time_left);
if (!time_left) {
rcar_i2c_init(priv);
ret = -ETIMEDOUT;
} else if (priv->flags & ID_NACK) {
ret = -ENXIO;
} else if (priv->flags & ID_ARBLOST) {
ret = -EAGAIN;
} else {
ret = num - priv->msgs_left; /* The number of transfer */
}
out:
pm_runtime_put(dev);
if (ret < 0 && ret != -ENXIO)
dev_err(dev, "error %d : %x\n", ret, priv->flags);
return ret;
}
static int rcar_reg_slave(struct i2c_client *slave)
{
struct rcar_i2c_priv *priv = i2c_get_adapdata(slave->adapter);
@ -922,6 +993,7 @@ static u32 rcar_i2c_func(struct i2c_adapter *adap)
static const struct i2c_algorithm rcar_i2c_algo = {
.master_xfer = rcar_i2c_master_xfer,
.master_xfer_atomic = rcar_i2c_master_xfer_atomic,
.functionality = rcar_i2c_func,
.reg_slave = rcar_reg_slave,
.unreg_slave = rcar_unreg_slave,
@ -1027,7 +1099,10 @@ static int rcar_i2c_probe(struct platform_device *pdev)
if (of_property_read_bool(dev->of_node, "smbus"))
priv->flags |= ID_P_HOST_NOTIFY;
priv->irq = platform_get_irq(pdev, 0);
ret = platform_get_irq(pdev, 0);
if (ret < 0)
goto out_pm_disable;
priv->irq = ret;
ret = devm_request_irq(dev, priv->irq, irqhandler, irqflags, dev_name(dev), priv);
if (ret < 0) {
dev_err(dev, "cannot get irq %d\n", priv->irq);

View File

@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/gpio/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/mfd/syscon.h>
@ -156,12 +157,8 @@ MODULE_DEVICE_TABLE(of, s3c24xx_i2c_match);
*/
static inline kernel_ulong_t s3c24xx_get_device_quirks(struct platform_device *pdev)
{
if (pdev->dev.of_node) {
const struct of_device_id *match;
match = of_match_node(s3c24xx_i2c_match, pdev->dev.of_node);
return (kernel_ulong_t)match->data;
}
if (pdev->dev.of_node)
return (kernel_ulong_t)of_device_get_match_data(&pdev->dev);
return platform_get_device_id(pdev)->driver_data;
}

View File

@ -18,8 +18,6 @@
/* SMBUS HID definition as supported by Microsoft Windows */
#define ACPI_SMBUS_MS_HID "SMB0001"
ACPI_MODULE_NAME("smbus_cmi");
struct smbus_methods_t {
char *mt_info;
char *mt_sbr;

View File

@ -471,7 +471,10 @@ static int sh7760_i2c_probe(struct platform_device *pdev)
goto out2;
}
id->irq = platform_get_irq(pdev, 0);
ret = platform_get_irq(pdev, 0);
if (ret < 0)
goto out3;
id->irq = ret;
id->adap.nr = pdev->id;
id->adap.algo = &sh7760_i2c_algo;

View File

@ -290,7 +290,7 @@ static int sprd_i2c_master_xfer(struct i2c_adapter *i2c_adap,
struct sprd_i2c *i2c_dev = i2c_adap->algo_data;
int im, ret;
ret = pm_runtime_get_sync(i2c_dev->dev);
ret = pm_runtime_resume_and_get(i2c_dev->dev);
if (ret < 0)
return ret;
@ -576,7 +576,7 @@ static int sprd_i2c_remove(struct platform_device *pdev)
struct sprd_i2c *i2c_dev = platform_get_drvdata(pdev);
int ret;
ret = pm_runtime_get_sync(i2c_dev->dev);
ret = pm_runtime_resume_and_get(i2c_dev->dev);
if (ret < 0)
return ret;
@ -640,6 +640,7 @@ static const struct of_device_id sprd_i2c_of_match[] = {
{ .compatible = "sprd,sc9860-i2c", },
{},
};
MODULE_DEVICE_TABLE(of, sprd_i2c_of_match);
static struct platform_driver sprd_i2c_driver = {
.probe = sprd_i2c_probe,

View File

@ -164,7 +164,6 @@ enum {
#define STM32F7_I2C_DNF_DEFAULT 0
#define STM32F7_I2C_DNF_MAX 15
#define STM32F7_I2C_ANALOG_FILTER_ENABLE 1
#define STM32F7_I2C_ANALOG_FILTER_DELAY_MIN 50 /* ns */
#define STM32F7_I2C_ANALOG_FILTER_DELAY_MAX 260 /* ns */
@ -223,8 +222,6 @@ struct stm32f7_i2c_spec {
* @clock_src: I2C clock source frequency (Hz)
* @rise_time: Rise time (ns)
* @fall_time: Fall time (ns)
* @dnf: Digital filter coefficient (0-16)
* @analog_filter: Analog filter delay (On/Off)
* @fmp_clr_offset: Fast Mode Plus clear register offset from set register
*/
struct stm32f7_i2c_setup {
@ -232,8 +229,6 @@ struct stm32f7_i2c_setup {
u32 clock_src;
u32 rise_time;
u32 fall_time;
u8 dnf;
bool analog_filter;
u32 fmp_clr_offset;
};
@ -312,6 +307,9 @@ struct stm32f7_i2c_msg {
* @wakeup_src: boolean to know if the device is a wakeup source
* @smbus_mode: states that the controller is configured in SMBus mode
* @host_notify_client: SMBus host-notify client
* @analog_filter: boolean to indicate enabling of the analog filter
* @dnf_dt: value of digital filter requested via dt
* @dnf: value of digital filter to apply
*/
struct stm32f7_i2c_dev {
struct i2c_adapter adap;
@ -340,6 +338,9 @@ struct stm32f7_i2c_dev {
bool wakeup_src;
bool smbus_mode;
struct i2c_client *host_notify_client;
bool analog_filter;
u32 dnf_dt;
u32 dnf;
};
/*
@ -385,15 +386,11 @@ static struct stm32f7_i2c_spec stm32f7_i2c_specs[] = {
static const struct stm32f7_i2c_setup stm32f7_setup = {
.rise_time = STM32F7_I2C_RISE_TIME_DEFAULT,
.fall_time = STM32F7_I2C_FALL_TIME_DEFAULT,
.dnf = STM32F7_I2C_DNF_DEFAULT,
.analog_filter = STM32F7_I2C_ANALOG_FILTER_ENABLE,
};
static const struct stm32f7_i2c_setup stm32mp15_setup = {
.rise_time = STM32F7_I2C_RISE_TIME_DEFAULT,
.fall_time = STM32F7_I2C_FALL_TIME_DEFAULT,
.dnf = STM32F7_I2C_DNF_DEFAULT,
.analog_filter = STM32F7_I2C_ANALOG_FILTER_ENABLE,
.fmp_clr_offset = 0x40,
};
@ -462,27 +459,28 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
return -EINVAL;
}
if (setup->dnf > STM32F7_I2C_DNF_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",
setup->dnf, STM32F7_I2C_DNF_MAX);
i2c_dev->dnf * i2cclk, STM32F7_I2C_DNF_MAX * i2cclk);
return -EINVAL;
}
/* Analog and Digital Filters */
af_delay_min =
(setup->analog_filter ?
(i2c_dev->analog_filter ?
STM32F7_I2C_ANALOG_FILTER_DELAY_MIN : 0);
af_delay_max =
(setup->analog_filter ?
(i2c_dev->analog_filter ?
STM32F7_I2C_ANALOG_FILTER_DELAY_MAX : 0);
dnf_delay = setup->dnf * i2cclk;
dnf_delay = i2c_dev->dnf * i2cclk;
sdadel_min = specs->hddat_min + setup->fall_time -
af_delay_min - (setup->dnf + 3) * i2cclk;
af_delay_min - (i2c_dev->dnf + 3) * i2cclk;
sdadel_max = specs->vddat_max - setup->rise_time -
af_delay_max - (setup->dnf + 4) * i2cclk;
af_delay_max - (i2c_dev->dnf + 4) * i2cclk;
scldel_min = setup->rise_time + specs->sudat_min;
@ -648,6 +646,7 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
setup->speed_freq = t->bus_freq_hz;
i2c_dev->setup.rise_time = t->scl_rise_ns;
i2c_dev->setup.fall_time = t->scl_fall_ns;
i2c_dev->dnf_dt = t->digital_filter_width_ns;
setup->clock_src = clk_get_rate(i2c_dev->clk);
if (!setup->clock_src) {
@ -655,6 +654,9 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
return -EINVAL;
}
if (!of_property_read_bool(i2c_dev->dev->of_node, "i2c-digital-filter"))
i2c_dev->dnf_dt = STM32F7_I2C_DNF_DEFAULT;
do {
ret = stm32f7_i2c_compute_timing(i2c_dev, setup,
&i2c_dev->timing);
@ -676,12 +678,15 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
return ret;
}
i2c_dev->analog_filter = of_property_read_bool(i2c_dev->dev->of_node,
"i2c-analog-filter");
dev_dbg(i2c_dev->dev, "I2C Speed(%i), Clk Source(%i)\n",
setup->speed_freq, setup->clock_src);
dev_dbg(i2c_dev->dev, "I2C Rise(%i) and Fall(%i) Time\n",
setup->rise_time, setup->fall_time);
dev_dbg(i2c_dev->dev, "I2C Analog Filter(%s), DNF(%i)\n",
(setup->analog_filter ? "On" : "Off"), setup->dnf);
(i2c_dev->analog_filter ? "On" : "Off"), i2c_dev->dnf);
i2c_dev->bus_rate = setup->speed_freq;
@ -720,8 +725,8 @@ static void stm32f7_i2c_hw_config(struct stm32f7_i2c_dev *i2c_dev)
timing |= STM32F7_I2C_TIMINGR_SCLL(t->scll);
writel_relaxed(timing, i2c_dev->base + STM32F7_I2C_TIMINGR);
/* Enable I2C */
if (i2c_dev->setup.analog_filter)
/* Configure the Analog Filter */
if (i2c_dev->analog_filter)
stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
STM32F7_I2C_CR1_ANFOFF);
else
@ -732,7 +737,7 @@ static void stm32f7_i2c_hw_config(struct stm32f7_i2c_dev *i2c_dev)
stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
STM32F7_I2C_CR1_DNF_MASK);
stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
STM32F7_I2C_CR1_DNF(i2c_dev->setup.dnf));
STM32F7_I2C_CR1_DNF(i2c_dev->dnf));
stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
STM32F7_I2C_CR1_PE);
@ -1597,7 +1602,8 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data)
/* Bus error */
if (status & STM32F7_I2C_ISR_BERR) {
dev_err(dev, "<%s>: Bus error\n", __func__);
dev_err(dev, "<%s>: Bus error accessing addr 0x%x\n",
__func__, f7_msg->addr);
writel_relaxed(STM32F7_I2C_ICR_BERRCF, base + STM32F7_I2C_ICR);
stm32f7_i2c_release_bus(&i2c_dev->adap);
f7_msg->result = -EIO;
@ -1605,13 +1611,15 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data)
/* Arbitration loss */
if (status & STM32F7_I2C_ISR_ARLO) {
dev_dbg(dev, "<%s>: Arbitration loss\n", __func__);
dev_dbg(dev, "<%s>: Arbitration loss accessing addr 0x%x\n",
__func__, f7_msg->addr);
writel_relaxed(STM32F7_I2C_ICR_ARLOCF, base + STM32F7_I2C_ICR);
f7_msg->result = -EAGAIN;
}
if (status & STM32F7_I2C_ISR_PECERR) {
dev_err(dev, "<%s>: PEC error in reception\n", __func__);
dev_err(dev, "<%s>: PEC error in reception accessing addr 0x%x\n",
__func__, f7_msg->addr);
writel_relaxed(STM32F7_I2C_ICR_PECCF, base + STM32F7_I2C_ICR);
f7_msg->result = -EINVAL;
}
@ -1652,7 +1660,7 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap,
i2c_dev->msg_id = 0;
f7_msg->smbus = false;
ret = pm_runtime_get_sync(i2c_dev->dev);
ret = pm_runtime_resume_and_get(i2c_dev->dev);
if (ret < 0)
return ret;
@ -1698,7 +1706,7 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
f7_msg->read_write = read_write;
f7_msg->smbus = true;
ret = pm_runtime_get_sync(dev);
ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
return ret;
@ -1799,7 +1807,7 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
if (ret)
return ret;
ret = pm_runtime_get_sync(dev);
ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
return ret;
@ -1880,7 +1888,7 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave)
WARN_ON(!i2c_dev->slave[id]);
ret = pm_runtime_get_sync(i2c_dev->dev);
ret = pm_runtime_resume_and_get(i2c_dev->dev);
if (ret < 0)
return ret;
@ -2027,12 +2035,8 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
phy_addr = (dma_addr_t)res->start;
irq_event = platform_get_irq(pdev, 0);
if (irq_event <= 0) {
if (irq_event != -EPROBE_DEFER)
dev_err(&pdev->dev, "Failed to get IRQ event: %d\n",
irq_event);
if (irq_event <= 0)
return irq_event ? : -ENOENT;
}
irq_error = platform_get_irq(pdev, 1);
if (irq_error <= 0)
@ -2267,13 +2271,12 @@ static int __maybe_unused stm32f7_i2c_runtime_resume(struct device *dev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev)
static int __maybe_unused stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev)
{
int ret;
struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs;
ret = pm_runtime_get_sync(i2c_dev->dev);
ret = pm_runtime_resume_and_get(i2c_dev->dev);
if (ret < 0)
return ret;
@ -2289,13 +2292,13 @@ static int stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev)
return ret;
}
static int stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev)
static int __maybe_unused stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev)
{
u32 cr1;
int ret;
struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs;
ret = pm_runtime_get_sync(i2c_dev->dev);
ret = pm_runtime_resume_and_get(i2c_dev->dev);
if (ret < 0)
return ret;
@ -2320,7 +2323,7 @@ static int stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev)
return ret;
}
static int stm32f7_i2c_suspend(struct device *dev)
static int __maybe_unused stm32f7_i2c_suspend(struct device *dev)
{
struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
int ret;
@ -2341,7 +2344,7 @@ static int stm32f7_i2c_suspend(struct device *dev)
return 0;
}
static int stm32f7_i2c_resume(struct device *dev)
static int __maybe_unused stm32f7_i2c_resume(struct device *dev)
{
struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
int ret;
@ -2361,7 +2364,6 @@ static int stm32f7_i2c_resume(struct device *dev)
return 0;
}
#endif
static const struct dev_pm_ops stm32f7_i2c_pm_ops = {
SET_RUNTIME_PM_OPS(stm32f7_i2c_runtime_suspend,

View File

@ -38,49 +38,31 @@ struct tegra_bpmp_i2c {
* firmware I2C driver to avoid any issues in future if Linux I2C flags are
* changed.
*/
static int tegra_bpmp_xlate_flags(u16 flags, u16 *out)
static void tegra_bpmp_xlate_flags(u16 flags, u16 *out)
{
if (flags & I2C_M_TEN) {
if (flags & I2C_M_TEN)
*out |= SERIALI2C_TEN;
flags &= ~I2C_M_TEN;
}
if (flags & I2C_M_RD) {
if (flags & I2C_M_RD)
*out |= SERIALI2C_RD;
flags &= ~I2C_M_RD;
}
if (flags & I2C_M_STOP) {
if (flags & I2C_M_STOP)
*out |= SERIALI2C_STOP;
flags &= ~I2C_M_STOP;
}
if (flags & I2C_M_NOSTART) {
if (flags & I2C_M_NOSTART)
*out |= SERIALI2C_NOSTART;
flags &= ~I2C_M_NOSTART;
}
if (flags & I2C_M_REV_DIR_ADDR) {
if (flags & I2C_M_REV_DIR_ADDR)
*out |= SERIALI2C_REV_DIR_ADDR;
flags &= ~I2C_M_REV_DIR_ADDR;
}
if (flags & I2C_M_IGNORE_NAK) {
if (flags & I2C_M_IGNORE_NAK)
*out |= SERIALI2C_IGNORE_NAK;
flags &= ~I2C_M_IGNORE_NAK;
}
if (flags & I2C_M_NO_RD_ACK) {
if (flags & I2C_M_NO_RD_ACK)
*out |= SERIALI2C_NO_RD_ACK;
flags &= ~I2C_M_NO_RD_ACK;
}
if (flags & I2C_M_RECV_LEN) {
if (flags & I2C_M_RECV_LEN)
*out |= SERIALI2C_RECV_LEN;
flags &= ~I2C_M_RECV_LEN;
}
return 0;
}
/**
@ -97,22 +79,19 @@ static int tegra_bpmp_xlate_flags(u16 flags, u16 *out)
*
* See deserialize_i2c documentation for the data format in the other direction.
*/
static int tegra_bpmp_serialize_i2c_msg(struct tegra_bpmp_i2c *i2c,
static void tegra_bpmp_serialize_i2c_msg(struct tegra_bpmp_i2c *i2c,
struct mrq_i2c_request *request,
struct i2c_msg *msgs,
unsigned int num)
{
char *buf = request->xfer.data_buf;
unsigned int i, j, pos = 0;
int err;
for (i = 0; i < num; i++) {
struct i2c_msg *msg = &msgs[i];
u16 flags = 0;
err = tegra_bpmp_xlate_flags(msg->flags, &flags);
if (err < 0)
return err;
tegra_bpmp_xlate_flags(msg->flags, &flags);
buf[pos++] = msg->addr & 0xff;
buf[pos++] = (msg->addr & 0xff00) >> 8;
@ -128,8 +107,6 @@ static int tegra_bpmp_serialize_i2c_msg(struct tegra_bpmp_i2c *i2c,
}
request->xfer.data_size = pos;
return 0;
}
/**
@ -217,7 +194,32 @@ static int tegra_bpmp_i2c_msg_xfer(struct tegra_bpmp_i2c *i2c,
else
err = tegra_bpmp_transfer(i2c->bpmp, &msg);
return err;
if (err < 0) {
dev_err(i2c->dev, "failed to transfer message: %d\n", err);
return err;
}
if (msg.rx.ret != 0) {
if (msg.rx.ret == -BPMP_EAGAIN) {
dev_dbg(i2c->dev, "arbitration lost\n");
return -EAGAIN;
}
if (msg.rx.ret == -BPMP_ETIMEDOUT) {
dev_dbg(i2c->dev, "timeout\n");
return -ETIMEDOUT;
}
if (msg.rx.ret == -BPMP_ENXIO) {
dev_dbg(i2c->dev, "NAK\n");
return -ENXIO;
}
dev_err(i2c->dev, "transaction failed: %d\n", msg.rx.ret);
return -EIO;
}
return 0;
}
static int tegra_bpmp_i2c_xfer_common(struct i2c_adapter *adapter,
@ -238,12 +240,7 @@ static int tegra_bpmp_i2c_xfer_common(struct i2c_adapter *adapter,
memset(&request, 0, sizeof(request));
memset(&response, 0, sizeof(response));
err = tegra_bpmp_serialize_i2c_msg(i2c, &request, msgs, num);
if (err < 0) {
dev_err(i2c->dev, "failed to serialize message: %d\n", err);
return err;
}
tegra_bpmp_serialize_i2c_msg(i2c, &request, msgs, num);
err = tegra_bpmp_i2c_msg_xfer(i2c, &request, &response, atomic);
if (err < 0) {
dev_err(i2c->dev, "failed to transfer message: %d\n", err);

View File

@ -19,7 +19,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/version.h>
#define MAILBOX_OP_TIMEOUT 1000 /* Operation time out in ms */
#define MAILBOX_I2C_INDEX 0

View File

@ -706,7 +706,7 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
dev_dbg(adap->dev.parent, "%s entry SR: 0x%x\n", __func__,
xiic_getreg8(i2c, XIIC_SR_REG_OFFSET));
err = pm_runtime_get_sync(i2c->dev);
err = pm_runtime_resume_and_get(i2c->dev);
if (err < 0)
return err;
@ -873,7 +873,7 @@ static int xiic_i2c_remove(struct platform_device *pdev)
/* remove adapter & data */
i2c_del_adapter(&i2c->adap);
ret = pm_runtime_get_sync(i2c->dev);
ret = pm_runtime_resume_and_get(i2c->dev);
if (ret < 0)
return ret;

View File

@ -47,7 +47,6 @@ EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num);
*
* The board info passed can safely be __initdata, but be careful of embedded
* pointers (for platform_data, functions, etc) since that won't be copied.
* Device properties are deep-copied though.
*/
int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)
{
@ -72,16 +71,6 @@ int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsig
devinfo->busnum = busnum;
devinfo->board_info = *info;
if (info->properties) {
devinfo->board_info.properties =
property_entries_dup(info->properties);
if (IS_ERR(devinfo->board_info.properties)) {
status = PTR_ERR(devinfo->board_info.properties);
kfree(devinfo);
break;
}
}
if (info->resources) {
devinfo->board_info.resources =
kmemdup(info->resources,

View File

@ -76,6 +76,27 @@ void i2c_transfer_trace_unreg(void)
static_branch_dec(&i2c_trace_msg_key);
}
const char *i2c_freq_mode_string(u32 bus_freq_hz)
{
switch (bus_freq_hz) {
case I2C_MAX_STANDARD_MODE_FREQ:
return "Standard Mode (100 kHz)";
case I2C_MAX_FAST_MODE_FREQ:
return "Fast Mode (400 kHz)";
case I2C_MAX_FAST_MODE_PLUS_FREQ:
return "Fast Mode Plus (1.0 MHz)";
case I2C_MAX_TURBO_MODE_FREQ:
return "Turbo Mode (1.4 MHz)";
case I2C_MAX_HIGH_SPEED_MODE_FREQ:
return "High Speed Mode (3.4 MHz)";
case I2C_MAX_ULTRA_FAST_MODE_FREQ:
return "Ultra Fast Mode (5.0 MHz)";
default:
return "Unknown Mode";
}
}
EXPORT_SYMBOL_GPL(i2c_freq_mode_string);
const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
const struct i2c_client *client)
{
@ -249,7 +270,7 @@ EXPORT_SYMBOL_GPL(i2c_generic_scl_recovery);
int i2c_recover_bus(struct i2c_adapter *adap)
{
if (!adap->bus_recovery_info)
return -EOPNOTSUPP;
return -EBUSY;
dev_dbg(&adap->dev, "Trying i2c bus recovery\n");
return adap->bus_recovery_info->recover_bus(adap);
@ -519,6 +540,13 @@ static int i2c_device_probe(struct device *dev)
if (status)
goto err_clear_wakeup_irq;
client->devres_group_id = devres_open_group(&client->dev, NULL,
GFP_KERNEL);
if (!client->devres_group_id) {
status = -ENOMEM;
goto err_detach_pm_domain;
}
/*
* When there are no more users of probe(),
* rename probe_new to probe.
@ -531,11 +559,21 @@ static int i2c_device_probe(struct device *dev)
else
status = -EINVAL;
/*
* Note that we are not closing the devres group opened above so
* even resources that were attached to the device after probe is
* run are released when i2c_device_remove() is executed. This is
* needed as some drivers would allocate additional resources,
* for example when updating firmware.
*/
if (status)
goto err_detach_pm_domain;
goto err_release_driver_resources;
return 0;
err_release_driver_resources:
devres_release_group(&client->dev, client->devres_group_id);
err_detach_pm_domain:
dev_pm_domain_detach(&client->dev, true);
err_clear_wakeup_irq:
@ -564,6 +602,8 @@ static int i2c_device_remove(struct device *dev)
dev_warn(dev, "remove failed (%pe), will be ignored\n", ERR_PTR(status));
}
devres_release_group(&client->dev, client->devres_group_id);
dev_pm_domain_detach(&client->dev, true);
dev_pm_clear_wake_irq(&client->dev);
@ -612,7 +652,7 @@ modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
if (len != -ENODEV)
return len;
len = acpi_device_modalias(dev, buf, PAGE_SIZE -1);
len = acpi_device_modalias(dev, buf, PAGE_SIZE - 1);
if (len != -ENODEV)
return len;
@ -910,11 +950,11 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf
i2c_dev_set_name(adap, client, info);
if (info->properties) {
status = device_add_properties(&client->dev, info->properties);
if (info->swnode) {
status = device_add_software_node(&client->dev, info->swnode);
if (status) {
dev_err(&adap->dev,
"Failed to add properties to client %s: %d\n",
"Failed to add software node to client %s: %d\n",
client->name, status);
goto out_err_put_of_node;
}
@ -922,16 +962,15 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf
status = device_register(&client->dev);
if (status)
goto out_free_props;
goto out_remove_swnode;
dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",
client->name, dev_name(&client->dev));
return client;
out_free_props:
if (info->properties)
device_remove_properties(&client->dev);
out_remove_swnode:
device_remove_software_node(&client->dev);
out_err_put_of_node:
of_node_put(info->of_node);
out_err:
@ -961,6 +1000,7 @@ void i2c_unregister_device(struct i2c_client *client)
if (ACPI_COMPANION(&client->dev))
acpi_device_clear_enumerated(ACPI_COMPANION(&client->dev));
device_remove_software_node(&client->dev);
device_unregister(&client->dev);
}
EXPORT_SYMBOL_GPL(i2c_unregister_device);
@ -1017,15 +1057,9 @@ struct i2c_client *i2c_new_dummy_device(struct i2c_adapter *adapter, u16 address
}
EXPORT_SYMBOL_GPL(i2c_new_dummy_device);
struct i2c_dummy_devres {
struct i2c_client *client;
};
static void devm_i2c_release_dummy(struct device *dev, void *res)
static void devm_i2c_release_dummy(void *client)
{
struct i2c_dummy_devres *this = res;
i2c_unregister_device(this->client);
i2c_unregister_device(client);
}
/**
@ -1042,20 +1076,16 @@ struct i2c_client *devm_i2c_new_dummy_device(struct device *dev,
struct i2c_adapter *adapter,
u16 address)
{
struct i2c_dummy_devres *dr;
struct i2c_client *client;
dr = devres_alloc(devm_i2c_release_dummy, sizeof(*dr), GFP_KERNEL);
if (!dr)
return ERR_PTR(-ENOMEM);
int ret;
client = i2c_new_dummy_device(adapter, address);
if (IS_ERR(client)) {
devres_free(dr);
} else {
dr->client = client;
devres_add(dev, dr);
}
if (IS_ERR(client))
return client;
ret = devm_add_action_or_reset(dev, devm_i2c_release_dummy, client);
if (ret)
return ERR_PTR(ret);
return client;
}
@ -1704,6 +1734,32 @@ void i2c_del_adapter(struct i2c_adapter *adap)
}
EXPORT_SYMBOL(i2c_del_adapter);
static void devm_i2c_del_adapter(void *adapter)
{
i2c_del_adapter(adapter);
}
/**
* devm_i2c_add_adapter - device-managed variant of i2c_add_adapter()
* @dev: managing device for adding this I2C adapter
* @adapter: the adapter to add
* Context: can sleep
*
* Add adapter with dynamic bus number, same with i2c_add_adapter()
* but the adapter will be auto deleted on driver detach.
*/
int devm_i2c_add_adapter(struct device *dev, struct i2c_adapter *adapter)
{
int ret;
ret = i2c_add_adapter(adapter);
if (ret)
return ret;
return devm_add_action_or_reset(dev, devm_i2c_del_adapter, adapter);
}
EXPORT_SYMBOL_GPL(devm_i2c_add_adapter);
static void i2c_parse_timing(struct device *dev, char *prop_name, u32 *cur_val_p,
u32 def_val, bool use_def)
{

View File

@ -440,8 +440,13 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
sizeof(rdwr_arg)))
return -EFAULT;
/* Put an arbitrary limit on the number of messages that can
* be sent at once */
if (!rdwr_arg.msgs || rdwr_arg.nmsgs == 0)
return -EINVAL;
/*
* Put an arbitrary limit on the number of messages that can
* be sent at once
*/
if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS)
return -EINVAL;

View File

@ -1885,8 +1885,6 @@ static int elantech_create_smbus(struct psmouse *psmouse,
};
unsigned int idx = 0;
smbus_board.properties = i2c_props;
i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-size-x",
info->x_max + 1);
i2c_props[idx++] = PROPERTY_ENTRY_U32("touchscreen-size-y",
@ -1918,6 +1916,10 @@ static int elantech_create_smbus(struct psmouse *psmouse,
if (elantech_is_buttonpad(info))
i2c_props[idx++] = PROPERTY_ENTRY_BOOL("elan,clickpad");
smbus_board.fwnode = fwnode_create_software_node(i2c_props, NULL);
if (IS_ERR(smbus_board.fwnode))
return PTR_ERR(smbus_board.fwnode);
return psmouse_smbus_init(psmouse, &smbus_board, NULL, 0, false,
leave_breadcrumbs);
}

View File

@ -52,12 +52,15 @@ struct i2c_peripheral {
enum i2c_adapter_type type;
u32 pci_devid;
const struct property_entry *properties;
struct i2c_client *client;
};
struct acpi_peripheral {
char hid[ACPI_ID_LEN];
const struct property_entry *properties;
struct software_node swnode;
struct i2c_client *client;
};
struct chromeos_laptop {
@ -68,7 +71,7 @@ struct chromeos_laptop {
struct i2c_peripheral *i2c_peripherals;
unsigned int num_i2c_peripherals;
const struct acpi_peripheral *acpi_peripherals;
struct acpi_peripheral *acpi_peripherals;
unsigned int num_acpi_peripherals;
};
@ -161,7 +164,7 @@ static void chromeos_laptop_check_adapter(struct i2c_adapter *adapter)
static bool chromeos_laptop_adjust_client(struct i2c_client *client)
{
const struct acpi_peripheral *acpi_dev;
struct acpi_peripheral *acpi_dev;
struct acpi_device_id acpi_ids[2] = { };
int i;
int error;
@ -175,8 +178,7 @@ static bool chromeos_laptop_adjust_client(struct i2c_client *client)
memcpy(acpi_ids[0].id, acpi_dev->hid, ACPI_ID_LEN);
if (acpi_match_device(acpi_ids, &client->dev)) {
error = device_add_properties(&client->dev,
acpi_dev->properties);
error = device_add_software_node(&client->dev, &acpi_dev->swnode);
if (error) {
dev_err(&client->dev,
"failed to add properties: %d\n",
@ -184,6 +186,8 @@ static bool chromeos_laptop_adjust_client(struct i2c_client *client)
break;
}
acpi_dev->client = client;
return true;
}
}
@ -193,15 +197,28 @@ static bool chromeos_laptop_adjust_client(struct i2c_client *client)
static void chromeos_laptop_detach_i2c_client(struct i2c_client *client)
{
struct acpi_peripheral *acpi_dev;
struct i2c_peripheral *i2c_dev;
int i;
for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
i2c_dev = &cros_laptop->i2c_peripherals[i];
if (has_acpi_companion(&client->dev))
for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) {
acpi_dev = &cros_laptop->acpi_peripherals[i];
if (i2c_dev->client == client)
i2c_dev->client = NULL;
}
if (acpi_dev->client == client) {
acpi_dev->client = NULL;
return;
}
}
else
for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
i2c_dev = &cros_laptop->i2c_peripherals[i];
if (i2c_dev->client == client) {
i2c_dev->client = NULL;
return;
}
}
}
static int chromeos_laptop_i2c_notifier_call(struct notifier_block *nb,
@ -302,28 +319,26 @@ static struct i2c_peripheral chromebook_pixel_peripherals[] __initdata = {
.board_info = {
I2C_BOARD_INFO("atmel_mxt_ts",
ATMEL_TS_I2C_ADDR),
.properties =
chromebook_atmel_touchscreen_props,
.flags = I2C_CLIENT_WAKE,
},
.dmi_name = "touchscreen",
.irqflags = IRQF_TRIGGER_FALLING,
.type = I2C_ADAPTER_PANEL,
.alt_addr = ATMEL_TS_I2C_BL_ADDR,
.properties = chromebook_atmel_touchscreen_props,
},
/* Touchpad. */
{
.board_info = {
I2C_BOARD_INFO("atmel_mxt_tp",
ATMEL_TP_I2C_ADDR),
.properties =
chromebook_pixel_trackpad_props,
.flags = I2C_CLIENT_WAKE,
},
.dmi_name = "trackpad",
.irqflags = IRQF_TRIGGER_FALLING,
.type = I2C_ADAPTER_VGADDC,
.alt_addr = ATMEL_TP_I2C_BL_ADDR,
.properties = chromebook_pixel_trackpad_props,
},
/* Light Sensor. */
{
@ -414,8 +429,6 @@ static struct i2c_peripheral acer_c720_peripherals[] __initdata = {
.board_info = {
I2C_BOARD_INFO("atmel_mxt_ts",
ATMEL_TS_I2C_ADDR),
.properties =
chromebook_atmel_touchscreen_props,
.flags = I2C_CLIENT_WAKE,
},
.dmi_name = "touchscreen",
@ -423,6 +436,7 @@ static struct i2c_peripheral acer_c720_peripherals[] __initdata = {
.type = I2C_ADAPTER_DESIGNWARE,
.pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)),
.alt_addr = ATMEL_TS_I2C_BL_ADDR,
.properties = chromebook_atmel_touchscreen_props,
},
/* Touchpad. */
{
@ -498,12 +512,16 @@ static struct acpi_peripheral samus_peripherals[] __initdata = {
/* Touchpad */
{
.hid = "ATML0000",
.properties = samus_trackpad_props,
.swnode = {
.properties = samus_trackpad_props,
},
},
/* Touchsceen */
{
.hid = "ATML0001",
.properties = chromebook_atmel_touchscreen_props,
.swnode = {
.properties = chromebook_atmel_touchscreen_props,
},
},
};
DECLARE_ACPI_CROS_LAPTOP(samus);
@ -512,12 +530,16 @@ static struct acpi_peripheral generic_atmel_peripherals[] __initdata = {
/* Touchpad */
{
.hid = "ATML0000",
.properties = chromebook_pixel_trackpad_props,
.swnode = {
.properties = chromebook_pixel_trackpad_props,
},
},
/* Touchsceen */
{
.hid = "ATML0001",
.properties = chromebook_atmel_touchscreen_props,
.swnode = {
.properties = chromebook_atmel_touchscreen_props,
},
},
};
DECLARE_ACPI_CROS_LAPTOP(generic_atmel);
@ -743,12 +765,11 @@ chromeos_laptop_prepare_i2c_peripherals(struct chromeos_laptop *cros_laptop,
if (error)
goto err_out;
/* We need to deep-copy properties */
if (info->properties) {
info->properties =
property_entries_dup(info->properties);
if (IS_ERR(info->properties)) {
error = PTR_ERR(info->properties);
/* Create primary fwnode for the device - copies everything */
if (i2c_dev->properties) {
info->fwnode = fwnode_create_software_node(i2c_dev->properties, NULL);
if (IS_ERR(info->fwnode)) {
error = PTR_ERR(info->fwnode);
goto err_out;
}
}
@ -760,8 +781,8 @@ err_out:
while (--i >= 0) {
i2c_dev = &cros_laptop->i2c_peripherals[i];
info = &i2c_dev->board_info;
if (info->properties)
property_entries_free(info->properties);
if (!IS_ERR_OR_NULL(info->fwnode))
fwnode_remove_software_node(info->fwnode);
}
kfree(cros_laptop->i2c_peripherals);
return error;
@ -801,11 +822,11 @@ chromeos_laptop_prepare_acpi_peripherals(struct chromeos_laptop *cros_laptop,
*acpi_dev = *src_dev;
/* We need to deep-copy properties */
if (src_dev->properties) {
acpi_dev->properties =
property_entries_dup(src_dev->properties);
if (IS_ERR(acpi_dev->properties)) {
error = PTR_ERR(acpi_dev->properties);
if (src_dev->swnode.properties) {
acpi_dev->swnode.properties =
property_entries_dup(src_dev->swnode.properties);
if (IS_ERR(acpi_dev->swnode.properties)) {
error = PTR_ERR(acpi_dev->swnode.properties);
goto err_out;
}
}
@ -821,8 +842,8 @@ chromeos_laptop_prepare_acpi_peripherals(struct chromeos_laptop *cros_laptop,
err_out:
while (--i >= 0) {
acpi_dev = &acpi_peripherals[i];
if (acpi_dev->properties)
property_entries_free(acpi_dev->properties);
if (!IS_ERR_OR_NULL(acpi_dev->swnode.properties))
property_entries_free(acpi_dev->swnode.properties);
}
kfree(acpi_peripherals);
@ -833,21 +854,20 @@ static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop)
{
const struct acpi_peripheral *acpi_dev;
struct i2c_peripheral *i2c_dev;
struct i2c_board_info *info;
int i;
for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
i2c_dev = &cros_laptop->i2c_peripherals[i];
info = &i2c_dev->board_info;
i2c_unregister_device(i2c_dev->client);
property_entries_free(info->properties);
}
for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) {
acpi_dev = &cros_laptop->acpi_peripherals[i];
property_entries_free(acpi_dev->properties);
if (acpi_dev->client)
device_remove_software_node(&acpi_dev->client->dev);
property_entries_free(acpi_dev->swnode.properties);
}
kfree(cros_laptop->i2c_peripherals);

View File

@ -35,6 +35,10 @@ static const struct property_entry bq27xxx_props[] = {
{ }
};
static const struct software_node bq27xxx_node = {
.properties = bq27xxx_props,
};
int cht_int33fe_microb_probe(struct cht_int33fe_data *data)
{
struct device *dev = data->dev;
@ -43,7 +47,7 @@ int cht_int33fe_microb_probe(struct cht_int33fe_data *data)
memset(&board_info, 0, sizeof(board_info));
strscpy(board_info.type, "bq27542", ARRAY_SIZE(board_info.type));
board_info.dev_name = "bq27542";
board_info.properties = bq27xxx_props;
board_info.swnode = &bq27xxx_node;
data->battery_fg = i2c_acpi_new_device(dev, 1, &board_info);
return PTR_ERR_OR_ZERO(data->battery_fg);

View File

@ -51,6 +51,9 @@ struct module;
struct property_entry;
#if IS_ENABLED(CONFIG_I2C)
/* Return the Frequency mode string based on the bus frequency */
const char *i2c_freq_mode_string(u32 bus_freq_hz);
/*
* The master routines are the ones normally used to transmit data to devices
* on a bus (or read from them). Apart from two basic transfer functions to
@ -306,6 +309,8 @@ struct i2c_driver {
* userspace_devices list
* @slave_cb: Callback when I2C slave mode of an adapter is used. The adapter
* calls it to pass on slave events to the slave driver.
* @devres_group_id: id of the devres group that will be created for resources
* acquired when probing this device.
*
* An i2c_client identifies a single device (i.e. chip) connected to an
* i2c bus. The behaviour exposed to Linux is defined by the driver
@ -334,6 +339,7 @@ struct i2c_client {
#if IS_ENABLED(CONFIG_I2C_SLAVE)
i2c_slave_cb_t slave_cb; /* callback for slave mode */
#endif
void *devres_group_id; /* ID of probe devres group */
};
#define to_i2c_client(d) container_of(d, struct i2c_client, dev)
@ -391,7 +397,7 @@ static inline bool i2c_detect_slave_mode(struct device *dev) { return false; }
* @platform_data: stored in i2c_client.dev.platform_data
* @of_node: pointer to OpenFirmware device node
* @fwnode: device node supplied by the platform firmware
* @properties: additional device properties for the device
* @swnode: software node for the device
* @resources: resources associated with the device
* @num_resources: number of resources in the @resources array
* @irq: stored in i2c_client.irq
@ -415,7 +421,7 @@ struct i2c_board_info {
void *platform_data;
struct device_node *of_node;
struct fwnode_handle *fwnode;
const struct property_entry *properties;
const struct software_node *swnode;
const struct resource *resources;
unsigned int num_resources;
int irq;
@ -687,6 +693,8 @@ struct i2c_adapter_quirks {
#define I2C_AQ_NO_ZERO_LEN_READ BIT(5)
#define I2C_AQ_NO_ZERO_LEN_WRITE BIT(6)
#define I2C_AQ_NO_ZERO_LEN (I2C_AQ_NO_ZERO_LEN_READ | I2C_AQ_NO_ZERO_LEN_WRITE)
/* adapter cannot do repeated START */
#define I2C_AQ_NO_REP_START BIT(7)
/*
* i2c_adapter is the structure used to identify a physical i2c bus along
@ -844,6 +852,7 @@ static inline void i2c_mark_adapter_resumed(struct i2c_adapter *adap)
*/
#if IS_ENABLED(CONFIG_I2C)
int i2c_add_adapter(struct i2c_adapter *adap);
int devm_i2c_add_adapter(struct device *dev, struct i2c_adapter *adapter);
void i2c_del_adapter(struct i2c_adapter *adap);
int i2c_add_numbered_adapter(struct i2c_adapter *adap);