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:
Коммит
e764a1e323
|
@ -14,6 +14,7 @@ Required properties:
|
|||
"mediatek,mt7629-i2c", "mediatek,mt2712-i2c": for MediaTek MT7629
|
||||
"mediatek,mt8173-i2c": for MediaTek MT8173
|
||||
"mediatek,mt8183-i2c": for MediaTek MT8183
|
||||
"mediatek,mt8192-i2c": for MediaTek MT8192
|
||||
"mediatek,mt8516-i2c", "mediatek,mt2712-i2c": for MediaTek MT8516
|
||||
- reg: physical base address of the controller and dma base, length of memory
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
|
|
@ -26,6 +26,9 @@ properties:
|
|||
- items:
|
||||
- const: allwinner,sun50i-a64-i2c
|
||||
- const: allwinner,sun6i-a31-i2c
|
||||
- items:
|
||||
- const: allwinner,sun50i-a100-i2c
|
||||
- const: allwinner,sun6i-a31-i2c
|
||||
- items:
|
||||
- const: allwinner,sun50i-h6-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-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-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-r8a7779" if the device is a part of a R8A7779 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-r8a774b1" (RZ/G2N)
|
||||
- "renesas,iic-r8a774c0" (RZ/G2E)
|
||||
- "renesas,iic-r8a774e1" (RZ/G2H)
|
||||
- "renesas,iic-r8a7790" (R-Car H2)
|
||||
- "renesas,iic-r8a7791" (R-Car M2-W)
|
||||
- "renesas,iic-r8a7792" (R-Car V2H)
|
||||
|
|
|
@ -43,6 +43,7 @@ Supported adapters:
|
|||
* Intel Elkhart Lake (PCH)
|
||||
* Intel Tiger Lake (PCH)
|
||||
* Intel Jasper Lake (SOC)
|
||||
* Intel Emmitsburg (PCH)
|
||||
|
||||
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_write_word_data(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_write_block_data(int file, __u8 command, __u8 length,
|
||||
__u8 *values);
|
||||
|
|
|
@ -542,8 +542,8 @@ int i2c_pca_add_numbered_bus(struct i2c_adapter *adap)
|
|||
}
|
||||
EXPORT_SYMBOL(i2c_pca_add_numbered_bus);
|
||||
|
||||
MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>, "
|
||||
"Wolfram Sang <kernel@pengutronix.de>");
|
||||
MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
|
||||
MODULE_AUTHOR("Wolfram Sang <kernel@pengutronix.de>");
|
||||
MODULE_DESCRIPTION("I2C-Bus PCA9564/PCA9665 algorithm");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
|
|
@ -146,6 +146,7 @@ config I2C_I801
|
|||
Elkhart Lake (PCH)
|
||||
Tiger Lake (PCH)
|
||||
Jasper Lake (SOC)
|
||||
Emmitsburg (PCH)
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-i801.
|
||||
|
|
|
@ -519,9 +519,9 @@ static struct pci_driver ali1535_driver = {
|
|||
|
||||
module_pci_driver(ali1535_driver);
|
||||
|
||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
|
||||
"Philip Edelbrock <phil@netroedge.com>, "
|
||||
"Mark D. Studebaker <mdsxyz123@yahoo.com> "
|
||||
"and Dan Eaton <dan.eaton@rocketlogix.com>");
|
||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
|
||||
MODULE_AUTHOR("Philip Edelbrock <phil@netroedge.com>");
|
||||
MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
|
||||
MODULE_AUTHOR("Dan Eaton <dan.eaton@rocketlogix.com>");
|
||||
MODULE_DESCRIPTION("ALI1535 SMBus driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -502,8 +502,8 @@ static struct pci_driver ali15x3_driver = {
|
|||
|
||||
module_pci_driver(ali15x3_driver);
|
||||
|
||||
MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
|
||||
"Philip Edelbrock <phil@netroedge.com>, "
|
||||
"and Mark D. Studebaker <mdsxyz123@yahoo.com>");
|
||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
|
||||
MODULE_AUTHOR("Philip Edelbrock <phil@netroedge.com>");
|
||||
MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
|
||||
MODULE_DESCRIPTION("ALI15X3 SMBus driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -381,7 +381,7 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr,
|
|||
if (status)
|
||||
return status;
|
||||
len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||
for (i = 0; i < len; 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;
|
||||
}
|
||||
irq_handled |= ASPEED_I2CD_INTR_TX_ACK;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case ASPEED_I2C_MASTER_TX_FIRST:
|
||||
if (bus->buf_index < msg->len) {
|
||||
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) */
|
||||
if (!(irq_status & ASPEED_I2CD_INTR_RX_DONE))
|
||||
goto out_no_complete;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case ASPEED_I2C_MASTER_RX:
|
||||
if (unlikely(!(irq_status & ASPEED_I2CD_INTR_RX_DONE))) {
|
||||
dev_err(bus->dev, "master failed to RX\n");
|
||||
|
|
|
@ -816,79 +816,16 @@ error:
|
|||
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,
|
||||
struct at91_twi_dev *dev)
|
||||
{
|
||||
struct i2c_bus_recovery_info *rinfo = &dev->rinfo;
|
||||
|
||||
dev->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
if (!dev->pinctrl || IS_ERR(dev->pinctrl)) {
|
||||
rinfo->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
if (!rinfo->pinctrl || IS_ERR(rinfo->pinctrl)) {
|
||||
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;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -157,9 +157,6 @@ struct at91_twi_dev {
|
|||
struct at91_twi_dma dma;
|
||||
bool slave_detected;
|
||||
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
|
||||
unsigned smr;
|
||||
struct i2c_client *slave;
|
||||
|
|
|
@ -1078,7 +1078,7 @@ static int bcm_iproc_i2c_unreg_slave(struct i2c_client *slave)
|
|||
if (!iproc_i2c->slave)
|
||||
return -EINVAL;
|
||||
|
||||
iproc_i2c->slave = NULL;
|
||||
disable_irq(iproc_i2c->irq);
|
||||
|
||||
/* disable all slave interrupts */
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -392,7 +392,7 @@ static const struct i2c_algorithm bcm2835_i2c_algo = {
|
|||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
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) {
|
||||
case 0x0817:
|
||||
dev->timings.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case 0x0818:
|
||||
case 0x0819:
|
||||
c->bus_num = pdev->device - 0x817 + 3;
|
||||
|
|
|
@ -187,7 +187,7 @@ static irqreturn_t dc_i2c_irq(int irq, void *dev_id)
|
|||
break;
|
||||
}
|
||||
i2c->state = STATE_WRITE;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case STATE_WRITE:
|
||||
if (i2c->msgbuf_ptr < i2c->msg->len)
|
||||
dc_i2c_write_buf(i2c);
|
||||
|
|
|
@ -846,11 +846,10 @@ static void pch_i2c_remove(struct pci_dev *pdev)
|
|||
kfree(adap_info);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
static int __maybe_unused pch_i2c_suspend(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct adapter_info *adap_info = pci_get_drvdata(pdev);
|
||||
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_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;
|
||||
}
|
||||
|
||||
static int pch_i2c_resume(struct pci_dev *pdev)
|
||||
static int __maybe_unused pch_i2c_resume(struct device *dev)
|
||||
{
|
||||
int i;
|
||||
struct adapter_info *adap_info = pci_get_drvdata(pdev);
|
||||
|
||||
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);
|
||||
struct adapter_info *adap_info = dev_get_drvdata(dev);
|
||||
|
||||
for (i = 0; i < adap_info->ch_num; i++)
|
||||
pch_i2c_init(&adap_info->pch_data[i]);
|
||||
|
@ -908,18 +886,15 @@ static int pch_i2c_resume(struct pci_dev *pdev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define pch_i2c_suspend NULL
|
||||
#define pch_i2c_resume NULL
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pch_i2c_pm_ops, pch_i2c_suspend, pch_i2c_resume);
|
||||
|
||||
static struct pci_driver pch_pcidriver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = pch_pcidev_id,
|
||||
.probe = pch_i2c_probe,
|
||||
.remove = pch_i2c_remove,
|
||||
.suspend = pch_i2c_suspend,
|
||||
.resume = pch_i2c_resume
|
||||
.driver.pm = &pch_i2c_pm_ops,
|
||||
};
|
||||
|
||||
module_pci_driver(pch_pcidriver);
|
||||
|
|
|
@ -442,6 +442,7 @@ static struct platform_driver em_i2c_driver = {
|
|||
module_platform_driver(em_i2c_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_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++) {
|
||||
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;
|
||||
|
||||
port = kzalloc(sizeof(*port), GFP_KERNEL);
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
* Sunrise Point-H (PCH) 0xa123 32 hard yes yes yes
|
||||
* Sunrise Point-LP (PCH) 0x9d23 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
|
||||
* Lewisburg (PCH) 0xa1a3 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
|
||||
* Elkhart Lake (PCH) 0x4b23 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
|
||||
* 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_CDF_SMBUS 0x18df
|
||||
#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_PATSBURG_SMBUS 0x1d22
|
||||
/* 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_ICELAKE_LP_SMBUS 0x34a3
|
||||
#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_JASPER_LAKE_SMBUS 0x4da3
|
||||
#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_CDF_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_LEWISBURG_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_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_H_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS) },
|
||||
{ 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_ELKHART_LAKE_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_EBG_SMBUS:
|
||||
priv->features |= FEATURE_BLOCK_PROC;
|
||||
priv->features |= FEATURE_I2C_BLOCK_READ;
|
||||
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_MS2:
|
||||
priv->features |= FEATURE_IDF;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
default:
|
||||
priv->features |= FEATURE_BLOCK_PROC;
|
||||
priv->features |= FEATURE_I2C_BLOCK_READ;
|
||||
priv->features |= FEATURE_IRQ;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case PCI_DEVICE_ID_INTEL_82801DB_3:
|
||||
priv->features |= FEATURE_SMBUS_PEC;
|
||||
priv->features |= FEATURE_BLOCK_BUFFER;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case PCI_DEVICE_ID_INTEL_82801CA_3:
|
||||
priv->features |= FEATURE_HOST_NOTIFY;
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case PCI_DEVICE_ID_INTEL_82801BA_2:
|
||||
case PCI_DEVICE_ID_INTEL_82801AB_3:
|
||||
case PCI_DEVICE_ID_INTEL_82801AA_3:
|
||||
|
@ -1986,7 +1994,8 @@ static void __exit i2c_i801_exit(void)
|
|||
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_LICENSE("GPL");
|
||||
|
||||
|
|
|
@ -48,11 +48,13 @@
|
|||
|
||||
#define I2C_DMA_CON_TX 0x0000
|
||||
#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_INT_FLAG_NONE 0x0000
|
||||
#define I2C_DMA_CLR_FLAG 0x0000
|
||||
#define I2C_DMA_HARD_RST 0x0002
|
||||
#define I2C_DMA_4G_MODE 0x0001
|
||||
|
||||
#define MAX_SAMPLE_CNT_DIV 8
|
||||
#define MAX_STEP_CNT_DIV 64
|
||||
|
@ -201,10 +203,11 @@ struct mtk_i2c_compatible {
|
|||
unsigned char dcm: 1;
|
||||
unsigned char auto_restart: 1;
|
||||
unsigned char aux_len_reg: 1;
|
||||
unsigned char support_33bits: 1;
|
||||
unsigned char timing_adjust: 1;
|
||||
unsigned char dma_sync: 1;
|
||||
unsigned char ltiming_adjust: 1;
|
||||
unsigned char apdma_sync: 1;
|
||||
unsigned char max_dma_support;
|
||||
};
|
||||
|
||||
struct mtk_i2c_ac_timing {
|
||||
|
@ -250,14 +253,13 @@ struct mtk_i2c {
|
|||
|
||||
/**
|
||||
* struct i2c_spec_values:
|
||||
* min_low_ns: min LOW period of the SCL clock
|
||||
* min_su_sta_ns: min set-up time for a repeated START condition
|
||||
* max_hd_dat_ns: max data hold time
|
||||
* min_su_dat_ns: min data set-up time
|
||||
* @min_low_ns: min LOW period of the SCL clock
|
||||
* @min_su_sta_ns: min set-up time for a repeated START condition
|
||||
* @max_hd_dat_ns: max data hold time
|
||||
* @min_su_dat_ns: min data set-up time
|
||||
*/
|
||||
struct i2c_spec_values {
|
||||
unsigned int min_low_ns;
|
||||
unsigned int min_high_ns;
|
||||
unsigned int min_su_sta_ns;
|
||||
unsigned int max_hd_dat_ns;
|
||||
unsigned int min_su_dat_ns;
|
||||
|
@ -307,10 +309,11 @@ static const struct mtk_i2c_compatible mt2712_compat = {
|
|||
.dcm = 1,
|
||||
.auto_restart = 1,
|
||||
.aux_len_reg = 1,
|
||||
.support_33bits = 1,
|
||||
.timing_adjust = 1,
|
||||
.dma_sync = 0,
|
||||
.ltiming_adjust = 0,
|
||||
.apdma_sync = 0,
|
||||
.max_dma_support = 33,
|
||||
};
|
||||
|
||||
static const struct mtk_i2c_compatible mt6577_compat = {
|
||||
|
@ -320,10 +323,11 @@ static const struct mtk_i2c_compatible mt6577_compat = {
|
|||
.dcm = 1,
|
||||
.auto_restart = 0,
|
||||
.aux_len_reg = 0,
|
||||
.support_33bits = 0,
|
||||
.timing_adjust = 0,
|
||||
.dma_sync = 0,
|
||||
.ltiming_adjust = 0,
|
||||
.apdma_sync = 0,
|
||||
.max_dma_support = 32,
|
||||
};
|
||||
|
||||
static const struct mtk_i2c_compatible mt6589_compat = {
|
||||
|
@ -333,10 +337,11 @@ static const struct mtk_i2c_compatible mt6589_compat = {
|
|||
.dcm = 0,
|
||||
.auto_restart = 0,
|
||||
.aux_len_reg = 0,
|
||||
.support_33bits = 0,
|
||||
.timing_adjust = 0,
|
||||
.dma_sync = 0,
|
||||
.ltiming_adjust = 0,
|
||||
.apdma_sync = 0,
|
||||
.max_dma_support = 32,
|
||||
};
|
||||
|
||||
static const struct mtk_i2c_compatible mt7622_compat = {
|
||||
|
@ -346,10 +351,11 @@ static const struct mtk_i2c_compatible mt7622_compat = {
|
|||
.dcm = 1,
|
||||
.auto_restart = 1,
|
||||
.aux_len_reg = 1,
|
||||
.support_33bits = 0,
|
||||
.timing_adjust = 0,
|
||||
.dma_sync = 0,
|
||||
.ltiming_adjust = 0,
|
||||
.apdma_sync = 0,
|
||||
.max_dma_support = 32,
|
||||
};
|
||||
|
||||
static const struct mtk_i2c_compatible mt8173_compat = {
|
||||
|
@ -358,10 +364,11 @@ static const struct mtk_i2c_compatible mt8173_compat = {
|
|||
.dcm = 1,
|
||||
.auto_restart = 1,
|
||||
.aux_len_reg = 1,
|
||||
.support_33bits = 1,
|
||||
.timing_adjust = 0,
|
||||
.dma_sync = 0,
|
||||
.ltiming_adjust = 0,
|
||||
.apdma_sync = 0,
|
||||
.max_dma_support = 33,
|
||||
};
|
||||
|
||||
static const struct mtk_i2c_compatible mt8183_compat = {
|
||||
|
@ -371,10 +378,25 @@ static const struct mtk_i2c_compatible mt8183_compat = {
|
|||
.dcm = 0,
|
||||
.auto_restart = 1,
|
||||
.aux_len_reg = 1,
|
||||
.support_33bits = 1,
|
||||
.timing_adjust = 1,
|
||||
.dma_sync = 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[] = {
|
||||
|
@ -384,6 +406,7 @@ static const struct of_device_id mtk_i2c_of_match[] = {
|
|||
{ .compatible = "mediatek,mt7622-i2c", .data = &mt7622_compat },
|
||||
{ .compatible = "mediatek,mt8173-i2c", .data = &mt8173_compat },
|
||||
{ .compatible = "mediatek,mt8183-i2c", .data = &mt8183_compat },
|
||||
{ .compatible = "mediatek,mt8192-i2c", .data = &mt8192_compat },
|
||||
{}
|
||||
};
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
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 control_reg;
|
||||
u16 restart_flag = 0;
|
||||
u16 dma_sync = 0;
|
||||
u32 reg_4g_mode;
|
||||
u8 *dma_rd_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);
|
||||
}
|
||||
|
||||
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 */
|
||||
if (i2c->op == I2C_MASTER_RD) {
|
||||
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);
|
||||
if (!dma_rd_buf)
|
||||
|
@ -868,8 +893,8 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (i2c->dev_comp->support_33bits) {
|
||||
reg_4g_mode = mtk_i2c_set_4g_mode(rpaddr);
|
||||
if (i2c->dev_comp->max_dma_support > 32) {
|
||||
reg_4g_mode = upper_32_bits(rpaddr);
|
||||
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);
|
||||
} else if (i2c->op == I2C_MASTER_WR) {
|
||||
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);
|
||||
if (!dma_wr_buf)
|
||||
|
@ -891,8 +916,8 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (i2c->dev_comp->support_33bits) {
|
||||
reg_4g_mode = mtk_i2c_set_4g_mode(wpaddr);
|
||||
if (i2c->dev_comp->max_dma_support > 32) {
|
||||
reg_4g_mode = upper_32_bits(wpaddr);
|
||||
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);
|
||||
} else {
|
||||
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);
|
||||
if (!dma_wr_buf)
|
||||
|
@ -937,11 +962,11 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (i2c->dev_comp->support_33bits) {
|
||||
reg_4g_mode = mtk_i2c_set_4g_mode(wpaddr);
|
||||
if (i2c->dev_comp->max_dma_support > 32) {
|
||||
reg_4g_mode = upper_32_bits(wpaddr);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1215,8 +1240,9 @@ static int mtk_i2c_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (i2c->dev_comp->support_33bits) {
|
||||
ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(33));
|
||||
if (i2c->dev_comp->max_dma_support > 32) {
|
||||
ret = dma_set_mask(&pdev->dev,
|
||||
DMA_BIT_MASK(i2c->dev_comp->max_dma_support));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "dma_set_mask return error.\n");
|
||||
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;
|
||||
break;
|
||||
}
|
||||
/* FALLTHRU */
|
||||
fallthrough;
|
||||
case MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK: /* 0xd0 */
|
||||
case MV64XXX_I2C_STATUS_MAST_WR_ACK: /* 0x28 */
|
||||
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;
|
||||
break;
|
||||
}
|
||||
/* FALLTHRU */
|
||||
fallthrough;
|
||||
case MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK: /* 0xe0 */
|
||||
if (drv_data->bytes_left == 0) {
|
||||
drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
|
||||
drv_data->state = MV64XXX_I2C_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
/* FALLTHRU */
|
||||
fallthrough;
|
||||
case MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK: /* 0x50 */
|
||||
if (status != MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK)
|
||||
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",
|
||||
drv_data->action);
|
||||
drv_data->rc = -EIO;
|
||||
|
||||
/* FALLTHRU */
|
||||
fallthrough;
|
||||
case MV64XXX_I2C_ACTION_SEND_STOP:
|
||||
drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
|
||||
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);
|
||||
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_LICENSE("GPL");
|
||||
|
|
|
@ -1032,7 +1032,7 @@ static struct pci_driver piix4_driver = {
|
|||
|
||||
module_pci_driver(piix4_driver);
|
||||
|
||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
|
||||
"Philip Edelbrock <phil@netroedge.com>");
|
||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
|
||||
MODULE_AUTHOR("Philip Edelbrock <phil@netroedge.com>");
|
||||
MODULE_DESCRIPTION("PIIX4 SMBus driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -781,7 +781,8 @@ static void __exit i2c_adap_pnx_exit(void)
|
|||
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_LICENSE("GPL");
|
||||
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, 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 */
|
||||
if (ssr_filtered & SSR) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -853,7 +854,7 @@ static int rcar_reg_slave(struct i2c_client *slave)
|
|||
priv->slave = slave;
|
||||
rcar_i2c_write(priv, ICSAR, slave->addr);
|
||||
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);
|
||||
|
||||
return 0;
|
||||
|
@ -865,12 +866,14 @@ static int rcar_unreg_slave(struct i2c_client *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, 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 */
|
||||
|
||||
synchronize_irq(priv->irq);
|
||||
priv->slave = NULL;
|
||||
|
||||
pm_runtime_put(rcar_i2c_priv_to_dev(priv));
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.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;
|
||||
}
|
||||
|
||||
static int rk3x_i2c_xfer(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msgs, int num)
|
||||
static int rk3x_i2c_wait_xfer_poll(struct rk3x_i2c *i2c)
|
||||
{
|
||||
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;
|
||||
unsigned long timeout, flags;
|
||||
|
@ -1075,8 +1089,12 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
|
|||
|
||||
rk3x_i2c_start(i2c);
|
||||
|
||||
timeout = wait_event_timeout(i2c->wait, !i2c->busy,
|
||||
msecs_to_jiffies(WAIT_TIMEOUT));
|
||||
if (!polling) {
|
||||
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);
|
||||
|
||||
|
@ -1110,6 +1128,18 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
|
|||
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)
|
||||
{
|
||||
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 = {
|
||||
.master_xfer = rk3x_i2c_xfer,
|
||||
.master_xfer_atomic = rk3x_i2c_xfer_polling,
|
||||
.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_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_ALIAS("platform:i2c-sh_mobile");
|
||||
|
|
|
@ -180,6 +180,7 @@ static void __exit i2c_sibyte_exit(void)
|
|||
module_init(i2c_sibyte_init);
|
||||
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_LICENSE("GPL");
|
||||
|
|
|
@ -470,6 +470,6 @@ static struct platform_driver i2c_sirfsoc_driver = {
|
|||
module_platform_driver(i2c_sirfsoc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("SiRF SoC I2C master controller driver");
|
||||
MODULE_AUTHOR("Zhiwu Song <Zhiwu.Song@csr.com>, "
|
||||
"Xiangzhen Ye <Xiangzhen.Ye@csr.com>");
|
||||
MODULE_AUTHOR("Zhiwu Song <Zhiwu.Song@csr.com>");
|
||||
MODULE_AUTHOR("Xiangzhen Ye <Xiangzhen.Ye@csr.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -398,8 +398,7 @@ static irqreturn_t synquacer_i2c_isr(int irq, void *dev_id)
|
|||
|
||||
if (i2c->state == STATE_READ)
|
||||
goto prepare_read;
|
||||
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
|
||||
case STATE_WRITE:
|
||||
if (bsr & SYNQUACER_I2C_BSR_LRB) {
|
||||
|
|
|
@ -293,6 +293,8 @@ struct tegra_i2c_dev {
|
|||
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,
|
||||
unsigned long reg)
|
||||
{
|
||||
|
@ -419,7 +421,7 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev)
|
|||
dma_addr_t dma_phys;
|
||||
int err;
|
||||
|
||||
if (!i2c_dev->hw->has_apb_dma)
|
||||
if (!i2c_dev->hw->has_apb_dma || i2c_dev->is_vi)
|
||||
return 0;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_TEGRA20_APB_DMA)) {
|
||||
|
@ -655,32 +657,47 @@ static int __maybe_unused tegra_i2c_runtime_resume(struct device *dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!i2c_dev->hw->has_single_clk_source) {
|
||||
ret = clk_enable(i2c_dev->fast_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(i2c_dev->dev,
|
||||
"Enabling fast clk failed, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = clk_enable(i2c_dev->fast_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(i2c_dev->dev,
|
||||
"Enabling fast clk failed, err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (i2c_dev->slow_clk) {
|
||||
ret = clk_enable(i2c_dev->slow_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to enable slow clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = clk_enable(i2c_dev->slow_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to enable slow clock: %d\n", ret);
|
||||
goto disable_fast_clk;
|
||||
}
|
||||
|
||||
ret = clk_enable(i2c_dev->div_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(i2c_dev->dev,
|
||||
"Enabling div clk failed, err %d\n", ret);
|
||||
clk_disable(i2c_dev->fast_clk);
|
||||
return ret;
|
||||
goto disable_slow_clk;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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)
|
||||
|
@ -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);
|
||||
|
||||
clk_disable(i2c_dev->div_clk);
|
||||
|
||||
if (i2c_dev->slow_clk)
|
||||
clk_disable(i2c_dev->slow_clk);
|
||||
|
||||
if (!i2c_dev->hw->has_single_clk_source)
|
||||
clk_disable(i2c_dev->fast_clk);
|
||||
clk_disable(i2c_dev->slow_clk);
|
||||
clk_disable(i2c_dev->fast_clk);
|
||||
|
||||
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);
|
||||
|
||||
if (!i2c_dev->hw->has_single_clk_source) {
|
||||
ret = clk_prepare(i2c_dev->fast_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(i2c_dev->dev, "Clock prepare failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = clk_prepare(i2c_dev->fast_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(i2c_dev->dev, "Clock prepare failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (i2c_dev->slow_clk) {
|
||||
ret = clk_prepare(i2c_dev->slow_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to prepare slow clock: %d\n", ret);
|
||||
goto unprepare_fast_clk;
|
||||
}
|
||||
ret = clk_prepare(i2c_dev->slow_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to prepare slow clock: %d\n", ret);
|
||||
goto unprepare_fast_clk;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
if (!pm_runtime_enabled(&pdev->dev)) {
|
||||
ret = tegra_i2c_runtime_resume(&pdev->dev);
|
||||
|
@ -1835,12 +1852,10 @@ unprepare_div_clk:
|
|||
clk_unprepare(i2c_dev->div_clk);
|
||||
|
||||
unprepare_slow_clk:
|
||||
if (i2c_dev->is_vi)
|
||||
clk_unprepare(i2c_dev->slow_clk);
|
||||
clk_unprepare(i2c_dev->slow_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;
|
||||
}
|
||||
|
@ -1859,12 +1874,8 @@ static int tegra_i2c_remove(struct platform_device *pdev)
|
|||
tegra_i2c_runtime_suspend(&pdev->dev);
|
||||
|
||||
clk_unprepare(i2c_dev->div_clk);
|
||||
|
||||
if (i2c_dev->slow_clk)
|
||||
clk_unprepare(i2c_dev->slow_clk);
|
||||
|
||||
if (!i2c_dev->hw->has_single_clk_source)
|
||||
clk_unprepare(i2c_dev->fast_clk);
|
||||
clk_unprepare(i2c_dev->slow_clk);
|
||||
clk_unprepare(i2c_dev->fast_clk);
|
||||
|
||||
tegra_i2c_release_dma(i2c_dev);
|
||||
return 0;
|
||||
|
|
|
@ -228,7 +228,7 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
|
|||
goto exit_unsupported;
|
||||
if (read_write == I2C_SMBUS_READ)
|
||||
outb_p(data->block[0], SMBHSTDAT0);
|
||||
/* Fall through */
|
||||
fallthrough;
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
outb_p(command, SMBHSTCMD);
|
||||
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>, "
|
||||
"Mark D. Studebaker <mdsxyz123@yahoo.com> and "
|
||||
"Jean Delvare <jdelvare@suse.de>");
|
||||
MODULE_AUTHOR("Kyosti Malkki <kmalkki@cc.hut.fi>");
|
||||
MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
|
||||
MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
|
||||
MODULE_DESCRIPTION("vt82c596 SMBus driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
|
|||
|
||||
case state_repeat_start:
|
||||
outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
|
||||
/* fallthrough */
|
||||
fallthrough;
|
||||
|
||||
case state_quick:
|
||||
if (iface->address_byte & 1) {
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
|
@ -181,6 +182,8 @@ int i2c_generic_scl_recovery(struct i2c_adapter *adap)
|
|||
|
||||
if (bri->prepare_recovery)
|
||||
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
|
||||
|
@ -236,6 +239,8 @@ int i2c_generic_scl_recovery(struct i2c_adapter *adap)
|
|||
|
||||
if (bri->unprepare_recovery)
|
||||
bri->unprepare_recovery(adap);
|
||||
if (bri->pinctrl)
|
||||
pinctrl_select_state(bri->pinctrl, bri->pins_default);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -251,13 +256,135 @@ int i2c_recover_bus(struct i2c_adapter *adap)
|
|||
}
|
||||
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;
|
||||
char *err_str;
|
||||
|
||||
if (!bri)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (i2c_gpio_init_recovery(adap) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
if (!bri->recover_bus) {
|
||||
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)
|
||||
bri->set_sda = set_sda_gpio_value;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (bri->recover_bus == i2c_generic_scl_recovery) {
|
||||
} else if (bri->recover_bus == i2c_generic_scl_recovery) {
|
||||
/* Generic SCL recovery */
|
||||
if (!bri->set_scl || !bri->get_scl) {
|
||||
err_str = "no {get|set}_scl() found";
|
||||
|
@ -288,10 +412,12 @@ static void i2c_init_recovery(struct i2c_adapter *adap)
|
|||
}
|
||||
}
|
||||
|
||||
return;
|
||||
return 0;
|
||||
err:
|
||||
dev_err(&adap->dev, "Not using recovery: %s\n", err_str);
|
||||
adap->bus_recovery_info = NULL;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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)
|
||||
return 0;
|
||||
|
||||
driver = to_i2c_driver(dev->driver);
|
||||
|
||||
client->irq = client->init_irq;
|
||||
|
||||
if (!client->irq && !driver->disable_i2c_core_irq_mapping) {
|
||||
if (!client->irq) {
|
||||
int irq = -ENOENT;
|
||||
|
||||
if (client->flags & I2C_CLIENT_HOST_NOTIFY) {
|
||||
|
@ -349,6 +473,8 @@ static int i2c_device_probe(struct device *dev)
|
|||
client->irq = irq;
|
||||
}
|
||||
|
||||
driver = to_i2c_driver(dev->driver);
|
||||
|
||||
/*
|
||||
* An I2C ID table is not mandatory, if and only if, a suitable OF
|
||||
* 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))
|
||||
return 0;
|
||||
|
||||
domain = irq_domain_create_linear(adap->dev.fwnode,
|
||||
domain = irq_domain_create_linear(adap->dev.parent->fwnode,
|
||||
I2C_ADDR_7BITS_COUNT,
|
||||
&i2c_host_notify_irq_ops, adap);
|
||||
if (!domain)
|
||||
|
@ -1318,12 +1444,16 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
|
|||
if (res)
|
||||
goto out_reg;
|
||||
|
||||
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
|
||||
|
||||
pm_runtime_no_callbacks(&adap->dev);
|
||||
pm_suspend_ignore_children(&adap->dev, true);
|
||||
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
|
||||
res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
|
||||
adap->dev.parent);
|
||||
|
@ -1332,8 +1462,6 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
|
|||
"Failed to create compatibility class link\n");
|
||||
#endif
|
||||
|
||||
i2c_init_recovery(adap);
|
||||
|
||||
/* create pre-declared device nodes */
|
||||
of_i2c_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);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
|
||||
"Simon G. Vogl <simon@tk.uni-linz.ac.at>");
|
||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
|
||||
MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
|
||||
MODULE_DESCRIPTION("I2C /dev entries driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ static int i2c_slave_eeprom_slave_cb(struct i2c_client *client,
|
|||
case I2C_SLAVE_READ_PROCESSED:
|
||||
/* The previous byte made it to the bus, get next one */
|
||||
eeprom->buffer_idx++;
|
||||
/* fallthrough */
|
||||
fallthrough;
|
||||
case I2C_SLAVE_READ_REQUESTED:
|
||||
spin_lock(&eeprom->buffer_lock);
|
||||
*val = eeprom->buffer[eeprom->buffer_idx & eeprom->address_mask];
|
||||
|
|
|
@ -231,7 +231,6 @@ enum i2c_alert_protocol {
|
|||
* @detect: Callback for device detection
|
||||
* @address_list: The I2C addresses to probe (for detect)
|
||||
* @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.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);
|
||||
const unsigned short *address_list;
|
||||
struct list_head clients;
|
||||
|
||||
bool disable_i2c_core_irq_mapping;
|
||||
};
|
||||
#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.
|
||||
* @scl_gpiod: gpiod of the SCL 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 {
|
||||
int (*recover_bus)(struct i2c_adapter *adap);
|
||||
|
@ -625,6 +630,9 @@ struct i2c_bus_recovery_info {
|
|||
/* gpio recovery */
|
||||
struct gpio_desc *scl_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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче