mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 12:43:29 +02:00
Merge branch 'i2c/for-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: - bus recovery can now be given a pinctrl handle and the I2C core will do all the steps to switch to/from GPIO which can save quite some boilerplate code from drivers - "fallthrough" conversion - driver updates, mostly ID additions * 'i2c/for-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (32 commits) i2c: iproc: fix race between client unreg and isr i2c: eg20t: use generic power management i2c: eg20t: Drop PCI wakeup calls from .suspend/.resume i2c: mediatek: Fix i2c_spec_values description i2c: mediatek: Add i2c compatible for MediaTek MT8192 dt-bindings: i2c: update bindings for MT8192 SoC i2c: mediatek: Add access to more than 8GB dram in i2c driver i2c: mediatek: Add apdma sync in i2c driver i2c: i801: Add support for Intel Tiger Lake PCH-H i2c: i801: Add support for Intel Emmitsburg PCH i2c: bcm2835: Replace HTTP links with HTTPS ones Documentation: i2c: dev: 'block process call' is supported i2c: at91: Move to generic GPIO bus recovery i2c: core: treat EPROBE_DEFER when acquiring SCL/SDA GPIOs i2c: core: add generic I2C GPIO recovery dt-bindings: i2c: add generic properties for GPIO bus recovery i2c: rcar: avoid race when unregistering slave i2c: tegra: Avoid tegra_i2c_init_dma() for Tegra210 vi i2c i2c: tegra: Fix runtime resume to re-init VI I2C i2c: tegra: Fix the error path in tegra_i2c_runtime_resume ...
This commit is contained in:
@@ -14,6 +14,7 @@ Required properties:
|
|||||||
"mediatek,mt7629-i2c", "mediatek,mt2712-i2c": for MediaTek MT7629
|
"mediatek,mt7629-i2c", "mediatek,mt2712-i2c": for MediaTek MT7629
|
||||||
"mediatek,mt8173-i2c": for MediaTek MT8173
|
"mediatek,mt8173-i2c": for MediaTek MT8173
|
||||||
"mediatek,mt8183-i2c": for MediaTek MT8183
|
"mediatek,mt8183-i2c": for MediaTek MT8183
|
||||||
|
"mediatek,mt8192-i2c": for MediaTek MT8192
|
||||||
"mediatek,mt8516-i2c", "mediatek,mt2712-i2c": for MediaTek MT8516
|
"mediatek,mt8516-i2c", "mediatek,mt2712-i2c": for MediaTek MT8516
|
||||||
- reg: physical base address of the controller and dma base, length of memory
|
- reg: physical base address of the controller and dma base, length of memory
|
||||||
mapped region.
|
mapped region.
|
||||||
|
@@ -72,6 +72,16 @@ wants to support one of the below features, it should adapt these bindings.
|
|||||||
this information to adapt power management to keep the arbitration awake
|
this information to adapt power management to keep the arbitration awake
|
||||||
all the time, for example. Can not be combined with 'single-master'.
|
all the time, for example. Can not be combined with 'single-master'.
|
||||||
|
|
||||||
|
- pinctrl
|
||||||
|
add extra pinctrl to configure SCL/SDA pins to GPIO function for bus
|
||||||
|
recovery, call it "gpio" or "recovery" (deprecated) state
|
||||||
|
|
||||||
|
- scl-gpios
|
||||||
|
specify the gpio related to SCL pin. Used for GPIO bus recovery.
|
||||||
|
|
||||||
|
- sda-gpios
|
||||||
|
specify the gpio related to SDA pin. Optional for GPIO bus recovery.
|
||||||
|
|
||||||
- single-master
|
- single-master
|
||||||
states that there is no other master active on this bus. The OS can use
|
states that there is no other master active on this bus. The OS can use
|
||||||
this information to detect a stalled bus more reliably, for example.
|
this information to detect a stalled bus more reliably, for example.
|
||||||
|
@@ -26,6 +26,9 @@ properties:
|
|||||||
- items:
|
- items:
|
||||||
- const: allwinner,sun50i-a64-i2c
|
- const: allwinner,sun50i-a64-i2c
|
||||||
- const: allwinner,sun6i-a31-i2c
|
- const: allwinner,sun6i-a31-i2c
|
||||||
|
- items:
|
||||||
|
- const: allwinner,sun50i-a100-i2c
|
||||||
|
- const: allwinner,sun6i-a31-i2c
|
||||||
- items:
|
- items:
|
||||||
- const: allwinner,sun50i-h6-i2c
|
- const: allwinner,sun50i-h6-i2c
|
||||||
- const: allwinner,sun6i-a31-i2c
|
- const: allwinner,sun6i-a31-i2c
|
||||||
|
@@ -10,6 +10,7 @@ Required properties:
|
|||||||
"renesas,i2c-r8a774a1" if the device is a part of a R8A774A1 SoC.
|
"renesas,i2c-r8a774a1" if the device is a part of a R8A774A1 SoC.
|
||||||
"renesas,i2c-r8a774b1" if the device is a part of a R8A774B1 SoC.
|
"renesas,i2c-r8a774b1" if the device is a part of a R8A774B1 SoC.
|
||||||
"renesas,i2c-r8a774c0" if the device is a part of a R8A774C0 SoC.
|
"renesas,i2c-r8a774c0" if the device is a part of a R8A774C0 SoC.
|
||||||
|
"renesas,i2c-r8a774e1" if the device is a part of a R8A774E1 SoC.
|
||||||
"renesas,i2c-r8a7778" if the device is a part of a R8A7778 SoC.
|
"renesas,i2c-r8a7778" if the device is a part of a R8A7778 SoC.
|
||||||
"renesas,i2c-r8a7779" if the device is a part of a R8A7779 SoC.
|
"renesas,i2c-r8a7779" if the device is a part of a R8A7779 SoC.
|
||||||
"renesas,i2c-r8a7790" if the device is a part of a R8A7790 SoC.
|
"renesas,i2c-r8a7790" if the device is a part of a R8A7790 SoC.
|
||||||
|
@@ -11,6 +11,7 @@ Required properties:
|
|||||||
- "renesas,iic-r8a774a1" (RZ/G2M)
|
- "renesas,iic-r8a774a1" (RZ/G2M)
|
||||||
- "renesas,iic-r8a774b1" (RZ/G2N)
|
- "renesas,iic-r8a774b1" (RZ/G2N)
|
||||||
- "renesas,iic-r8a774c0" (RZ/G2E)
|
- "renesas,iic-r8a774c0" (RZ/G2E)
|
||||||
|
- "renesas,iic-r8a774e1" (RZ/G2H)
|
||||||
- "renesas,iic-r8a7790" (R-Car H2)
|
- "renesas,iic-r8a7790" (R-Car H2)
|
||||||
- "renesas,iic-r8a7791" (R-Car M2-W)
|
- "renesas,iic-r8a7791" (R-Car M2-W)
|
||||||
- "renesas,iic-r8a7792" (R-Car V2H)
|
- "renesas,iic-r8a7792" (R-Car V2H)
|
||||||
|
@@ -43,6 +43,7 @@ Supported adapters:
|
|||||||
* Intel Elkhart Lake (PCH)
|
* Intel Elkhart Lake (PCH)
|
||||||
* Intel Tiger Lake (PCH)
|
* Intel Tiger Lake (PCH)
|
||||||
* Intel Jasper Lake (SOC)
|
* Intel Jasper Lake (SOC)
|
||||||
|
* Intel Emmitsburg (PCH)
|
||||||
|
|
||||||
Datasheets: Publicly available at the Intel website
|
Datasheets: Publicly available at the Intel website
|
||||||
|
|
||||||
|
@@ -159,6 +159,8 @@ for details) through the following functions::
|
|||||||
__s32 i2c_smbus_read_word_data(int file, __u8 command);
|
__s32 i2c_smbus_read_word_data(int file, __u8 command);
|
||||||
__s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value);
|
__s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value);
|
||||||
__s32 i2c_smbus_process_call(int file, __u8 command, __u16 value);
|
__s32 i2c_smbus_process_call(int file, __u8 command, __u16 value);
|
||||||
|
__s32 i2c_smbus_block_process_call(int file, __u8 command, __u8 length,
|
||||||
|
__u8 *values);
|
||||||
__s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values);
|
__s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values);
|
||||||
__s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length,
|
__s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length,
|
||||||
__u8 *values);
|
__u8 *values);
|
||||||
|
@@ -542,8 +542,8 @@ int i2c_pca_add_numbered_bus(struct i2c_adapter *adap)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(i2c_pca_add_numbered_bus);
|
EXPORT_SYMBOL(i2c_pca_add_numbered_bus);
|
||||||
|
|
||||||
MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>, "
|
MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
|
||||||
"Wolfram Sang <kernel@pengutronix.de>");
|
MODULE_AUTHOR("Wolfram Sang <kernel@pengutronix.de>");
|
||||||
MODULE_DESCRIPTION("I2C-Bus PCA9564/PCA9665 algorithm");
|
MODULE_DESCRIPTION("I2C-Bus PCA9564/PCA9665 algorithm");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
@@ -146,6 +146,7 @@ config I2C_I801
|
|||||||
Elkhart Lake (PCH)
|
Elkhart Lake (PCH)
|
||||||
Tiger Lake (PCH)
|
Tiger Lake (PCH)
|
||||||
Jasper Lake (SOC)
|
Jasper Lake (SOC)
|
||||||
|
Emmitsburg (PCH)
|
||||||
|
|
||||||
This driver can also be built as a module. If so, the module
|
This driver can also be built as a module. If so, the module
|
||||||
will be called i2c-i801.
|
will be called i2c-i801.
|
||||||
|
@@ -519,9 +519,9 @@ static struct pci_driver ali1535_driver = {
|
|||||||
|
|
||||||
module_pci_driver(ali1535_driver);
|
module_pci_driver(ali1535_driver);
|
||||||
|
|
||||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
|
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
|
||||||
"Philip Edelbrock <phil@netroedge.com>, "
|
MODULE_AUTHOR("Philip Edelbrock <phil@netroedge.com>");
|
||||||
"Mark D. Studebaker <mdsxyz123@yahoo.com> "
|
MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
|
||||||
"and Dan Eaton <dan.eaton@rocketlogix.com>");
|
MODULE_AUTHOR("Dan Eaton <dan.eaton@rocketlogix.com>");
|
||||||
MODULE_DESCRIPTION("ALI1535 SMBus driver");
|
MODULE_DESCRIPTION("ALI1535 SMBus driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
@@ -502,8 +502,8 @@ static struct pci_driver ali15x3_driver = {
|
|||||||
|
|
||||||
module_pci_driver(ali15x3_driver);
|
module_pci_driver(ali15x3_driver);
|
||||||
|
|
||||||
MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
|
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
|
||||||
"Philip Edelbrock <phil@netroedge.com>, "
|
MODULE_AUTHOR("Philip Edelbrock <phil@netroedge.com>");
|
||||||
"and Mark D. Studebaker <mdsxyz123@yahoo.com>");
|
MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
|
||||||
MODULE_DESCRIPTION("ALI15X3 SMBus driver");
|
MODULE_DESCRIPTION("ALI15X3 SMBus driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
@@ -381,7 +381,7 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr,
|
|||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
|
len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
|
||||||
/* fall through */
|
fallthrough;
|
||||||
case I2C_SMBUS_I2C_BLOCK_DATA:
|
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
status = amd_ec_read(smbus, AMD_SMB_DATA + i,
|
status = amd_ec_read(smbus, AMD_SMB_DATA + i,
|
||||||
|
@@ -504,7 +504,7 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
|
|||||||
goto error_and_stop;
|
goto error_and_stop;
|
||||||
}
|
}
|
||||||
irq_handled |= ASPEED_I2CD_INTR_TX_ACK;
|
irq_handled |= ASPEED_I2CD_INTR_TX_ACK;
|
||||||
/* fall through */
|
fallthrough;
|
||||||
case ASPEED_I2C_MASTER_TX_FIRST:
|
case ASPEED_I2C_MASTER_TX_FIRST:
|
||||||
if (bus->buf_index < msg->len) {
|
if (bus->buf_index < msg->len) {
|
||||||
bus->master_state = ASPEED_I2C_MASTER_TX;
|
bus->master_state = ASPEED_I2C_MASTER_TX;
|
||||||
@@ -520,7 +520,7 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
|
|||||||
/* RX may not have completed yet (only address cycle) */
|
/* RX may not have completed yet (only address cycle) */
|
||||||
if (!(irq_status & ASPEED_I2CD_INTR_RX_DONE))
|
if (!(irq_status & ASPEED_I2CD_INTR_RX_DONE))
|
||||||
goto out_no_complete;
|
goto out_no_complete;
|
||||||
/* fall through */
|
fallthrough;
|
||||||
case ASPEED_I2C_MASTER_RX:
|
case ASPEED_I2C_MASTER_RX:
|
||||||
if (unlikely(!(irq_status & ASPEED_I2CD_INTR_RX_DONE))) {
|
if (unlikely(!(irq_status & ASPEED_I2CD_INTR_RX_DONE))) {
|
||||||
dev_err(bus->dev, "master failed to RX\n");
|
dev_err(bus->dev, "master failed to RX\n");
|
||||||
|
@@ -816,79 +816,16 @@ error:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void at91_prepare_twi_recovery(struct i2c_adapter *adap)
|
|
||||||
{
|
|
||||||
struct at91_twi_dev *dev = i2c_get_adapdata(adap);
|
|
||||||
|
|
||||||
pinctrl_select_state(dev->pinctrl, dev->pinctrl_pins_gpio);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void at91_unprepare_twi_recovery(struct i2c_adapter *adap)
|
|
||||||
{
|
|
||||||
struct at91_twi_dev *dev = i2c_get_adapdata(adap);
|
|
||||||
|
|
||||||
pinctrl_select_state(dev->pinctrl, dev->pinctrl_pins_default);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int at91_init_twi_recovery_gpio(struct platform_device *pdev,
|
static int at91_init_twi_recovery_gpio(struct platform_device *pdev,
|
||||||
struct at91_twi_dev *dev)
|
struct at91_twi_dev *dev)
|
||||||
{
|
{
|
||||||
struct i2c_bus_recovery_info *rinfo = &dev->rinfo;
|
struct i2c_bus_recovery_info *rinfo = &dev->rinfo;
|
||||||
|
|
||||||
dev->pinctrl = devm_pinctrl_get(&pdev->dev);
|
rinfo->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||||
if (!dev->pinctrl || IS_ERR(dev->pinctrl)) {
|
if (!rinfo->pinctrl || IS_ERR(rinfo->pinctrl)) {
|
||||||
dev_info(dev->dev, "can't get pinctrl, bus recovery not supported\n");
|
dev_info(dev->dev, "can't get pinctrl, bus recovery not supported\n");
|
||||||
return PTR_ERR(dev->pinctrl);
|
return PTR_ERR(rinfo->pinctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->pinctrl_pins_default = pinctrl_lookup_state(dev->pinctrl,
|
|
||||||
PINCTRL_STATE_DEFAULT);
|
|
||||||
dev->pinctrl_pins_gpio = pinctrl_lookup_state(dev->pinctrl,
|
|
||||||
"gpio");
|
|
||||||
if (IS_ERR(dev->pinctrl_pins_default) ||
|
|
||||||
IS_ERR(dev->pinctrl_pins_gpio)) {
|
|
||||||
dev_info(&pdev->dev, "pinctrl states incomplete for recovery\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* pins will be taken as GPIO, so we might as well inform pinctrl about
|
|
||||||
* this and move the state to GPIO
|
|
||||||
*/
|
|
||||||
pinctrl_select_state(dev->pinctrl, dev->pinctrl_pins_gpio);
|
|
||||||
|
|
||||||
rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN);
|
|
||||||
if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER)
|
|
||||||
return -EPROBE_DEFER;
|
|
||||||
|
|
||||||
rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl",
|
|
||||||
GPIOD_OUT_HIGH_OPEN_DRAIN);
|
|
||||||
if (PTR_ERR(rinfo->scl_gpiod) == -EPROBE_DEFER)
|
|
||||||
return -EPROBE_DEFER;
|
|
||||||
|
|
||||||
if (IS_ERR(rinfo->sda_gpiod) ||
|
|
||||||
IS_ERR(rinfo->scl_gpiod)) {
|
|
||||||
dev_info(&pdev->dev, "recovery information incomplete\n");
|
|
||||||
if (!IS_ERR(rinfo->sda_gpiod)) {
|
|
||||||
gpiod_put(rinfo->sda_gpiod);
|
|
||||||
rinfo->sda_gpiod = NULL;
|
|
||||||
}
|
|
||||||
if (!IS_ERR(rinfo->scl_gpiod)) {
|
|
||||||
gpiod_put(rinfo->scl_gpiod);
|
|
||||||
rinfo->scl_gpiod = NULL;
|
|
||||||
}
|
|
||||||
pinctrl_select_state(dev->pinctrl, dev->pinctrl_pins_default);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* change the state of the pins back to their default state */
|
|
||||||
pinctrl_select_state(dev->pinctrl, dev->pinctrl_pins_default);
|
|
||||||
|
|
||||||
dev_info(&pdev->dev, "using scl, sda for recovery\n");
|
|
||||||
|
|
||||||
rinfo->prepare_recovery = at91_prepare_twi_recovery;
|
|
||||||
rinfo->unprepare_recovery = at91_unprepare_twi_recovery;
|
|
||||||
rinfo->recover_bus = i2c_generic_scl_recovery;
|
|
||||||
dev->adapter.bus_recovery_info = rinfo;
|
dev->adapter.bus_recovery_info = rinfo;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -157,9 +157,6 @@ struct at91_twi_dev {
|
|||||||
struct at91_twi_dma dma;
|
struct at91_twi_dma dma;
|
||||||
bool slave_detected;
|
bool slave_detected;
|
||||||
struct i2c_bus_recovery_info rinfo;
|
struct i2c_bus_recovery_info rinfo;
|
||||||
struct pinctrl *pinctrl;
|
|
||||||
struct pinctrl_state *pinctrl_pins_default;
|
|
||||||
struct pinctrl_state *pinctrl_pins_gpio;
|
|
||||||
#ifdef CONFIG_I2C_AT91_SLAVE_EXPERIMENTAL
|
#ifdef CONFIG_I2C_AT91_SLAVE_EXPERIMENTAL
|
||||||
unsigned smr;
|
unsigned smr;
|
||||||
struct i2c_client *slave;
|
struct i2c_client *slave;
|
||||||
|
@@ -1078,7 +1078,7 @@ static int bcm_iproc_i2c_unreg_slave(struct i2c_client *slave)
|
|||||||
if (!iproc_i2c->slave)
|
if (!iproc_i2c->slave)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
iproc_i2c->slave = NULL;
|
disable_irq(iproc_i2c->irq);
|
||||||
|
|
||||||
/* disable all slave interrupts */
|
/* disable all slave interrupts */
|
||||||
tmp = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
|
tmp = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET);
|
||||||
@@ -1091,6 +1091,17 @@ static int bcm_iproc_i2c_unreg_slave(struct i2c_client *slave)
|
|||||||
tmp &= ~BIT(S_CFG_EN_NIC_SMB_ADDR3_SHIFT);
|
tmp &= ~BIT(S_CFG_EN_NIC_SMB_ADDR3_SHIFT);
|
||||||
iproc_i2c_wr_reg(iproc_i2c, S_CFG_SMBUS_ADDR_OFFSET, tmp);
|
iproc_i2c_wr_reg(iproc_i2c, S_CFG_SMBUS_ADDR_OFFSET, tmp);
|
||||||
|
|
||||||
|
/* flush TX/RX FIFOs */
|
||||||
|
tmp = (BIT(S_FIFO_RX_FLUSH_SHIFT) | BIT(S_FIFO_TX_FLUSH_SHIFT));
|
||||||
|
iproc_i2c_wr_reg(iproc_i2c, S_FIFO_CTRL_OFFSET, tmp);
|
||||||
|
|
||||||
|
/* clear all pending slave interrupts */
|
||||||
|
iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, ISR_MASK_SLAVE);
|
||||||
|
|
||||||
|
iproc_i2c->slave = NULL;
|
||||||
|
|
||||||
|
enable_irq(iproc_i2c->irq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -392,7 +392,7 @@ static const struct i2c_algorithm bcm2835_i2c_algo = {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* The BCM2835 was reported to have problems with clock stretching:
|
* The BCM2835 was reported to have problems with clock stretching:
|
||||||
* http://www.advamation.com/knowhow/raspberrypi/rpi-i2c-bug.html
|
* https://www.advamation.com/knowhow/raspberrypi/rpi-i2c-bug.html
|
||||||
* https://www.raspberrypi.org/forums/viewtopic.php?p=146272
|
* https://www.raspberrypi.org/forums/viewtopic.php?p=146272
|
||||||
*/
|
*/
|
||||||
static const struct i2c_adapter_quirks bcm2835_i2c_quirks = {
|
static const struct i2c_adapter_quirks bcm2835_i2c_quirks = {
|
||||||
|
@@ -90,7 +90,7 @@ static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
|
|||||||
switch (pdev->device) {
|
switch (pdev->device) {
|
||||||
case 0x0817:
|
case 0x0817:
|
||||||
dev->timings.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ;
|
dev->timings.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ;
|
||||||
/* fall through */
|
fallthrough;
|
||||||
case 0x0818:
|
case 0x0818:
|
||||||
case 0x0819:
|
case 0x0819:
|
||||||
c->bus_num = pdev->device - 0x817 + 3;
|
c->bus_num = pdev->device - 0x817 + 3;
|
||||||
|
@@ -187,7 +187,7 @@ static irqreturn_t dc_i2c_irq(int irq, void *dev_id)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i2c->state = STATE_WRITE;
|
i2c->state = STATE_WRITE;
|
||||||
/* fall through */
|
fallthrough;
|
||||||
case STATE_WRITE:
|
case STATE_WRITE:
|
||||||
if (i2c->msgbuf_ptr < i2c->msg->len)
|
if (i2c->msgbuf_ptr < i2c->msg->len)
|
||||||
dc_i2c_write_buf(i2c);
|
dc_i2c_write_buf(i2c);
|
||||||
|
@@ -846,11 +846,10 @@ static void pch_i2c_remove(struct pci_dev *pdev)
|
|||||||
kfree(adap_info);
|
kfree(adap_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
static int __maybe_unused pch_i2c_suspend(struct device *dev)
|
||||||
static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state)
|
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
int i;
|
int i;
|
||||||
|
struct pci_dev *pdev = to_pci_dev(dev);
|
||||||
struct adapter_info *adap_info = pci_get_drvdata(pdev);
|
struct adapter_info *adap_info = pci_get_drvdata(pdev);
|
||||||
void __iomem *p = adap_info->pch_data[0].pch_base_address;
|
void __iomem *p = adap_info->pch_data[0].pch_base_address;
|
||||||
|
|
||||||
@@ -872,34 +871,13 @@ static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state)
|
|||||||
ioread32(p + PCH_I2CSR), ioread32(p + PCH_I2CBUFSTA),
|
ioread32(p + PCH_I2CSR), ioread32(p + PCH_I2CBUFSTA),
|
||||||
ioread32(p + PCH_I2CESRSTA));
|
ioread32(p + PCH_I2CESRSTA));
|
||||||
|
|
||||||
ret = pci_save_state(pdev);
|
|
||||||
|
|
||||||
if (ret) {
|
|
||||||
pch_pci_err(pdev, "pci_save_state\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
pci_enable_wake(pdev, PCI_D3hot, 0);
|
|
||||||
pci_disable_device(pdev);
|
|
||||||
pci_set_power_state(pdev, pci_choose_state(pdev, state));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pch_i2c_resume(struct pci_dev *pdev)
|
static int __maybe_unused pch_i2c_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct adapter_info *adap_info = pci_get_drvdata(pdev);
|
struct adapter_info *adap_info = dev_get_drvdata(dev);
|
||||||
|
|
||||||
pci_set_power_state(pdev, PCI_D0);
|
|
||||||
pci_restore_state(pdev);
|
|
||||||
|
|
||||||
if (pci_enable_device(pdev) < 0) {
|
|
||||||
pch_pci_err(pdev, "pch_i2c_resume:pci_enable_device FAILED\n");
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
pci_enable_wake(pdev, PCI_D3hot, 0);
|
|
||||||
|
|
||||||
for (i = 0; i < adap_info->ch_num; i++)
|
for (i = 0; i < adap_info->ch_num; i++)
|
||||||
pch_i2c_init(&adap_info->pch_data[i]);
|
pch_i2c_init(&adap_info->pch_data[i]);
|
||||||
@@ -908,18 +886,15 @@ static int pch_i2c_resume(struct pci_dev *pdev)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
#define pch_i2c_suspend NULL
|
static SIMPLE_DEV_PM_OPS(pch_i2c_pm_ops, pch_i2c_suspend, pch_i2c_resume);
|
||||||
#define pch_i2c_resume NULL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static struct pci_driver pch_pcidriver = {
|
static struct pci_driver pch_pcidriver = {
|
||||||
.name = KBUILD_MODNAME,
|
.name = KBUILD_MODNAME,
|
||||||
.id_table = pch_pcidev_id,
|
.id_table = pch_pcidev_id,
|
||||||
.probe = pch_i2c_probe,
|
.probe = pch_i2c_probe,
|
||||||
.remove = pch_i2c_remove,
|
.remove = pch_i2c_remove,
|
||||||
.suspend = pch_i2c_suspend,
|
.driver.pm = &pch_i2c_pm_ops,
|
||||||
.resume = pch_i2c_resume
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module_pci_driver(pch_pcidriver);
|
module_pci_driver(pch_pcidriver);
|
||||||
|
@@ -442,6 +442,7 @@ static struct platform_driver em_i2c_driver = {
|
|||||||
module_platform_driver(em_i2c_driver);
|
module_platform_driver(em_i2c_driver);
|
||||||
|
|
||||||
MODULE_DESCRIPTION("EMEV2 I2C bus driver");
|
MODULE_DESCRIPTION("EMEV2 I2C bus driver");
|
||||||
MODULE_AUTHOR("Ian Molton and Wolfram Sang <wsa@sang-engineering.com>");
|
MODULE_AUTHOR("Ian Molton");
|
||||||
|
MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
MODULE_DEVICE_TABLE(of, em_i2c_ids);
|
MODULE_DEVICE_TABLE(of, em_i2c_ids);
|
||||||
|
@@ -703,7 +703,7 @@ static int fsi_i2c_probe(struct device *dev)
|
|||||||
|
|
||||||
for (port_no = 0; port_no < ports; port_no++) {
|
for (port_no = 0; port_no < ports; port_no++) {
|
||||||
np = fsi_i2c_find_port_of_node(dev->of_node, port_no);
|
np = fsi_i2c_find_port_of_node(dev->of_node, port_no);
|
||||||
if (np && !of_device_is_available(np))
|
if (!of_device_is_available(np))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
port = kzalloc(sizeof(*port), GFP_KERNEL);
|
port = kzalloc(sizeof(*port), GFP_KERNEL);
|
||||||
|
@@ -54,6 +54,7 @@
|
|||||||
* Sunrise Point-H (PCH) 0xa123 32 hard yes yes yes
|
* Sunrise Point-H (PCH) 0xa123 32 hard yes yes yes
|
||||||
* Sunrise Point-LP (PCH) 0x9d23 32 hard yes yes yes
|
* Sunrise Point-LP (PCH) 0x9d23 32 hard yes yes yes
|
||||||
* DNV (SOC) 0x19df 32 hard yes yes yes
|
* DNV (SOC) 0x19df 32 hard yes yes yes
|
||||||
|
* Emmitsburg (PCH) 0x1bc9 32 hard yes yes yes
|
||||||
* Broxton (SOC) 0x5ad4 32 hard yes yes yes
|
* Broxton (SOC) 0x5ad4 32 hard yes yes yes
|
||||||
* Lewisburg (PCH) 0xa1a3 32 hard yes yes yes
|
* Lewisburg (PCH) 0xa1a3 32 hard yes yes yes
|
||||||
* Lewisburg Supersku (PCH) 0xa223 32 hard yes yes yes
|
* Lewisburg Supersku (PCH) 0xa223 32 hard yes yes yes
|
||||||
@@ -67,6 +68,7 @@
|
|||||||
* Comet Lake-H (PCH) 0x06a3 32 hard yes yes yes
|
* Comet Lake-H (PCH) 0x06a3 32 hard yes yes yes
|
||||||
* Elkhart Lake (PCH) 0x4b23 32 hard yes yes yes
|
* Elkhart Lake (PCH) 0x4b23 32 hard yes yes yes
|
||||||
* Tiger Lake-LP (PCH) 0xa0a3 32 hard yes yes yes
|
* Tiger Lake-LP (PCH) 0xa0a3 32 hard yes yes yes
|
||||||
|
* Tiger Lake-H (PCH) 0x43a3 32 hard yes yes yes
|
||||||
* Jasper Lake (SOC) 0x4da3 32 hard yes yes yes
|
* Jasper Lake (SOC) 0x4da3 32 hard yes yes yes
|
||||||
* Comet Lake-V (PCH) 0xa3a3 32 hard yes yes yes
|
* Comet Lake-V (PCH) 0xa3a3 32 hard yes yes yes
|
||||||
*
|
*
|
||||||
@@ -207,6 +209,7 @@
|
|||||||
#define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12
|
#define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12
|
||||||
#define PCI_DEVICE_ID_INTEL_CDF_SMBUS 0x18df
|
#define PCI_DEVICE_ID_INTEL_CDF_SMBUS 0x18df
|
||||||
#define PCI_DEVICE_ID_INTEL_DNV_SMBUS 0x19df
|
#define PCI_DEVICE_ID_INTEL_DNV_SMBUS 0x19df
|
||||||
|
#define PCI_DEVICE_ID_INTEL_EBG_SMBUS 0x1bc9
|
||||||
#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22
|
#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22
|
||||||
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22
|
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22
|
||||||
/* Patsburg also has three 'Integrated Device Function' SMBus controllers */
|
/* Patsburg also has three 'Integrated Device Function' SMBus controllers */
|
||||||
@@ -221,6 +224,7 @@
|
|||||||
#define PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS 0x31d4
|
#define PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS 0x31d4
|
||||||
#define PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS 0x34a3
|
#define PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS 0x34a3
|
||||||
#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
|
#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
|
||||||
|
#define PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS 0x43a3
|
||||||
#define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS 0x4b23
|
#define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS 0x4b23
|
||||||
#define PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS 0x4da3
|
#define PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS 0x4da3
|
||||||
#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4
|
#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4
|
||||||
@@ -1062,6 +1066,7 @@ static const struct pci_device_id i801_ids[] = {
|
|||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS) },
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS) },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CDF_SMBUS) },
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CDF_SMBUS) },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMBUS) },
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMBUS) },
|
||||||
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EBG_SMBUS) },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROXTON_SMBUS) },
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROXTON_SMBUS) },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS) },
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS) },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS) },
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS) },
|
||||||
@@ -1074,6 +1079,7 @@ static const struct pci_device_id i801_ids[] = {
|
|||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS) },
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS) },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS) },
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS) },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS) },
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS) },
|
||||||
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS) },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS) },
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS) },
|
||||||
{ 0, }
|
{ 0, }
|
||||||
};
|
};
|
||||||
@@ -1748,7 +1754,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||||||
case PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS:
|
case PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS:
|
||||||
case PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS:
|
case PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS:
|
||||||
case PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS:
|
case PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS:
|
||||||
|
case PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS:
|
||||||
case PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS:
|
case PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS:
|
||||||
|
case PCI_DEVICE_ID_INTEL_EBG_SMBUS:
|
||||||
priv->features |= FEATURE_BLOCK_PROC;
|
priv->features |= FEATURE_BLOCK_PROC;
|
||||||
priv->features |= FEATURE_I2C_BLOCK_READ;
|
priv->features |= FEATURE_I2C_BLOCK_READ;
|
||||||
priv->features |= FEATURE_IRQ;
|
priv->features |= FEATURE_IRQ;
|
||||||
@@ -1765,19 +1773,19 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||||||
case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1:
|
case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1:
|
||||||
case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2:
|
case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2:
|
||||||
priv->features |= FEATURE_IDF;
|
priv->features |= FEATURE_IDF;
|
||||||
/* fall through */
|
fallthrough;
|
||||||
default:
|
default:
|
||||||
priv->features |= FEATURE_BLOCK_PROC;
|
priv->features |= FEATURE_BLOCK_PROC;
|
||||||
priv->features |= FEATURE_I2C_BLOCK_READ;
|
priv->features |= FEATURE_I2C_BLOCK_READ;
|
||||||
priv->features |= FEATURE_IRQ;
|
priv->features |= FEATURE_IRQ;
|
||||||
/* fall through */
|
fallthrough;
|
||||||
case PCI_DEVICE_ID_INTEL_82801DB_3:
|
case PCI_DEVICE_ID_INTEL_82801DB_3:
|
||||||
priv->features |= FEATURE_SMBUS_PEC;
|
priv->features |= FEATURE_SMBUS_PEC;
|
||||||
priv->features |= FEATURE_BLOCK_BUFFER;
|
priv->features |= FEATURE_BLOCK_BUFFER;
|
||||||
/* fall through */
|
fallthrough;
|
||||||
case PCI_DEVICE_ID_INTEL_82801CA_3:
|
case PCI_DEVICE_ID_INTEL_82801CA_3:
|
||||||
priv->features |= FEATURE_HOST_NOTIFY;
|
priv->features |= FEATURE_HOST_NOTIFY;
|
||||||
/* fall through */
|
fallthrough;
|
||||||
case PCI_DEVICE_ID_INTEL_82801BA_2:
|
case PCI_DEVICE_ID_INTEL_82801BA_2:
|
||||||
case PCI_DEVICE_ID_INTEL_82801AB_3:
|
case PCI_DEVICE_ID_INTEL_82801AB_3:
|
||||||
case PCI_DEVICE_ID_INTEL_82801AA_3:
|
case PCI_DEVICE_ID_INTEL_82801AA_3:
|
||||||
@@ -1986,7 +1994,8 @@ static void __exit i2c_i801_exit(void)
|
|||||||
pci_unregister_driver(&i801_driver);
|
pci_unregister_driver(&i801_driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>, Jean Delvare <jdelvare@suse.de>");
|
MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
|
||||||
|
MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
|
||||||
MODULE_DESCRIPTION("I801 SMBus driver");
|
MODULE_DESCRIPTION("I801 SMBus driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
@@ -48,11 +48,13 @@
|
|||||||
|
|
||||||
#define I2C_DMA_CON_TX 0x0000
|
#define I2C_DMA_CON_TX 0x0000
|
||||||
#define I2C_DMA_CON_RX 0x0001
|
#define I2C_DMA_CON_RX 0x0001
|
||||||
|
#define I2C_DMA_ASYNC_MODE 0x0004
|
||||||
|
#define I2C_DMA_SKIP_CONFIG 0x0010
|
||||||
|
#define I2C_DMA_DIR_CHANGE 0x0200
|
||||||
#define I2C_DMA_START_EN 0x0001
|
#define I2C_DMA_START_EN 0x0001
|
||||||
#define I2C_DMA_INT_FLAG_NONE 0x0000
|
#define I2C_DMA_INT_FLAG_NONE 0x0000
|
||||||
#define I2C_DMA_CLR_FLAG 0x0000
|
#define I2C_DMA_CLR_FLAG 0x0000
|
||||||
#define I2C_DMA_HARD_RST 0x0002
|
#define I2C_DMA_HARD_RST 0x0002
|
||||||
#define I2C_DMA_4G_MODE 0x0001
|
|
||||||
|
|
||||||
#define MAX_SAMPLE_CNT_DIV 8
|
#define MAX_SAMPLE_CNT_DIV 8
|
||||||
#define MAX_STEP_CNT_DIV 64
|
#define MAX_STEP_CNT_DIV 64
|
||||||
@@ -201,10 +203,11 @@ struct mtk_i2c_compatible {
|
|||||||
unsigned char dcm: 1;
|
unsigned char dcm: 1;
|
||||||
unsigned char auto_restart: 1;
|
unsigned char auto_restart: 1;
|
||||||
unsigned char aux_len_reg: 1;
|
unsigned char aux_len_reg: 1;
|
||||||
unsigned char support_33bits: 1;
|
|
||||||
unsigned char timing_adjust: 1;
|
unsigned char timing_adjust: 1;
|
||||||
unsigned char dma_sync: 1;
|
unsigned char dma_sync: 1;
|
||||||
unsigned char ltiming_adjust: 1;
|
unsigned char ltiming_adjust: 1;
|
||||||
|
unsigned char apdma_sync: 1;
|
||||||
|
unsigned char max_dma_support;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mtk_i2c_ac_timing {
|
struct mtk_i2c_ac_timing {
|
||||||
@@ -250,14 +253,13 @@ struct mtk_i2c {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* struct i2c_spec_values:
|
* struct i2c_spec_values:
|
||||||
* min_low_ns: min LOW period of the SCL clock
|
* @min_low_ns: min LOW period of the SCL clock
|
||||||
* min_su_sta_ns: min set-up time for a repeated START condition
|
* @min_su_sta_ns: min set-up time for a repeated START condition
|
||||||
* max_hd_dat_ns: max data hold time
|
* @max_hd_dat_ns: max data hold time
|
||||||
* min_su_dat_ns: min data set-up time
|
* @min_su_dat_ns: min data set-up time
|
||||||
*/
|
*/
|
||||||
struct i2c_spec_values {
|
struct i2c_spec_values {
|
||||||
unsigned int min_low_ns;
|
unsigned int min_low_ns;
|
||||||
unsigned int min_high_ns;
|
|
||||||
unsigned int min_su_sta_ns;
|
unsigned int min_su_sta_ns;
|
||||||
unsigned int max_hd_dat_ns;
|
unsigned int max_hd_dat_ns;
|
||||||
unsigned int min_su_dat_ns;
|
unsigned int min_su_dat_ns;
|
||||||
@@ -307,10 +309,11 @@ static const struct mtk_i2c_compatible mt2712_compat = {
|
|||||||
.dcm = 1,
|
.dcm = 1,
|
||||||
.auto_restart = 1,
|
.auto_restart = 1,
|
||||||
.aux_len_reg = 1,
|
.aux_len_reg = 1,
|
||||||
.support_33bits = 1,
|
|
||||||
.timing_adjust = 1,
|
.timing_adjust = 1,
|
||||||
.dma_sync = 0,
|
.dma_sync = 0,
|
||||||
.ltiming_adjust = 0,
|
.ltiming_adjust = 0,
|
||||||
|
.apdma_sync = 0,
|
||||||
|
.max_dma_support = 33,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct mtk_i2c_compatible mt6577_compat = {
|
static const struct mtk_i2c_compatible mt6577_compat = {
|
||||||
@@ -320,10 +323,11 @@ static const struct mtk_i2c_compatible mt6577_compat = {
|
|||||||
.dcm = 1,
|
.dcm = 1,
|
||||||
.auto_restart = 0,
|
.auto_restart = 0,
|
||||||
.aux_len_reg = 0,
|
.aux_len_reg = 0,
|
||||||
.support_33bits = 0,
|
|
||||||
.timing_adjust = 0,
|
.timing_adjust = 0,
|
||||||
.dma_sync = 0,
|
.dma_sync = 0,
|
||||||
.ltiming_adjust = 0,
|
.ltiming_adjust = 0,
|
||||||
|
.apdma_sync = 0,
|
||||||
|
.max_dma_support = 32,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct mtk_i2c_compatible mt6589_compat = {
|
static const struct mtk_i2c_compatible mt6589_compat = {
|
||||||
@@ -333,10 +337,11 @@ static const struct mtk_i2c_compatible mt6589_compat = {
|
|||||||
.dcm = 0,
|
.dcm = 0,
|
||||||
.auto_restart = 0,
|
.auto_restart = 0,
|
||||||
.aux_len_reg = 0,
|
.aux_len_reg = 0,
|
||||||
.support_33bits = 0,
|
|
||||||
.timing_adjust = 0,
|
.timing_adjust = 0,
|
||||||
.dma_sync = 0,
|
.dma_sync = 0,
|
||||||
.ltiming_adjust = 0,
|
.ltiming_adjust = 0,
|
||||||
|
.apdma_sync = 0,
|
||||||
|
.max_dma_support = 32,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct mtk_i2c_compatible mt7622_compat = {
|
static const struct mtk_i2c_compatible mt7622_compat = {
|
||||||
@@ -346,10 +351,11 @@ static const struct mtk_i2c_compatible mt7622_compat = {
|
|||||||
.dcm = 1,
|
.dcm = 1,
|
||||||
.auto_restart = 1,
|
.auto_restart = 1,
|
||||||
.aux_len_reg = 1,
|
.aux_len_reg = 1,
|
||||||
.support_33bits = 0,
|
|
||||||
.timing_adjust = 0,
|
.timing_adjust = 0,
|
||||||
.dma_sync = 0,
|
.dma_sync = 0,
|
||||||
.ltiming_adjust = 0,
|
.ltiming_adjust = 0,
|
||||||
|
.apdma_sync = 0,
|
||||||
|
.max_dma_support = 32,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct mtk_i2c_compatible mt8173_compat = {
|
static const struct mtk_i2c_compatible mt8173_compat = {
|
||||||
@@ -358,10 +364,11 @@ static const struct mtk_i2c_compatible mt8173_compat = {
|
|||||||
.dcm = 1,
|
.dcm = 1,
|
||||||
.auto_restart = 1,
|
.auto_restart = 1,
|
||||||
.aux_len_reg = 1,
|
.aux_len_reg = 1,
|
||||||
.support_33bits = 1,
|
|
||||||
.timing_adjust = 0,
|
.timing_adjust = 0,
|
||||||
.dma_sync = 0,
|
.dma_sync = 0,
|
||||||
.ltiming_adjust = 0,
|
.ltiming_adjust = 0,
|
||||||
|
.apdma_sync = 0,
|
||||||
|
.max_dma_support = 33,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct mtk_i2c_compatible mt8183_compat = {
|
static const struct mtk_i2c_compatible mt8183_compat = {
|
||||||
@@ -371,10 +378,25 @@ static const struct mtk_i2c_compatible mt8183_compat = {
|
|||||||
.dcm = 0,
|
.dcm = 0,
|
||||||
.auto_restart = 1,
|
.auto_restart = 1,
|
||||||
.aux_len_reg = 1,
|
.aux_len_reg = 1,
|
||||||
.support_33bits = 1,
|
|
||||||
.timing_adjust = 1,
|
.timing_adjust = 1,
|
||||||
.dma_sync = 1,
|
.dma_sync = 1,
|
||||||
.ltiming_adjust = 1,
|
.ltiming_adjust = 1,
|
||||||
|
.apdma_sync = 0,
|
||||||
|
.max_dma_support = 33,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct mtk_i2c_compatible mt8192_compat = {
|
||||||
|
.quirks = &mt8183_i2c_quirks,
|
||||||
|
.regs = mt_i2c_regs_v2,
|
||||||
|
.pmic_i2c = 0,
|
||||||
|
.dcm = 0,
|
||||||
|
.auto_restart = 1,
|
||||||
|
.aux_len_reg = 1,
|
||||||
|
.timing_adjust = 1,
|
||||||
|
.dma_sync = 1,
|
||||||
|
.ltiming_adjust = 1,
|
||||||
|
.apdma_sync = 1,
|
||||||
|
.max_dma_support = 36,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id mtk_i2c_of_match[] = {
|
static const struct of_device_id mtk_i2c_of_match[] = {
|
||||||
@@ -384,6 +406,7 @@ static const struct of_device_id mtk_i2c_of_match[] = {
|
|||||||
{ .compatible = "mediatek,mt7622-i2c", .data = &mt7622_compat },
|
{ .compatible = "mediatek,mt7622-i2c", .data = &mt7622_compat },
|
||||||
{ .compatible = "mediatek,mt8173-i2c", .data = &mt8173_compat },
|
{ .compatible = "mediatek,mt8173-i2c", .data = &mt8173_compat },
|
||||||
{ .compatible = "mediatek,mt8183-i2c", .data = &mt8183_compat },
|
{ .compatible = "mediatek,mt8183-i2c", .data = &mt8183_compat },
|
||||||
|
{ .compatible = "mediatek,mt8192-i2c", .data = &mt8192_compat },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, mtk_i2c_of_match);
|
MODULE_DEVICE_TABLE(of, mtk_i2c_of_match);
|
||||||
@@ -786,11 +809,6 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 mtk_i2c_set_4g_mode(dma_addr_t addr)
|
|
||||||
{
|
|
||||||
return (addr & BIT_ULL(32)) ? I2C_DMA_4G_MODE : I2C_DMA_CLR_FLAG;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
||||||
int num, int left_num)
|
int num, int left_num)
|
||||||
{
|
{
|
||||||
@@ -798,6 +816,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
|||||||
u16 start_reg;
|
u16 start_reg;
|
||||||
u16 control_reg;
|
u16 control_reg;
|
||||||
u16 restart_flag = 0;
|
u16 restart_flag = 0;
|
||||||
|
u16 dma_sync = 0;
|
||||||
u32 reg_4g_mode;
|
u32 reg_4g_mode;
|
||||||
u8 *dma_rd_buf = NULL;
|
u8 *dma_rd_buf = NULL;
|
||||||
u8 *dma_wr_buf = NULL;
|
u8 *dma_wr_buf = NULL;
|
||||||
@@ -851,10 +870,16 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
|||||||
mtk_i2c_writew(i2c, num, OFFSET_TRANSAC_LEN);
|
mtk_i2c_writew(i2c, num, OFFSET_TRANSAC_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i2c->dev_comp->apdma_sync) {
|
||||||
|
dma_sync = I2C_DMA_SKIP_CONFIG | I2C_DMA_ASYNC_MODE;
|
||||||
|
if (i2c->op == I2C_MASTER_WRRD)
|
||||||
|
dma_sync |= I2C_DMA_DIR_CHANGE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Prepare buffer data to start transfer */
|
/* Prepare buffer data to start transfer */
|
||||||
if (i2c->op == I2C_MASTER_RD) {
|
if (i2c->op == I2C_MASTER_RD) {
|
||||||
writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG);
|
writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG);
|
||||||
writel(I2C_DMA_CON_RX, i2c->pdmabase + OFFSET_CON);
|
writel(I2C_DMA_CON_RX | dma_sync, i2c->pdmabase + OFFSET_CON);
|
||||||
|
|
||||||
dma_rd_buf = i2c_get_dma_safe_msg_buf(msgs, 1);
|
dma_rd_buf = i2c_get_dma_safe_msg_buf(msgs, 1);
|
||||||
if (!dma_rd_buf)
|
if (!dma_rd_buf)
|
||||||
@@ -868,8 +893,8 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i2c->dev_comp->support_33bits) {
|
if (i2c->dev_comp->max_dma_support > 32) {
|
||||||
reg_4g_mode = mtk_i2c_set_4g_mode(rpaddr);
|
reg_4g_mode = upper_32_bits(rpaddr);
|
||||||
writel(reg_4g_mode, i2c->pdmabase + OFFSET_RX_4G_MODE);
|
writel(reg_4g_mode, i2c->pdmabase + OFFSET_RX_4G_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -877,7 +902,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
|||||||
writel(msgs->len, i2c->pdmabase + OFFSET_RX_LEN);
|
writel(msgs->len, i2c->pdmabase + OFFSET_RX_LEN);
|
||||||
} else if (i2c->op == I2C_MASTER_WR) {
|
} else if (i2c->op == I2C_MASTER_WR) {
|
||||||
writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG);
|
writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG);
|
||||||
writel(I2C_DMA_CON_TX, i2c->pdmabase + OFFSET_CON);
|
writel(I2C_DMA_CON_TX | dma_sync, i2c->pdmabase + OFFSET_CON);
|
||||||
|
|
||||||
dma_wr_buf = i2c_get_dma_safe_msg_buf(msgs, 1);
|
dma_wr_buf = i2c_get_dma_safe_msg_buf(msgs, 1);
|
||||||
if (!dma_wr_buf)
|
if (!dma_wr_buf)
|
||||||
@@ -891,8 +916,8 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i2c->dev_comp->support_33bits) {
|
if (i2c->dev_comp->max_dma_support > 32) {
|
||||||
reg_4g_mode = mtk_i2c_set_4g_mode(wpaddr);
|
reg_4g_mode = upper_32_bits(wpaddr);
|
||||||
writel(reg_4g_mode, i2c->pdmabase + OFFSET_TX_4G_MODE);
|
writel(reg_4g_mode, i2c->pdmabase + OFFSET_TX_4G_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -900,7 +925,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
|||||||
writel(msgs->len, i2c->pdmabase + OFFSET_TX_LEN);
|
writel(msgs->len, i2c->pdmabase + OFFSET_TX_LEN);
|
||||||
} else {
|
} else {
|
||||||
writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_INT_FLAG);
|
writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_INT_FLAG);
|
||||||
writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_CON);
|
writel(I2C_DMA_CLR_FLAG | dma_sync, i2c->pdmabase + OFFSET_CON);
|
||||||
|
|
||||||
dma_wr_buf = i2c_get_dma_safe_msg_buf(msgs, 1);
|
dma_wr_buf = i2c_get_dma_safe_msg_buf(msgs, 1);
|
||||||
if (!dma_wr_buf)
|
if (!dma_wr_buf)
|
||||||
@@ -937,11 +962,11 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i2c->dev_comp->support_33bits) {
|
if (i2c->dev_comp->max_dma_support > 32) {
|
||||||
reg_4g_mode = mtk_i2c_set_4g_mode(wpaddr);
|
reg_4g_mode = upper_32_bits(wpaddr);
|
||||||
writel(reg_4g_mode, i2c->pdmabase + OFFSET_TX_4G_MODE);
|
writel(reg_4g_mode, i2c->pdmabase + OFFSET_TX_4G_MODE);
|
||||||
|
|
||||||
reg_4g_mode = mtk_i2c_set_4g_mode(rpaddr);
|
reg_4g_mode = upper_32_bits(rpaddr);
|
||||||
writel(reg_4g_mode, i2c->pdmabase + OFFSET_RX_4G_MODE);
|
writel(reg_4g_mode, i2c->pdmabase + OFFSET_RX_4G_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1215,8 +1240,9 @@ static int mtk_i2c_probe(struct platform_device *pdev)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i2c->dev_comp->support_33bits) {
|
if (i2c->dev_comp->max_dma_support > 32) {
|
||||||
ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(33));
|
ret = dma_set_mask(&pdev->dev,
|
||||||
|
DMA_BIT_MASK(i2c->dev_comp->max_dma_support));
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "dma_set_mask return error.\n");
|
dev_err(&pdev->dev, "dma_set_mask return error.\n");
|
||||||
return ret;
|
return ret;
|
||||||
|
@@ -251,7 +251,7 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
|
|||||||
MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;
|
MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* FALLTHRU */
|
fallthrough;
|
||||||
case MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK: /* 0xd0 */
|
case MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK: /* 0xd0 */
|
||||||
case MV64XXX_I2C_STATUS_MAST_WR_ACK: /* 0x28 */
|
case MV64XXX_I2C_STATUS_MAST_WR_ACK: /* 0x28 */
|
||||||
if ((drv_data->bytes_left == 0)
|
if ((drv_data->bytes_left == 0)
|
||||||
@@ -282,14 +282,14 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
|
|||||||
MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;
|
MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* FALLTHRU */
|
fallthrough;
|
||||||
case MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK: /* 0xe0 */
|
case MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK: /* 0xe0 */
|
||||||
if (drv_data->bytes_left == 0) {
|
if (drv_data->bytes_left == 0) {
|
||||||
drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
|
drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
|
||||||
drv_data->state = MV64XXX_I2C_STATE_IDLE;
|
drv_data->state = MV64XXX_I2C_STATE_IDLE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* FALLTHRU */
|
fallthrough;
|
||||||
case MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK: /* 0x50 */
|
case MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK: /* 0x50 */
|
||||||
if (status != MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK)
|
if (status != MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK)
|
||||||
drv_data->action = MV64XXX_I2C_ACTION_CONTINUE;
|
drv_data->action = MV64XXX_I2C_ACTION_CONTINUE;
|
||||||
@@ -417,8 +417,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
|
|||||||
"mv64xxx_i2c_do_action: Invalid action: %d\n",
|
"mv64xxx_i2c_do_action: Invalid action: %d\n",
|
||||||
drv_data->action);
|
drv_data->action);
|
||||||
drv_data->rc = -EIO;
|
drv_data->rc = -EIO;
|
||||||
|
fallthrough;
|
||||||
/* FALLTHRU */
|
|
||||||
case MV64XXX_I2C_ACTION_SEND_STOP:
|
case MV64XXX_I2C_ACTION_SEND_STOP:
|
||||||
drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
|
drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
|
||||||
writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
|
writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
|
||||||
|
@@ -1122,6 +1122,7 @@ static void __exit nmk_i2c_exit(void)
|
|||||||
subsys_initcall(nmk_i2c_init);
|
subsys_initcall(nmk_i2c_init);
|
||||||
module_exit(nmk_i2c_exit);
|
module_exit(nmk_i2c_exit);
|
||||||
|
|
||||||
MODULE_AUTHOR("Sachin Verma, Srinidhi KASAGAR");
|
MODULE_AUTHOR("Sachin Verma");
|
||||||
|
MODULE_AUTHOR("Srinidhi KASAGAR");
|
||||||
MODULE_DESCRIPTION("Nomadik/Ux500 I2C driver");
|
MODULE_DESCRIPTION("Nomadik/Ux500 I2C driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
@@ -1032,7 +1032,7 @@ static struct pci_driver piix4_driver = {
|
|||||||
|
|
||||||
module_pci_driver(piix4_driver);
|
module_pci_driver(piix4_driver);
|
||||||
|
|
||||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
|
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
|
||||||
"Philip Edelbrock <phil@netroedge.com>");
|
MODULE_AUTHOR("Philip Edelbrock <phil@netroedge.com>");
|
||||||
MODULE_DESCRIPTION("PIIX4 SMBus driver");
|
MODULE_DESCRIPTION("PIIX4 SMBus driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
@@ -781,7 +781,8 @@ static void __exit i2c_adap_pnx_exit(void)
|
|||||||
platform_driver_unregister(&i2c_pnx_driver);
|
platform_driver_unregister(&i2c_pnx_driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
MODULE_AUTHOR("Vitaly Wool, Dennis Kovalev <source@mvista.com>");
|
MODULE_AUTHOR("Vitaly Wool");
|
||||||
|
MODULE_AUTHOR("Dennis Kovalev <source@mvista.com>");
|
||||||
MODULE_DESCRIPTION("I2C driver for Philips IP3204-based I2C busses");
|
MODULE_DESCRIPTION("I2C driver for Philips IP3204-based I2C busses");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_ALIAS("platform:pnx-i2c");
|
MODULE_ALIAS("platform:pnx-i2c");
|
||||||
|
@@ -583,13 +583,14 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
|
|||||||
rcar_i2c_write(priv, ICSIER, SDR | SSR | SAR);
|
rcar_i2c_write(priv, ICSIER, SDR | SSR | SAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
rcar_i2c_write(priv, ICSSR, ~SAR & 0xff);
|
/* Clear SSR, too, because of old STOPs to other clients than us */
|
||||||
|
rcar_i2c_write(priv, ICSSR, ~(SAR | SSR) & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* master sent stop */
|
/* master sent stop */
|
||||||
if (ssr_filtered & SSR) {
|
if (ssr_filtered & SSR) {
|
||||||
i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value);
|
i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value);
|
||||||
rcar_i2c_write(priv, ICSIER, SAR | SSR);
|
rcar_i2c_write(priv, ICSIER, SAR);
|
||||||
rcar_i2c_write(priv, ICSSR, ~SSR & 0xff);
|
rcar_i2c_write(priv, ICSSR, ~SSR & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -853,7 +854,7 @@ static int rcar_reg_slave(struct i2c_client *slave)
|
|||||||
priv->slave = slave;
|
priv->slave = slave;
|
||||||
rcar_i2c_write(priv, ICSAR, slave->addr);
|
rcar_i2c_write(priv, ICSAR, slave->addr);
|
||||||
rcar_i2c_write(priv, ICSSR, 0);
|
rcar_i2c_write(priv, ICSSR, 0);
|
||||||
rcar_i2c_write(priv, ICSIER, SAR | SSR);
|
rcar_i2c_write(priv, ICSIER, SAR);
|
||||||
rcar_i2c_write(priv, ICSCR, SIE | SDBS);
|
rcar_i2c_write(priv, ICSCR, SIE | SDBS);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -865,12 +866,14 @@ static int rcar_unreg_slave(struct i2c_client *slave)
|
|||||||
|
|
||||||
WARN_ON(!priv->slave);
|
WARN_ON(!priv->slave);
|
||||||
|
|
||||||
/* disable irqs and ensure none is running before clearing ptr */
|
/* ensure no irq is running before clearing ptr */
|
||||||
|
disable_irq(priv->irq);
|
||||||
rcar_i2c_write(priv, ICSIER, 0);
|
rcar_i2c_write(priv, ICSIER, 0);
|
||||||
rcar_i2c_write(priv, ICSCR, 0);
|
rcar_i2c_write(priv, ICSSR, 0);
|
||||||
|
enable_irq(priv->irq);
|
||||||
|
rcar_i2c_write(priv, ICSCR, SDBS);
|
||||||
rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */
|
rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */
|
||||||
|
|
||||||
synchronize_irq(priv->irq);
|
|
||||||
priv->slave = NULL;
|
priv->slave = NULL;
|
||||||
|
|
||||||
pm_runtime_put(rcar_i2c_priv_to_dev(priv));
|
pm_runtime_put(rcar_i2c_priv_to_dev(priv));
|
||||||
|
@@ -10,6 +10,7 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/iopoll.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
@@ -1040,8 +1041,21 @@ static int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rk3x_i2c_xfer(struct i2c_adapter *adap,
|
static int rk3x_i2c_wait_xfer_poll(struct rk3x_i2c *i2c)
|
||||||
struct i2c_msg *msgs, int num)
|
{
|
||||||
|
ktime_t timeout = ktime_add_ms(ktime_get(), WAIT_TIMEOUT);
|
||||||
|
|
||||||
|
while (READ_ONCE(i2c->busy) &&
|
||||||
|
ktime_compare(ktime_get(), timeout) < 0) {
|
||||||
|
udelay(5);
|
||||||
|
rk3x_i2c_irq(0, i2c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !i2c->busy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rk3x_i2c_xfer_common(struct i2c_adapter *adap,
|
||||||
|
struct i2c_msg *msgs, int num, bool polling)
|
||||||
{
|
{
|
||||||
struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data;
|
struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data;
|
||||||
unsigned long timeout, flags;
|
unsigned long timeout, flags;
|
||||||
@@ -1075,8 +1089,12 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
|
|||||||
|
|
||||||
rk3x_i2c_start(i2c);
|
rk3x_i2c_start(i2c);
|
||||||
|
|
||||||
timeout = wait_event_timeout(i2c->wait, !i2c->busy,
|
if (!polling) {
|
||||||
msecs_to_jiffies(WAIT_TIMEOUT));
|
timeout = wait_event_timeout(i2c->wait, !i2c->busy,
|
||||||
|
msecs_to_jiffies(WAIT_TIMEOUT));
|
||||||
|
} else {
|
||||||
|
timeout = rk3x_i2c_wait_xfer_poll(i2c);
|
||||||
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&i2c->lock, flags);
|
spin_lock_irqsave(&i2c->lock, flags);
|
||||||
|
|
||||||
@@ -1110,6 +1128,18 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
|
|||||||
return ret < 0 ? ret : num;
|
return ret < 0 ? ret : num;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rk3x_i2c_xfer(struct i2c_adapter *adap,
|
||||||
|
struct i2c_msg *msgs, int num)
|
||||||
|
{
|
||||||
|
return rk3x_i2c_xfer_common(adap, msgs, num, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rk3x_i2c_xfer_polling(struct i2c_adapter *adap,
|
||||||
|
struct i2c_msg *msgs, int num)
|
||||||
|
{
|
||||||
|
return rk3x_i2c_xfer_common(adap, msgs, num, true);
|
||||||
|
}
|
||||||
|
|
||||||
static __maybe_unused int rk3x_i2c_resume(struct device *dev)
|
static __maybe_unused int rk3x_i2c_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct rk3x_i2c *i2c = dev_get_drvdata(dev);
|
struct rk3x_i2c *i2c = dev_get_drvdata(dev);
|
||||||
@@ -1126,6 +1156,7 @@ static u32 rk3x_i2c_func(struct i2c_adapter *adap)
|
|||||||
|
|
||||||
static const struct i2c_algorithm rk3x_i2c_algorithm = {
|
static const struct i2c_algorithm rk3x_i2c_algorithm = {
|
||||||
.master_xfer = rk3x_i2c_xfer,
|
.master_xfer = rk3x_i2c_xfer,
|
||||||
|
.master_xfer_atomic = rk3x_i2c_xfer_polling,
|
||||||
.functionality = rk3x_i2c_func,
|
.functionality = rk3x_i2c_func,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -932,6 +932,7 @@ static void __exit sh_mobile_i2c_adap_exit(void)
|
|||||||
module_exit(sh_mobile_i2c_adap_exit);
|
module_exit(sh_mobile_i2c_adap_exit);
|
||||||
|
|
||||||
MODULE_DESCRIPTION("SuperH Mobile I2C Bus Controller driver");
|
MODULE_DESCRIPTION("SuperH Mobile I2C Bus Controller driver");
|
||||||
MODULE_AUTHOR("Magnus Damm and Wolfram Sang");
|
MODULE_AUTHOR("Magnus Damm");
|
||||||
|
MODULE_AUTHOR("Wolfram Sang");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
MODULE_ALIAS("platform:i2c-sh_mobile");
|
MODULE_ALIAS("platform:i2c-sh_mobile");
|
||||||
|
@@ -180,6 +180,7 @@ static void __exit i2c_sibyte_exit(void)
|
|||||||
module_init(i2c_sibyte_init);
|
module_init(i2c_sibyte_init);
|
||||||
module_exit(i2c_sibyte_exit);
|
module_exit(i2c_sibyte_exit);
|
||||||
|
|
||||||
MODULE_AUTHOR("Kip Walker (Broadcom Corp.), Steven J. Hill <sjhill@realitydiluted.com>");
|
MODULE_AUTHOR("Kip Walker (Broadcom Corp.)");
|
||||||
|
MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>");
|
||||||
MODULE_DESCRIPTION("SMBus adapter routines for SiByte boards");
|
MODULE_DESCRIPTION("SMBus adapter routines for SiByte boards");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
@@ -470,6 +470,6 @@ static struct platform_driver i2c_sirfsoc_driver = {
|
|||||||
module_platform_driver(i2c_sirfsoc_driver);
|
module_platform_driver(i2c_sirfsoc_driver);
|
||||||
|
|
||||||
MODULE_DESCRIPTION("SiRF SoC I2C master controller driver");
|
MODULE_DESCRIPTION("SiRF SoC I2C master controller driver");
|
||||||
MODULE_AUTHOR("Zhiwu Song <Zhiwu.Song@csr.com>, "
|
MODULE_AUTHOR("Zhiwu Song <Zhiwu.Song@csr.com>");
|
||||||
"Xiangzhen Ye <Xiangzhen.Ye@csr.com>");
|
MODULE_AUTHOR("Xiangzhen Ye <Xiangzhen.Ye@csr.com>");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
@@ -398,8 +398,7 @@ static irqreturn_t synquacer_i2c_isr(int irq, void *dev_id)
|
|||||||
|
|
||||||
if (i2c->state == STATE_READ)
|
if (i2c->state == STATE_READ)
|
||||||
goto prepare_read;
|
goto prepare_read;
|
||||||
|
fallthrough;
|
||||||
/* fall through */
|
|
||||||
|
|
||||||
case STATE_WRITE:
|
case STATE_WRITE:
|
||||||
if (bsr & SYNQUACER_I2C_BSR_LRB) {
|
if (bsr & SYNQUACER_I2C_BSR_LRB) {
|
||||||
|
@@ -293,6 +293,8 @@ struct tegra_i2c_dev {
|
|||||||
bool is_curr_atomic_xfer;
|
bool is_curr_atomic_xfer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit);
|
||||||
|
|
||||||
static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
|
static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
|
||||||
unsigned long reg)
|
unsigned long reg)
|
||||||
{
|
{
|
||||||
@@ -419,7 +421,7 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev)
|
|||||||
dma_addr_t dma_phys;
|
dma_addr_t dma_phys;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!i2c_dev->hw->has_apb_dma)
|
if (!i2c_dev->hw->has_apb_dma || i2c_dev->is_vi)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!IS_ENABLED(CONFIG_TEGRA20_APB_DMA)) {
|
if (!IS_ENABLED(CONFIG_TEGRA20_APB_DMA)) {
|
||||||
@@ -655,32 +657,47 @@ static int __maybe_unused tegra_i2c_runtime_resume(struct device *dev)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (!i2c_dev->hw->has_single_clk_source) {
|
ret = clk_enable(i2c_dev->fast_clk);
|
||||||
ret = clk_enable(i2c_dev->fast_clk);
|
if (ret < 0) {
|
||||||
if (ret < 0) {
|
dev_err(i2c_dev->dev,
|
||||||
dev_err(i2c_dev->dev,
|
"Enabling fast clk failed, err %d\n", ret);
|
||||||
"Enabling fast clk failed, err %d\n", ret);
|
return ret;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i2c_dev->slow_clk) {
|
ret = clk_enable(i2c_dev->slow_clk);
|
||||||
ret = clk_enable(i2c_dev->slow_clk);
|
if (ret < 0) {
|
||||||
if (ret < 0) {
|
dev_err(dev, "failed to enable slow clock: %d\n", ret);
|
||||||
dev_err(dev, "failed to enable slow clock: %d\n", ret);
|
goto disable_fast_clk;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = clk_enable(i2c_dev->div_clk);
|
ret = clk_enable(i2c_dev->div_clk);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(i2c_dev->dev,
|
dev_err(i2c_dev->dev,
|
||||||
"Enabling div clk failed, err %d\n", ret);
|
"Enabling div clk failed, err %d\n", ret);
|
||||||
clk_disable(i2c_dev->fast_clk);
|
goto disable_slow_clk;
|
||||||
return ret;
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* VI I2C device is attached to VE power domain which goes through
|
||||||
|
* power ON/OFF during PM runtime resume/suspend. So, controller
|
||||||
|
* should go through reset and need to re-initialize after power
|
||||||
|
* domain ON.
|
||||||
|
*/
|
||||||
|
if (i2c_dev->is_vi) {
|
||||||
|
ret = tegra_i2c_init(i2c_dev, true);
|
||||||
|
if (ret)
|
||||||
|
goto disable_div_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
disable_div_clk:
|
||||||
|
clk_disable(i2c_dev->div_clk);
|
||||||
|
disable_slow_clk:
|
||||||
|
clk_disable(i2c_dev->slow_clk);
|
||||||
|
disable_fast_clk:
|
||||||
|
clk_disable(i2c_dev->fast_clk);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __maybe_unused tegra_i2c_runtime_suspend(struct device *dev)
|
static int __maybe_unused tegra_i2c_runtime_suspend(struct device *dev)
|
||||||
@@ -688,12 +705,8 @@ static int __maybe_unused tegra_i2c_runtime_suspend(struct device *dev)
|
|||||||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||||
|
|
||||||
clk_disable(i2c_dev->div_clk);
|
clk_disable(i2c_dev->div_clk);
|
||||||
|
clk_disable(i2c_dev->slow_clk);
|
||||||
if (i2c_dev->slow_clk)
|
clk_disable(i2c_dev->fast_clk);
|
||||||
clk_disable(i2c_dev->slow_clk);
|
|
||||||
|
|
||||||
if (!i2c_dev->hw->has_single_clk_source)
|
|
||||||
clk_disable(i2c_dev->fast_clk);
|
|
||||||
|
|
||||||
return pinctrl_pm_select_idle_state(i2c_dev->dev);
|
return pinctrl_pm_select_idle_state(i2c_dev->dev);
|
||||||
}
|
}
|
||||||
@@ -1716,20 +1729,16 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
platform_set_drvdata(pdev, i2c_dev);
|
platform_set_drvdata(pdev, i2c_dev);
|
||||||
|
|
||||||
if (!i2c_dev->hw->has_single_clk_source) {
|
ret = clk_prepare(i2c_dev->fast_clk);
|
||||||
ret = clk_prepare(i2c_dev->fast_clk);
|
if (ret < 0) {
|
||||||
if (ret < 0) {
|
dev_err(i2c_dev->dev, "Clock prepare failed %d\n", ret);
|
||||||
dev_err(i2c_dev->dev, "Clock prepare failed %d\n", ret);
|
return ret;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i2c_dev->slow_clk) {
|
ret = clk_prepare(i2c_dev->slow_clk);
|
||||||
ret = clk_prepare(i2c_dev->slow_clk);
|
if (ret < 0) {
|
||||||
if (ret < 0) {
|
dev_err(dev, "failed to prepare slow clock: %d\n", ret);
|
||||||
dev_err(dev, "failed to prepare slow clock: %d\n", ret);
|
goto unprepare_fast_clk;
|
||||||
goto unprepare_fast_clk;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i2c_dev->bus_clk_rate > I2C_MAX_FAST_MODE_FREQ &&
|
if (i2c_dev->bus_clk_rate > I2C_MAX_FAST_MODE_FREQ &&
|
||||||
@@ -1750,7 +1759,15 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
|||||||
goto unprepare_slow_clk;
|
goto unprepare_slow_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
pm_runtime_irq_safe(&pdev->dev);
|
/*
|
||||||
|
* VI I2C is in VE power domain which is not always on and not
|
||||||
|
* an IRQ safe. So, IRQ safe device can't be attached to a non-IRQ
|
||||||
|
* safe domain as it prevents powering off the PM domain.
|
||||||
|
* Also, VI I2C device don't need to use runtime IRQ safe as it will
|
||||||
|
* not be used for atomic transfers.
|
||||||
|
*/
|
||||||
|
if (!i2c_dev->is_vi)
|
||||||
|
pm_runtime_irq_safe(&pdev->dev);
|
||||||
pm_runtime_enable(&pdev->dev);
|
pm_runtime_enable(&pdev->dev);
|
||||||
if (!pm_runtime_enabled(&pdev->dev)) {
|
if (!pm_runtime_enabled(&pdev->dev)) {
|
||||||
ret = tegra_i2c_runtime_resume(&pdev->dev);
|
ret = tegra_i2c_runtime_resume(&pdev->dev);
|
||||||
@@ -1835,12 +1852,10 @@ unprepare_div_clk:
|
|||||||
clk_unprepare(i2c_dev->div_clk);
|
clk_unprepare(i2c_dev->div_clk);
|
||||||
|
|
||||||
unprepare_slow_clk:
|
unprepare_slow_clk:
|
||||||
if (i2c_dev->is_vi)
|
clk_unprepare(i2c_dev->slow_clk);
|
||||||
clk_unprepare(i2c_dev->slow_clk);
|
|
||||||
|
|
||||||
unprepare_fast_clk:
|
unprepare_fast_clk:
|
||||||
if (!i2c_dev->hw->has_single_clk_source)
|
clk_unprepare(i2c_dev->fast_clk);
|
||||||
clk_unprepare(i2c_dev->fast_clk);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1859,12 +1874,8 @@ static int tegra_i2c_remove(struct platform_device *pdev)
|
|||||||
tegra_i2c_runtime_suspend(&pdev->dev);
|
tegra_i2c_runtime_suspend(&pdev->dev);
|
||||||
|
|
||||||
clk_unprepare(i2c_dev->div_clk);
|
clk_unprepare(i2c_dev->div_clk);
|
||||||
|
clk_unprepare(i2c_dev->slow_clk);
|
||||||
if (i2c_dev->slow_clk)
|
clk_unprepare(i2c_dev->fast_clk);
|
||||||
clk_unprepare(i2c_dev->slow_clk);
|
|
||||||
|
|
||||||
if (!i2c_dev->hw->has_single_clk_source)
|
|
||||||
clk_unprepare(i2c_dev->fast_clk);
|
|
||||||
|
|
||||||
tegra_i2c_release_dma(i2c_dev);
|
tegra_i2c_release_dma(i2c_dev);
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -228,7 +228,7 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
|
|||||||
goto exit_unsupported;
|
goto exit_unsupported;
|
||||||
if (read_write == I2C_SMBUS_READ)
|
if (read_write == I2C_SMBUS_READ)
|
||||||
outb_p(data->block[0], SMBHSTDAT0);
|
outb_p(data->block[0], SMBHSTDAT0);
|
||||||
/* Fall through */
|
fallthrough;
|
||||||
case I2C_SMBUS_BLOCK_DATA:
|
case I2C_SMBUS_BLOCK_DATA:
|
||||||
outb_p(command, SMBHSTCMD);
|
outb_p(command, SMBHSTCMD);
|
||||||
if (read_write == I2C_SMBUS_WRITE) {
|
if (read_write == I2C_SMBUS_WRITE) {
|
||||||
@@ -489,9 +489,9 @@ static void __exit i2c_vt596_exit(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MODULE_AUTHOR("Kyosti Malkki <kmalkki@cc.hut.fi>, "
|
MODULE_AUTHOR("Kyosti Malkki <kmalkki@cc.hut.fi>");
|
||||||
"Mark D. Studebaker <mdsxyz123@yahoo.com> and "
|
MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
|
||||||
"Jean Delvare <jdelvare@suse.de>");
|
MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
|
||||||
MODULE_DESCRIPTION("vt82c596 SMBus driver");
|
MODULE_DESCRIPTION("vt82c596 SMBus driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
@@ -151,7 +151,7 @@ static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
|
|||||||
|
|
||||||
case state_repeat_start:
|
case state_repeat_start:
|
||||||
outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
|
outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
|
||||||
/* fallthrough */
|
fallthrough;
|
||||||
|
|
||||||
case state_quick:
|
case state_quick:
|
||||||
if (iface->address_byte & 1) {
|
if (iface->address_byte & 1) {
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
|
#include <linux/pinctrl/consumer.h>
|
||||||
#include <linux/pm_domain.h>
|
#include <linux/pm_domain.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/pm_wakeirq.h>
|
#include <linux/pm_wakeirq.h>
|
||||||
@@ -181,6 +182,8 @@ int i2c_generic_scl_recovery(struct i2c_adapter *adap)
|
|||||||
|
|
||||||
if (bri->prepare_recovery)
|
if (bri->prepare_recovery)
|
||||||
bri->prepare_recovery(adap);
|
bri->prepare_recovery(adap);
|
||||||
|
if (bri->pinctrl)
|
||||||
|
pinctrl_select_state(bri->pinctrl, bri->pins_gpio);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we can set SDA, we will always create a STOP to ensure additional
|
* If we can set SDA, we will always create a STOP to ensure additional
|
||||||
@@ -236,6 +239,8 @@ int i2c_generic_scl_recovery(struct i2c_adapter *adap)
|
|||||||
|
|
||||||
if (bri->unprepare_recovery)
|
if (bri->unprepare_recovery)
|
||||||
bri->unprepare_recovery(adap);
|
bri->unprepare_recovery(adap);
|
||||||
|
if (bri->pinctrl)
|
||||||
|
pinctrl_select_state(bri->pinctrl, bri->pins_default);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -251,13 +256,135 @@ int i2c_recover_bus(struct i2c_adapter *adap)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(i2c_recover_bus);
|
EXPORT_SYMBOL_GPL(i2c_recover_bus);
|
||||||
|
|
||||||
static void i2c_init_recovery(struct i2c_adapter *adap)
|
static void i2c_gpio_init_pinctrl_recovery(struct i2c_adapter *adap)
|
||||||
|
{
|
||||||
|
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
|
||||||
|
struct device *dev = &adap->dev;
|
||||||
|
struct pinctrl *p = bri->pinctrl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we can't change states without pinctrl, so remove the states if
|
||||||
|
* populated
|
||||||
|
*/
|
||||||
|
if (!p) {
|
||||||
|
bri->pins_default = NULL;
|
||||||
|
bri->pins_gpio = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bri->pins_default) {
|
||||||
|
bri->pins_default = pinctrl_lookup_state(p,
|
||||||
|
PINCTRL_STATE_DEFAULT);
|
||||||
|
if (IS_ERR(bri->pins_default)) {
|
||||||
|
dev_dbg(dev, PINCTRL_STATE_DEFAULT " state not found for GPIO recovery\n");
|
||||||
|
bri->pins_default = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!bri->pins_gpio) {
|
||||||
|
bri->pins_gpio = pinctrl_lookup_state(p, "gpio");
|
||||||
|
if (IS_ERR(bri->pins_gpio))
|
||||||
|
bri->pins_gpio = pinctrl_lookup_state(p, "recovery");
|
||||||
|
|
||||||
|
if (IS_ERR(bri->pins_gpio)) {
|
||||||
|
dev_dbg(dev, "no gpio or recovery state found for GPIO recovery\n");
|
||||||
|
bri->pins_gpio = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for pinctrl state changes, we need all the information */
|
||||||
|
if (bri->pins_default && bri->pins_gpio) {
|
||||||
|
dev_info(dev, "using pinctrl states for GPIO recovery");
|
||||||
|
} else {
|
||||||
|
bri->pinctrl = NULL;
|
||||||
|
bri->pins_default = NULL;
|
||||||
|
bri->pins_gpio = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int i2c_gpio_init_generic_recovery(struct i2c_adapter *adap)
|
||||||
|
{
|
||||||
|
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
|
||||||
|
struct device *dev = &adap->dev;
|
||||||
|
struct gpio_desc *gpiod;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* don't touch the recovery information if the driver is not using
|
||||||
|
* generic SCL recovery
|
||||||
|
*/
|
||||||
|
if (bri->recover_bus && bri->recover_bus != i2c_generic_scl_recovery)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pins might be taken as GPIO, so we should inform pinctrl about
|
||||||
|
* this and move the state to GPIO
|
||||||
|
*/
|
||||||
|
if (bri->pinctrl)
|
||||||
|
pinctrl_select_state(bri->pinctrl, bri->pins_gpio);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if there is incomplete or no recovery information, see if generic
|
||||||
|
* GPIO recovery is available
|
||||||
|
*/
|
||||||
|
if (!bri->scl_gpiod) {
|
||||||
|
gpiod = devm_gpiod_get(dev, "scl", GPIOD_OUT_HIGH_OPEN_DRAIN);
|
||||||
|
if (PTR_ERR(gpiod) == -EPROBE_DEFER) {
|
||||||
|
ret = -EPROBE_DEFER;
|
||||||
|
goto cleanup_pinctrl_state;
|
||||||
|
}
|
||||||
|
if (!IS_ERR(gpiod)) {
|
||||||
|
bri->scl_gpiod = gpiod;
|
||||||
|
bri->recover_bus = i2c_generic_scl_recovery;
|
||||||
|
dev_info(dev, "using generic GPIOs for recovery\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SDA GPIOD line is optional, so we care about DEFER only */
|
||||||
|
if (!bri->sda_gpiod) {
|
||||||
|
/*
|
||||||
|
* We have SCL. Pull SCL low and wait a bit so that SDA glitches
|
||||||
|
* have no effect.
|
||||||
|
*/
|
||||||
|
gpiod_direction_output(bri->scl_gpiod, 0);
|
||||||
|
udelay(10);
|
||||||
|
gpiod = devm_gpiod_get(dev, "sda", GPIOD_IN);
|
||||||
|
|
||||||
|
/* Wait a bit in case of a SDA glitch, and then release SCL. */
|
||||||
|
udelay(10);
|
||||||
|
gpiod_direction_output(bri->scl_gpiod, 1);
|
||||||
|
|
||||||
|
if (PTR_ERR(gpiod) == -EPROBE_DEFER) {
|
||||||
|
ret = -EPROBE_DEFER;
|
||||||
|
goto cleanup_pinctrl_state;
|
||||||
|
}
|
||||||
|
if (!IS_ERR(gpiod))
|
||||||
|
bri->sda_gpiod = gpiod;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_pinctrl_state:
|
||||||
|
/* change the state of the pins back to their default state */
|
||||||
|
if (bri->pinctrl)
|
||||||
|
pinctrl_select_state(bri->pinctrl, bri->pins_default);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int i2c_gpio_init_recovery(struct i2c_adapter *adap)
|
||||||
|
{
|
||||||
|
i2c_gpio_init_pinctrl_recovery(adap);
|
||||||
|
return i2c_gpio_init_generic_recovery(adap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int i2c_init_recovery(struct i2c_adapter *adap)
|
||||||
{
|
{
|
||||||
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
|
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
|
||||||
char *err_str;
|
char *err_str;
|
||||||
|
|
||||||
if (!bri)
|
if (!bri)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
|
if (i2c_gpio_init_recovery(adap) == -EPROBE_DEFER)
|
||||||
|
return -EPROBE_DEFER;
|
||||||
|
|
||||||
if (!bri->recover_bus) {
|
if (!bri->recover_bus) {
|
||||||
err_str = "no recover_bus() found";
|
err_str = "no recover_bus() found";
|
||||||
@@ -273,10 +400,7 @@ static void i2c_init_recovery(struct i2c_adapter *adap)
|
|||||||
if (gpiod_get_direction(bri->sda_gpiod) == 0)
|
if (gpiod_get_direction(bri->sda_gpiod) == 0)
|
||||||
bri->set_sda = set_sda_gpio_value;
|
bri->set_sda = set_sda_gpio_value;
|
||||||
}
|
}
|
||||||
return;
|
} else if (bri->recover_bus == i2c_generic_scl_recovery) {
|
||||||
}
|
|
||||||
|
|
||||||
if (bri->recover_bus == i2c_generic_scl_recovery) {
|
|
||||||
/* Generic SCL recovery */
|
/* Generic SCL recovery */
|
||||||
if (!bri->set_scl || !bri->get_scl) {
|
if (!bri->set_scl || !bri->get_scl) {
|
||||||
err_str = "no {get|set}_scl() found";
|
err_str = "no {get|set}_scl() found";
|
||||||
@@ -288,10 +412,12 @@ static void i2c_init_recovery(struct i2c_adapter *adap)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return 0;
|
||||||
err:
|
err:
|
||||||
dev_err(&adap->dev, "Not using recovery: %s\n", err_str);
|
dev_err(&adap->dev, "Not using recovery: %s\n", err_str);
|
||||||
adap->bus_recovery_info = NULL;
|
adap->bus_recovery_info = NULL;
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int i2c_smbus_host_notify_to_irq(const struct i2c_client *client)
|
static int i2c_smbus_host_notify_to_irq(const struct i2c_client *client)
|
||||||
@@ -319,11 +445,9 @@ static int i2c_device_probe(struct device *dev)
|
|||||||
if (!client)
|
if (!client)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
driver = to_i2c_driver(dev->driver);
|
|
||||||
|
|
||||||
client->irq = client->init_irq;
|
client->irq = client->init_irq;
|
||||||
|
|
||||||
if (!client->irq && !driver->disable_i2c_core_irq_mapping) {
|
if (!client->irq) {
|
||||||
int irq = -ENOENT;
|
int irq = -ENOENT;
|
||||||
|
|
||||||
if (client->flags & I2C_CLIENT_HOST_NOTIFY) {
|
if (client->flags & I2C_CLIENT_HOST_NOTIFY) {
|
||||||
@@ -349,6 +473,8 @@ static int i2c_device_probe(struct device *dev)
|
|||||||
client->irq = irq;
|
client->irq = irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
driver = to_i2c_driver(dev->driver);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* An I2C ID table is not mandatory, if and only if, a suitable OF
|
* An I2C ID table is not mandatory, if and only if, a suitable OF
|
||||||
* or ACPI ID table is supplied for the probing device.
|
* or ACPI ID table is supplied for the probing device.
|
||||||
@@ -1227,7 +1353,7 @@ static int i2c_setup_host_notify_irq_domain(struct i2c_adapter *adap)
|
|||||||
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_HOST_NOTIFY))
|
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_HOST_NOTIFY))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
domain = irq_domain_create_linear(adap->dev.fwnode,
|
domain = irq_domain_create_linear(adap->dev.parent->fwnode,
|
||||||
I2C_ADDR_7BITS_COUNT,
|
I2C_ADDR_7BITS_COUNT,
|
||||||
&i2c_host_notify_irq_ops, adap);
|
&i2c_host_notify_irq_ops, adap);
|
||||||
if (!domain)
|
if (!domain)
|
||||||
@@ -1318,12 +1444,16 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
|
|||||||
if (res)
|
if (res)
|
||||||
goto out_reg;
|
goto out_reg;
|
||||||
|
|
||||||
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
|
|
||||||
|
|
||||||
pm_runtime_no_callbacks(&adap->dev);
|
pm_runtime_no_callbacks(&adap->dev);
|
||||||
pm_suspend_ignore_children(&adap->dev, true);
|
pm_suspend_ignore_children(&adap->dev, true);
|
||||||
pm_runtime_enable(&adap->dev);
|
pm_runtime_enable(&adap->dev);
|
||||||
|
|
||||||
|
res = i2c_init_recovery(adap);
|
||||||
|
if (res == -EPROBE_DEFER)
|
||||||
|
goto out_reg;
|
||||||
|
|
||||||
|
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
|
||||||
|
|
||||||
#ifdef CONFIG_I2C_COMPAT
|
#ifdef CONFIG_I2C_COMPAT
|
||||||
res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
|
res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
|
||||||
adap->dev.parent);
|
adap->dev.parent);
|
||||||
@@ -1332,8 +1462,6 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
|
|||||||
"Failed to create compatibility class link\n");
|
"Failed to create compatibility class link\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
i2c_init_recovery(adap);
|
|
||||||
|
|
||||||
/* create pre-declared device nodes */
|
/* create pre-declared device nodes */
|
||||||
of_i2c_register_devices(adap);
|
of_i2c_register_devices(adap);
|
||||||
i2c_acpi_register_devices(adap);
|
i2c_acpi_register_devices(adap);
|
||||||
|
@@ -761,8 +761,8 @@ static void __exit i2c_dev_exit(void)
|
|||||||
unregister_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS);
|
unregister_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS);
|
||||||
}
|
}
|
||||||
|
|
||||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
|
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
|
||||||
"Simon G. Vogl <simon@tk.uni-linz.ac.at>");
|
MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
|
||||||
MODULE_DESCRIPTION("I2C /dev entries driver");
|
MODULE_DESCRIPTION("I2C /dev entries driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
@@ -66,7 +66,7 @@ static int i2c_slave_eeprom_slave_cb(struct i2c_client *client,
|
|||||||
case I2C_SLAVE_READ_PROCESSED:
|
case I2C_SLAVE_READ_PROCESSED:
|
||||||
/* The previous byte made it to the bus, get next one */
|
/* The previous byte made it to the bus, get next one */
|
||||||
eeprom->buffer_idx++;
|
eeprom->buffer_idx++;
|
||||||
/* fallthrough */
|
fallthrough;
|
||||||
case I2C_SLAVE_READ_REQUESTED:
|
case I2C_SLAVE_READ_REQUESTED:
|
||||||
spin_lock(&eeprom->buffer_lock);
|
spin_lock(&eeprom->buffer_lock);
|
||||||
*val = eeprom->buffer[eeprom->buffer_idx & eeprom->address_mask];
|
*val = eeprom->buffer[eeprom->buffer_idx & eeprom->address_mask];
|
||||||
|
@@ -231,7 +231,6 @@ enum i2c_alert_protocol {
|
|||||||
* @detect: Callback for device detection
|
* @detect: Callback for device detection
|
||||||
* @address_list: The I2C addresses to probe (for detect)
|
* @address_list: The I2C addresses to probe (for detect)
|
||||||
* @clients: List of detected clients we created (for i2c-core use only)
|
* @clients: List of detected clients we created (for i2c-core use only)
|
||||||
* @disable_i2c_core_irq_mapping: Tell the i2c-core to not do irq-mapping
|
|
||||||
*
|
*
|
||||||
* The driver.owner field should be set to the module owner of this driver.
|
* The driver.owner field should be set to the module owner of this driver.
|
||||||
* The driver.name field should be set to the name of this driver.
|
* The driver.name field should be set to the name of this driver.
|
||||||
@@ -290,8 +289,6 @@ struct i2c_driver {
|
|||||||
int (*detect)(struct i2c_client *client, struct i2c_board_info *info);
|
int (*detect)(struct i2c_client *client, struct i2c_board_info *info);
|
||||||
const unsigned short *address_list;
|
const unsigned short *address_list;
|
||||||
struct list_head clients;
|
struct list_head clients;
|
||||||
|
|
||||||
bool disable_i2c_core_irq_mapping;
|
|
||||||
};
|
};
|
||||||
#define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
|
#define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
|
||||||
|
|
||||||
@@ -609,6 +606,14 @@ struct i2c_timings {
|
|||||||
* may configure padmux here for SDA/SCL line or something else they want.
|
* may configure padmux here for SDA/SCL line or something else they want.
|
||||||
* @scl_gpiod: gpiod of the SCL line. Only required for GPIO recovery.
|
* @scl_gpiod: gpiod of the SCL line. Only required for GPIO recovery.
|
||||||
* @sda_gpiod: gpiod of the SDA line. Only required for GPIO recovery.
|
* @sda_gpiod: gpiod of the SDA line. Only required for GPIO recovery.
|
||||||
|
* @pinctrl: pinctrl used by GPIO recovery to change the state of the I2C pins.
|
||||||
|
* Optional.
|
||||||
|
* @pins_default: default pinctrl state of SCL/SDA lines, when they are assigned
|
||||||
|
* to the I2C bus. Optional. Populated internally for GPIO recovery, if
|
||||||
|
* state with the name PINCTRL_STATE_DEFAULT is found and pinctrl is valid.
|
||||||
|
* @pins_gpio: recovery pinctrl state of SCL/SDA lines, when they are used as
|
||||||
|
* GPIOs. Optional. Populated internally for GPIO recovery, if this state
|
||||||
|
* is called "gpio" or "recovery" and pinctrl is valid.
|
||||||
*/
|
*/
|
||||||
struct i2c_bus_recovery_info {
|
struct i2c_bus_recovery_info {
|
||||||
int (*recover_bus)(struct i2c_adapter *adap);
|
int (*recover_bus)(struct i2c_adapter *adap);
|
||||||
@@ -625,6 +630,9 @@ struct i2c_bus_recovery_info {
|
|||||||
/* gpio recovery */
|
/* gpio recovery */
|
||||||
struct gpio_desc *scl_gpiod;
|
struct gpio_desc *scl_gpiod;
|
||||||
struct gpio_desc *sda_gpiod;
|
struct gpio_desc *sda_gpiod;
|
||||||
|
struct pinctrl *pinctrl;
|
||||||
|
struct pinctrl_state *pins_default;
|
||||||
|
struct pinctrl_state *pins_gpio;
|
||||||
};
|
};
|
||||||
|
|
||||||
int i2c_recover_bus(struct i2c_adapter *adap);
|
int i2c_recover_bus(struct i2c_adapter *adap);
|
||||||
|
Reference in New Issue
Block a user