Merge branch 'i2c/for-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: - new driver for ICY, an Amiga Zorro card :) - axxia driver gained slave mode support, NXP driver gained ACPI - the slave EEPROM backend gained 16 bit address support - and lots of regular driver updates and reworks * 'i2c/for-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (52 commits) i2c: tegra: Move suspend handling to NOIRQ phase i2c: imx: ACPI support for NXP i2c controller i2c: uniphier(-f): remove all dev_dbg() i2c: uniphier(-f): use devm_platform_ioremap_resource() i2c: slave-eeprom: Add comment about address handling i2c: exynos5: Remove IRQF_ONESHOT i2c: stm32f7: Make structure stm32f7_i2c_algo constant i2c: cht-wc: drop check because i2c_unregister_device() is NULL safe i2c-eeprom_slave: Add support for more eeprom models i2c: fsi: Add of_put_node() before break i2c: synquacer: Make synquacer_i2c_ops constant i2c: hix5hd2: Remove IRQF_ONESHOT i2c: i801: Use iTCO version 6 in Cannon Lake PCH and beyond watchdog: iTCO: Add support for Cannon Lake PCH iTCO i2c: iproc: Make bcm_iproc_i2c_quirks constant i2c: iproc: Add full name of devicetree node to adapter name i2c: piix4: Add ACPI support i2c: piix4: Fix probing of reserved ports on AMD Family 16h Model 30h i2c: ocores: use request_any_context_irq() to register IRQ handler i2c: designware: Fix optional reset error handling ...
This commit is contained in:
Коммит
351c8a09b0
|
@ -1,7 +1,9 @@
|
|||
Broadcom BCM2835 I2C controller
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "brcm,bcm2835-i2c".
|
||||
- compatible : Should be one of:
|
||||
"brcm,bcm2711-i2c"
|
||||
"brcm,bcm2835-i2c"
|
||||
- reg: Should contain register location and length.
|
||||
- interrupts: Should contain interrupt.
|
||||
- clocks : The clock feeding the I2C controller.
|
||||
|
|
14
MAINTAINERS
14
MAINTAINERS
|
@ -7865,6 +7865,12 @@ S: Maintained
|
|||
F: drivers/mfd/lpc_ich.c
|
||||
F: drivers/gpio/gpio-ich.c
|
||||
|
||||
ICY I2C DRIVER
|
||||
M: Max Staudt <max@enpas.org>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/i2c/busses/i2c-icy.c
|
||||
|
||||
IDE SUBSYSTEM
|
||||
M: "David S. Miller" <davem@davemloft.net>
|
||||
L: linux-ide@vger.kernel.org
|
||||
|
@ -13791,7 +13797,7 @@ F: drivers/clk/renesas/
|
|||
RENESAS EMEV2 I2C DRIVER
|
||||
M: Wolfram Sang <wsa+renesas@sang-engineering.com>
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/i2c/i2c-emev2.txt
|
||||
F: Documentation/devicetree/bindings/i2c/renesas,iic-emev2.txt
|
||||
F: drivers/i2c/busses/i2c-emev2.c
|
||||
|
||||
RENESAS ETHERNET DRIVERS
|
||||
|
@ -13813,15 +13819,15 @@ F: drivers/iio/adc/rcar-gyroadc.c
|
|||
RENESAS R-CAR I2C DRIVERS
|
||||
M: Wolfram Sang <wsa+renesas@sang-engineering.com>
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/i2c/i2c-rcar.txt
|
||||
F: Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt
|
||||
F: Documentation/devicetree/bindings/i2c/renesas,i2c.txt
|
||||
F: Documentation/devicetree/bindings/i2c/renesas,iic.txt
|
||||
F: drivers/i2c/busses/i2c-rcar.c
|
||||
F: drivers/i2c/busses/i2c-sh_mobile.c
|
||||
|
||||
RENESAS RIIC DRIVER
|
||||
M: Chris Brandt <chris.brandt@renesas.com>
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/i2c/i2c-riic.txt
|
||||
F: Documentation/devicetree/bindings/i2c/renesas,riic.txt
|
||||
F: drivers/i2c/busses/i2c-riic.c
|
||||
|
||||
RENESAS USB PHY DRIVER
|
||||
|
|
|
@ -160,11 +160,17 @@ static const struct apd_device_desc hip08_i2c_desc = {
|
|||
.setup = acpi_apd_setup,
|
||||
.fixed_clk_rate = 250000000,
|
||||
};
|
||||
|
||||
static const struct apd_device_desc thunderx2_i2c_desc = {
|
||||
.setup = acpi_apd_setup,
|
||||
.fixed_clk_rate = 125000000,
|
||||
};
|
||||
|
||||
static const struct apd_device_desc nxp_i2c_desc = {
|
||||
.setup = acpi_apd_setup,
|
||||
.fixed_clk_rate = 350000000,
|
||||
};
|
||||
|
||||
static const struct apd_device_desc hip08_spi_desc = {
|
||||
.setup = acpi_apd_setup,
|
||||
.fixed_clk_rate = 250000000,
|
||||
|
@ -238,6 +244,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = {
|
|||
{ "HISI02A1", APD_ADDR(hip07_i2c_desc) },
|
||||
{ "HISI02A2", APD_ADDR(hip08_i2c_desc) },
|
||||
{ "HISI0173", APD_ADDR(hip08_spi_desc) },
|
||||
{ "NXP0001", APD_ADDR(nxp_i2c_desc) },
|
||||
#endif
|
||||
{ }
|
||||
};
|
||||
|
|
|
@ -978,10 +978,10 @@ static int adv7511_init_cec_regmap(struct adv7511 *adv)
|
|||
{
|
||||
int ret;
|
||||
|
||||
adv->i2c_cec = i2c_new_secondary_device(adv->i2c_main, "cec",
|
||||
adv->i2c_cec = i2c_new_ancillary_device(adv->i2c_main, "cec",
|
||||
ADV7511_CEC_I2C_ADDR_DEFAULT);
|
||||
if (!adv->i2c_cec)
|
||||
return -EINVAL;
|
||||
if (IS_ERR(adv->i2c_cec))
|
||||
return PTR_ERR(adv->i2c_cec);
|
||||
i2c_set_clientdata(adv->i2c_cec, adv);
|
||||
|
||||
adv->regmap_cec = devm_regmap_init_i2c(adv->i2c_cec,
|
||||
|
@ -1162,20 +1162,20 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
|
|||
|
||||
adv7511_packet_disable(adv7511, 0xffff);
|
||||
|
||||
adv7511->i2c_edid = i2c_new_secondary_device(i2c, "edid",
|
||||
adv7511->i2c_edid = i2c_new_ancillary_device(i2c, "edid",
|
||||
ADV7511_EDID_I2C_ADDR_DEFAULT);
|
||||
if (!adv7511->i2c_edid) {
|
||||
ret = -EINVAL;
|
||||
if (IS_ERR(adv7511->i2c_edid)) {
|
||||
ret = PTR_ERR(adv7511->i2c_edid);
|
||||
goto uninit_regulators;
|
||||
}
|
||||
|
||||
regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR,
|
||||
adv7511->i2c_edid->addr << 1);
|
||||
|
||||
adv7511->i2c_packet = i2c_new_secondary_device(i2c, "packet",
|
||||
adv7511->i2c_packet = i2c_new_ancillary_device(i2c, "packet",
|
||||
ADV7511_PACKET_I2C_ADDR_DEFAULT);
|
||||
if (!adv7511->i2c_packet) {
|
||||
ret = -EINVAL;
|
||||
if (IS_ERR(adv7511->i2c_packet)) {
|
||||
ret = PTR_ERR(adv7511->i2c_packet);
|
||||
goto err_i2c_unregister_edid;
|
||||
}
|
||||
|
||||
|
|
|
@ -429,6 +429,7 @@ config I2C_AXXIA
|
|||
tristate "Axxia I2C controller"
|
||||
depends on ARCH_AXXIA || COMPILE_TEST
|
||||
default ARCH_AXXIA
|
||||
select I2C_SLAVE
|
||||
help
|
||||
Say yes if you want to support the I2C bus on Axxia platforms.
|
||||
|
||||
|
@ -977,7 +978,7 @@ config I2C_SIRF
|
|||
will be called i2c-sirf.
|
||||
|
||||
config I2C_SPRD
|
||||
bool "Spreadtrum I2C interface"
|
||||
tristate "Spreadtrum I2C interface"
|
||||
depends on I2C=y && ARCH_SPRD
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
|
@ -1309,6 +1310,20 @@ config I2C_ELEKTOR
|
|||
This support is also available as a module. If so, the module
|
||||
will be called i2c-elektor.
|
||||
|
||||
config I2C_ICY
|
||||
tristate "ICY Zorro card"
|
||||
depends on ZORRO
|
||||
select I2C_ALGOPCF
|
||||
help
|
||||
This supports the PCF8584 Zorro bus I2C adapter, known as ICY.
|
||||
Say Y if you own such an adapter.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-icy.
|
||||
|
||||
If you have a 2019 edition board with an LTC2990 sensor at address
|
||||
0x4c, loading the module 'ltc2990' is sufficient to enable it.
|
||||
|
||||
config I2C_MLXCPLD
|
||||
tristate "Mellanox I2C driver"
|
||||
depends on X86_64
|
||||
|
|
|
@ -140,6 +140,7 @@ obj-$(CONFIG_I2C_BCM_KONA) += i2c-bcm-kona.o
|
|||
obj-$(CONFIG_I2C_BRCMSTB) += i2c-brcmstb.o
|
||||
obj-$(CONFIG_I2C_CROS_EC_TUNNEL) += i2c-cros-ec-tunnel.o
|
||||
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
|
||||
obj-$(CONFIG_I2C_ICY) += i2c-icy.o
|
||||
obj-$(CONFIG_I2C_MLXCPLD) += i2c-mlxcpld.o
|
||||
obj-$(CONFIG_I2C_OPAL) += i2c-opal.o
|
||||
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
|
||||
|
|
|
@ -77,6 +77,40 @@
|
|||
MST_STATUS_IP)
|
||||
#define MST_TX_BYTES_XFRD 0x50
|
||||
#define MST_RX_BYTES_XFRD 0x54
|
||||
#define SLV_ADDR_DEC_CTL 0x58
|
||||
#define SLV_ADDR_DEC_GCE BIT(0) /* ACK to General Call Address from own master (loopback) */
|
||||
#define SLV_ADDR_DEC_OGCE BIT(1) /* ACK to General Call Address from external masters */
|
||||
#define SLV_ADDR_DEC_SA1E BIT(2) /* ACK to addr_1 enabled */
|
||||
#define SLV_ADDR_DEC_SA1M BIT(3) /* 10-bit addressing for addr_1 enabled */
|
||||
#define SLV_ADDR_DEC_SA2E BIT(4) /* ACK to addr_2 enabled */
|
||||
#define SLV_ADDR_DEC_SA2M BIT(5) /* 10-bit addressing for addr_2 enabled */
|
||||
#define SLV_ADDR_1 0x5c
|
||||
#define SLV_ADDR_2 0x60
|
||||
#define SLV_RX_CTL 0x64
|
||||
#define SLV_RX_ACSA1 BIT(0) /* Generate ACK for writes to addr_1 */
|
||||
#define SLV_RX_ACSA2 BIT(1) /* Generate ACK for writes to addr_2 */
|
||||
#define SLV_RX_ACGCA BIT(2) /* ACK data phase transfers to General Call Address */
|
||||
#define SLV_DATA 0x68
|
||||
#define SLV_RX_FIFO 0x6c
|
||||
#define SLV_FIFO_DV1 BIT(0) /* Data Valid for addr_1 */
|
||||
#define SLV_FIFO_DV2 BIT(1) /* Data Valid for addr_2 */
|
||||
#define SLV_FIFO_AS BIT(2) /* (N)ACK Sent */
|
||||
#define SLV_FIFO_TNAK BIT(3) /* Timeout NACK */
|
||||
#define SLV_FIFO_STRC BIT(4) /* First byte after start condition received */
|
||||
#define SLV_FIFO_RSC BIT(5) /* Repeated Start Condition */
|
||||
#define SLV_FIFO_STPC BIT(6) /* Stop Condition */
|
||||
#define SLV_FIFO_DV (SLV_FIFO_DV1 | SLV_FIFO_DV2)
|
||||
#define SLV_INT_ENABLE 0x70
|
||||
#define SLV_INT_STATUS 0x74
|
||||
#define SLV_STATUS_RFH BIT(0) /* FIFO service */
|
||||
#define SLV_STATUS_WTC BIT(1) /* Write transfer complete */
|
||||
#define SLV_STATUS_SRS1 BIT(2) /* Slave read from addr 1 */
|
||||
#define SLV_STATUS_SRRS1 BIT(3) /* Repeated start from addr 1 */
|
||||
#define SLV_STATUS_SRND1 BIT(4) /* Read request not following start condition */
|
||||
#define SLV_STATUS_SRC1 BIT(5) /* Read canceled */
|
||||
#define SLV_STATUS_SRAT1 BIT(6) /* Slave Read timed out */
|
||||
#define SLV_STATUS_SRDRE1 BIT(7) /* Data written after timed out */
|
||||
#define SLV_READ_DUMMY 0x78
|
||||
#define SCL_HIGH_PERIOD 0x80
|
||||
#define SCL_LOW_PERIOD 0x84
|
||||
#define SPIKE_FLTR_LEN 0x88
|
||||
|
@ -111,6 +145,8 @@ struct axxia_i2c_dev {
|
|||
struct clk *i2c_clk;
|
||||
u32 bus_clk_rate;
|
||||
bool last;
|
||||
struct i2c_client *slave;
|
||||
int irq;
|
||||
};
|
||||
|
||||
static void i2c_int_disable(struct axxia_i2c_dev *idev, u32 mask)
|
||||
|
@ -276,13 +312,65 @@ static int axxia_i2c_fill_tx_fifo(struct axxia_i2c_dev *idev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void axxia_i2c_slv_fifo_event(struct axxia_i2c_dev *idev)
|
||||
{
|
||||
u32 fifo_status = readl(idev->base + SLV_RX_FIFO);
|
||||
u8 val;
|
||||
|
||||
dev_dbg(idev->dev, "slave irq fifo_status=0x%x\n", fifo_status);
|
||||
|
||||
if (fifo_status & SLV_FIFO_DV1) {
|
||||
if (fifo_status & SLV_FIFO_STRC)
|
||||
i2c_slave_event(idev->slave,
|
||||
I2C_SLAVE_WRITE_REQUESTED, &val);
|
||||
|
||||
val = readl(idev->base + SLV_DATA);
|
||||
i2c_slave_event(idev->slave, I2C_SLAVE_WRITE_RECEIVED, &val);
|
||||
}
|
||||
if (fifo_status & SLV_FIFO_STPC) {
|
||||
readl(idev->base + SLV_DATA); /* dummy read */
|
||||
i2c_slave_event(idev->slave, I2C_SLAVE_STOP, &val);
|
||||
}
|
||||
if (fifo_status & SLV_FIFO_RSC)
|
||||
readl(idev->base + SLV_DATA); /* dummy read */
|
||||
}
|
||||
|
||||
static irqreturn_t axxia_i2c_slv_isr(struct axxia_i2c_dev *idev)
|
||||
{
|
||||
u32 status = readl(idev->base + SLV_INT_STATUS);
|
||||
u8 val;
|
||||
|
||||
dev_dbg(idev->dev, "slave irq status=0x%x\n", status);
|
||||
|
||||
if (status & SLV_STATUS_RFH)
|
||||
axxia_i2c_slv_fifo_event(idev);
|
||||
if (status & SLV_STATUS_SRS1) {
|
||||
i2c_slave_event(idev->slave, I2C_SLAVE_READ_REQUESTED, &val);
|
||||
writel(val, idev->base + SLV_DATA);
|
||||
}
|
||||
if (status & SLV_STATUS_SRND1) {
|
||||
i2c_slave_event(idev->slave, I2C_SLAVE_READ_PROCESSED, &val);
|
||||
writel(val, idev->base + SLV_DATA);
|
||||
}
|
||||
if (status & SLV_STATUS_SRC1)
|
||||
i2c_slave_event(idev->slave, I2C_SLAVE_STOP, &val);
|
||||
|
||||
writel(INT_SLV, idev->base + INTERRUPT_STATUS);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t axxia_i2c_isr(int irq, void *_dev)
|
||||
{
|
||||
struct axxia_i2c_dev *idev = _dev;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
u32 status;
|
||||
|
||||
if (!(readl(idev->base + INTERRUPT_STATUS) & INT_MST))
|
||||
return IRQ_NONE;
|
||||
status = readl(idev->base + INTERRUPT_STATUS);
|
||||
|
||||
if (status & INT_SLV)
|
||||
ret = axxia_i2c_slv_isr(idev);
|
||||
if (!(status & INT_MST))
|
||||
return ret;
|
||||
|
||||
/* Read interrupt status bits */
|
||||
status = readl(idev->base + MST_INT_STATUS);
|
||||
|
@ -583,9 +671,58 @@ static u32 axxia_i2c_func(struct i2c_adapter *adap)
|
|||
return caps;
|
||||
}
|
||||
|
||||
static int axxia_i2c_reg_slave(struct i2c_client *slave)
|
||||
{
|
||||
struct axxia_i2c_dev *idev = i2c_get_adapdata(slave->adapter);
|
||||
u32 slv_int_mask = SLV_STATUS_RFH;
|
||||
u32 dec_ctl;
|
||||
|
||||
if (idev->slave)
|
||||
return -EBUSY;
|
||||
|
||||
idev->slave = slave;
|
||||
|
||||
/* Enable slave mode as well */
|
||||
writel(GLOBAL_MST_EN | GLOBAL_SLV_EN, idev->base + GLOBAL_CONTROL);
|
||||
writel(INT_MST | INT_SLV, idev->base + INTERRUPT_ENABLE);
|
||||
|
||||
/* Set slave address */
|
||||
dec_ctl = SLV_ADDR_DEC_SA1E;
|
||||
if (slave->flags & I2C_CLIENT_TEN)
|
||||
dec_ctl |= SLV_ADDR_DEC_SA1M;
|
||||
|
||||
writel(SLV_RX_ACSA1, idev->base + SLV_RX_CTL);
|
||||
writel(dec_ctl, idev->base + SLV_ADDR_DEC_CTL);
|
||||
writel(slave->addr, idev->base + SLV_ADDR_1);
|
||||
|
||||
/* Enable interrupts */
|
||||
slv_int_mask |= SLV_STATUS_SRS1 | SLV_STATUS_SRRS1 | SLV_STATUS_SRND1;
|
||||
slv_int_mask |= SLV_STATUS_SRC1;
|
||||
writel(slv_int_mask, idev->base + SLV_INT_ENABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int axxia_i2c_unreg_slave(struct i2c_client *slave)
|
||||
{
|
||||
struct axxia_i2c_dev *idev = i2c_get_adapdata(slave->adapter);
|
||||
|
||||
/* Disable slave mode */
|
||||
writel(GLOBAL_MST_EN, idev->base + GLOBAL_CONTROL);
|
||||
writel(INT_MST, idev->base + INTERRUPT_ENABLE);
|
||||
|
||||
synchronize_irq(idev->irq);
|
||||
|
||||
idev->slave = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm axxia_i2c_algo = {
|
||||
.master_xfer = axxia_i2c_xfer,
|
||||
.functionality = axxia_i2c_func,
|
||||
.reg_slave = axxia_i2c_reg_slave,
|
||||
.unreg_slave = axxia_i2c_unreg_slave,
|
||||
};
|
||||
|
||||
static const struct i2c_adapter_quirks axxia_i2c_quirks = {
|
||||
|
@ -599,7 +736,6 @@ static int axxia_i2c_probe(struct platform_device *pdev)
|
|||
struct axxia_i2c_dev *idev = NULL;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
int ret = 0;
|
||||
|
||||
idev = devm_kzalloc(&pdev->dev, sizeof(*idev), GFP_KERNEL);
|
||||
|
@ -611,10 +747,10 @@ static int axxia_i2c_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
idev->irq = platform_get_irq(pdev, 0);
|
||||
if (idev->irq < 0) {
|
||||
dev_err(&pdev->dev, "missing interrupt resource\n");
|
||||
return irq;
|
||||
return idev->irq;
|
||||
}
|
||||
|
||||
idev->i2c_clk = devm_clk_get(&pdev->dev, "i2c");
|
||||
|
@ -643,10 +779,10 @@ static int axxia_i2c_probe(struct platform_device *pdev)
|
|||
goto error_disable_clk;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, irq, axxia_i2c_isr, 0,
|
||||
ret = devm_request_irq(&pdev->dev, idev->irq, axxia_i2c_isr, 0,
|
||||
pdev->name, idev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to claim IRQ%d\n", irq);
|
||||
dev_err(&pdev->dev, "failed to claim IRQ%d\n", idev->irq);
|
||||
goto error_disable_clk;
|
||||
}
|
||||
|
||||
|
|
|
@ -808,7 +808,7 @@ static struct i2c_algorithm bcm_iproc_algo = {
|
|||
.unreg_slave = bcm_iproc_i2c_unreg_slave,
|
||||
};
|
||||
|
||||
static struct i2c_adapter_quirks bcm_iproc_i2c_quirks = {
|
||||
static const struct i2c_adapter_quirks bcm_iproc_i2c_quirks = {
|
||||
.max_read_len = M_RX_MAX_READ_LEN,
|
||||
};
|
||||
|
||||
|
@ -922,7 +922,9 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
adap = &iproc_i2c->adapter;
|
||||
i2c_set_adapdata(adap, iproc_i2c);
|
||||
strlcpy(adap->name, "Broadcom iProc I2C adapter", sizeof(adap->name));
|
||||
snprintf(adap->name, sizeof(adap->name),
|
||||
"Broadcom iProc (%s)",
|
||||
of_node_full_name(iproc_i2c->device->of_node));
|
||||
adap->algo = &bcm_iproc_algo;
|
||||
adap->quirks = &bcm_iproc_i2c_quirks;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
@ -389,7 +390,7 @@ static const struct i2c_algorithm bcm2835_i2c_algo = {
|
|||
};
|
||||
|
||||
/*
|
||||
* This HW 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.raspberrypi.org/forums/viewtopic.php?p=146272
|
||||
*/
|
||||
|
@ -471,11 +472,12 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
|
|||
i2c_set_adapdata(adap, i2c_dev);
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->class = I2C_CLASS_DEPRECATED;
|
||||
strlcpy(adap->name, "bcm2835 I2C adapter", sizeof(adap->name));
|
||||
snprintf(adap->name, sizeof(adap->name), "bcm2835 (%s)",
|
||||
of_node_full_name(pdev->dev.of_node));
|
||||
adap->algo = &bcm2835_i2c_algo;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
adap->dev.of_node = pdev->dev.of_node;
|
||||
adap->quirks = &bcm2835_i2c_quirks;
|
||||
adap->quirks = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, 0);
|
||||
|
||||
|
@ -501,7 +503,8 @@ static int bcm2835_i2c_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static const struct of_device_id bcm2835_i2c_of_match[] = {
|
||||
{ .compatible = "brcm,bcm2835-i2c" },
|
||||
{ .compatible = "brcm,bcm2711-i2c" },
|
||||
{ .compatible = "brcm,bcm2835-i2c", .data = &bcm2835_i2c_quirks },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bcm2835_i2c_of_match);
|
||||
|
|
|
@ -178,6 +178,51 @@ static const struct i2c_algorithm cht_wc_i2c_adap_algo = {
|
|||
.smbus_xfer = cht_wc_i2c_adap_smbus_xfer,
|
||||
};
|
||||
|
||||
/*
|
||||
* We are an i2c-adapter which itself is part of an i2c-client. This means that
|
||||
* transfers done through us take adapter->bus_lock twice, once for our parent
|
||||
* i2c-adapter and once to take our own bus_lock. Lockdep does not like this
|
||||
* nested locking, to make lockdep happy in the case of busses with muxes, the
|
||||
* i2c-core's i2c_adapter_lock_bus function calls:
|
||||
* rt_mutex_lock_nested(&adapter->bus_lock, i2c_adapter_depth(adapter));
|
||||
*
|
||||
* But i2c_adapter_depth only works when the direct parent of the adapter is
|
||||
* another adapter, as it is only meant for muxes. In our case there is an
|
||||
* i2c-client and MFD instantiated platform_device in the parent->child chain
|
||||
* between the 2 devices.
|
||||
*
|
||||
* So we override the default i2c_lock_operations and pass a hardcoded
|
||||
* depth of 1 to rt_mutex_lock_nested, to make lockdep happy.
|
||||
*
|
||||
* Note that if there were to be a mux attached to our adapter, this would
|
||||
* break things again since the i2c-mux code expects the root-adapter to have
|
||||
* a locking depth of 0. But we always have only 1 client directly attached
|
||||
* in the form of the Charger IC paired with the CHT Whiskey Cove PMIC.
|
||||
*/
|
||||
static void cht_wc_i2c_adap_lock_bus(struct i2c_adapter *adapter,
|
||||
unsigned int flags)
|
||||
{
|
||||
rt_mutex_lock_nested(&adapter->bus_lock, 1);
|
||||
}
|
||||
|
||||
static int cht_wc_i2c_adap_trylock_bus(struct i2c_adapter *adapter,
|
||||
unsigned int flags)
|
||||
{
|
||||
return rt_mutex_trylock(&adapter->bus_lock);
|
||||
}
|
||||
|
||||
static void cht_wc_i2c_adap_unlock_bus(struct i2c_adapter *adapter,
|
||||
unsigned int flags)
|
||||
{
|
||||
rt_mutex_unlock(&adapter->bus_lock);
|
||||
}
|
||||
|
||||
static const struct i2c_lock_operations cht_wc_i2c_adap_lock_ops = {
|
||||
.lock_bus = cht_wc_i2c_adap_lock_bus,
|
||||
.trylock_bus = cht_wc_i2c_adap_trylock_bus,
|
||||
.unlock_bus = cht_wc_i2c_adap_unlock_bus,
|
||||
};
|
||||
|
||||
/**** irqchip for the client connected to the extchgr i2c adapter ****/
|
||||
static void cht_wc_i2c_irq_lock(struct irq_data *data)
|
||||
{
|
||||
|
@ -286,6 +331,7 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
|
|||
adap->adapter.owner = THIS_MODULE;
|
||||
adap->adapter.class = I2C_CLASS_HWMON;
|
||||
adap->adapter.algo = &cht_wc_i2c_adap_algo;
|
||||
adap->adapter.lock_ops = &cht_wc_i2c_adap_lock_ops;
|
||||
strlcpy(adap->adapter.name, "PMIC I2C Adapter",
|
||||
sizeof(adap->adapter.name));
|
||||
adap->adapter.dev.parent = &pdev->dev;
|
||||
|
@ -363,8 +409,7 @@ static int cht_wc_i2c_adap_i2c_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct cht_wc_i2c_adap *adap = platform_get_drvdata(pdev);
|
||||
|
||||
if (adap->client)
|
||||
i2c_unregister_device(adap->client);
|
||||
i2c_unregister_device(adap->client);
|
||||
i2c_del_adapter(&adap->adapter);
|
||||
irq_domain_remove(adap->irq_domain);
|
||||
|
||||
|
|
|
@ -655,15 +655,11 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev)
|
|||
struct i2c_bus_recovery_info *rinfo = &dev->rinfo;
|
||||
struct i2c_adapter *adap = &dev->adapter;
|
||||
struct gpio_desc *gpio;
|
||||
int r;
|
||||
|
||||
gpio = devm_gpiod_get(dev->dev, "scl", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(gpio)) {
|
||||
r = PTR_ERR(gpio);
|
||||
if (r == -ENOENT || r == -ENOSYS)
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
gpio = devm_gpiod_get_optional(dev->dev, "scl", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR_OR_NULL(gpio))
|
||||
return PTR_ERR_OR_ZERO(gpio);
|
||||
|
||||
rinfo->scl_gpiod = gpio;
|
||||
|
||||
gpio = devm_gpiod_get_optional(dev->dev, "sda", GPIOD_IN);
|
||||
|
|
|
@ -33,6 +33,7 @@ enum dw_pci_ctl_id_t {
|
|||
baytrail,
|
||||
cherrytrail,
|
||||
haswell,
|
||||
elkhartlake,
|
||||
};
|
||||
|
||||
struct dw_scl_sda_cfg {
|
||||
|
@ -168,13 +169,20 @@ static struct dw_pci_controller dw_pci_controllers[] = {
|
|||
.flags = MODEL_CHERRYTRAIL,
|
||||
.scl_sda_cfg = &byt_config,
|
||||
},
|
||||
[elkhartlake] = {
|
||||
.bus_num = -1,
|
||||
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
|
||||
.tx_fifo_depth = 32,
|
||||
.rx_fifo_depth = 32,
|
||||
.functionality = I2C_FUNC_10BIT_ADDR,
|
||||
.clk_khz = 100000,
|
||||
},
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int i2c_dw_pci_suspend(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct dw_i2c_dev *i_dev = pci_get_drvdata(pdev);
|
||||
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
|
||||
|
||||
i_dev->suspended = true;
|
||||
i_dev->disable(i_dev);
|
||||
|
@ -184,8 +192,7 @@ static int i2c_dw_pci_suspend(struct device *dev)
|
|||
|
||||
static int i2c_dw_pci_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct dw_i2c_dev *i_dev = pci_get_drvdata(pdev);
|
||||
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = i_dev->init(i_dev);
|
||||
|
@ -227,6 +234,8 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
|
|||
return r;
|
||||
}
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
r = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev));
|
||||
if (r) {
|
||||
dev_err(&pdev->dev, "I/O memory remapping failed\n");
|
||||
|
@ -237,18 +246,24 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
|
|||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
r = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
dev->clk = NULL;
|
||||
dev->controller = controller;
|
||||
dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
|
||||
dev->base = pcim_iomap_table(pdev)[0];
|
||||
dev->dev = &pdev->dev;
|
||||
dev->irq = pdev->irq;
|
||||
dev->irq = pci_irq_vector(pdev, 0);
|
||||
dev->flags |= controller->flags;
|
||||
|
||||
if (controller->setup) {
|
||||
r = controller->setup(pdev, controller);
|
||||
if (r)
|
||||
if (r) {
|
||||
pci_free_irq_vectors(pdev);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
dev->functionality = controller->functionality |
|
||||
|
@ -276,8 +291,10 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
|
|||
adap->nr = controller->bus_num;
|
||||
|
||||
r = i2c_dw_probe(dev);
|
||||
if (r)
|
||||
if (r) {
|
||||
pci_free_irq_vectors(pdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
|
@ -296,6 +313,7 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev)
|
|||
pm_runtime_get_noresume(&pdev->dev);
|
||||
|
||||
i2c_del_adapter(&dev->adapter);
|
||||
pci_free_irq_vectors(pdev);
|
||||
}
|
||||
|
||||
/* work with hotplug and coldplug */
|
||||
|
@ -331,6 +349,15 @@ static const struct pci_device_id i2_designware_pci_ids[] = {
|
|||
{ PCI_VDEVICE(INTEL, 0x22C5), cherrytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C6), cherrytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C7), cherrytrail },
|
||||
/* Elkhart Lake (PSE I2C) */
|
||||
{ PCI_VDEVICE(INTEL, 0x4bb9), elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bba), elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bbb), elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bbc), elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bbd), elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bbe), elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bbf), elkhartlake },
|
||||
{ PCI_VDEVICE(INTEL, 0x4bc0), elkhartlake },
|
||||
{ 0,}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids);
|
||||
|
|
|
@ -279,12 +279,10 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, dev);
|
||||
|
||||
dev->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
|
||||
if (IS_ERR(dev->rst)) {
|
||||
if (PTR_ERR(dev->rst) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
} else {
|
||||
reset_control_deassert(dev->rst);
|
||||
}
|
||||
if (IS_ERR(dev->rst))
|
||||
return PTR_ERR(dev->rst);
|
||||
|
||||
reset_control_deassert(dev->rst);
|
||||
|
||||
t = &dev->timings;
|
||||
if (pdata)
|
||||
|
@ -346,8 +344,10 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
|
|||
|
||||
/* Optional interface clock */
|
||||
dev->pclk = devm_clk_get_optional(&pdev->dev, "pclk");
|
||||
if (IS_ERR(dev->pclk))
|
||||
return PTR_ERR(dev->pclk);
|
||||
if (IS_ERR(dev->pclk)) {
|
||||
ret = PTR_ERR(dev->pclk);
|
||||
goto exit_reset;
|
||||
}
|
||||
|
||||
dev->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (!i2c_dw_prepare_clk(dev, true)) {
|
||||
|
@ -400,8 +400,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
|
|||
exit_probe:
|
||||
dw_i2c_plat_pm_cleanup(dev);
|
||||
exit_reset:
|
||||
if (!IS_ERR_OR_NULL(dev->rst))
|
||||
reset_control_assert(dev->rst);
|
||||
reset_control_assert(dev->rst);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -419,8 +418,7 @@ static int dw_i2c_plat_remove(struct platform_device *pdev)
|
|||
pm_runtime_put_sync(&pdev->dev);
|
||||
dw_i2c_plat_pm_cleanup(dev);
|
||||
|
||||
if (!IS_ERR_OR_NULL(dev->rst))
|
||||
reset_control_assert(dev->rst);
|
||||
reset_control_assert(dev->rst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -791,9 +791,7 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, i2c->irq, exynos5_i2c_irq,
|
||||
IRQF_NO_SUSPEND | IRQF_ONESHOT,
|
||||
dev_name(&pdev->dev), i2c);
|
||||
|
||||
IRQF_NO_SUSPEND, dev_name(&pdev->dev), i2c);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "cannot request HS-I2C IRQ %d\n", i2c->irq);
|
||||
goto err_clk;
|
||||
|
|
|
@ -707,8 +707,10 @@ static int fsi_i2c_probe(struct device *dev)
|
|||
continue;
|
||||
|
||||
port = kzalloc(sizeof(*port), GFP_KERNEL);
|
||||
if (!port)
|
||||
if (!port) {
|
||||
of_node_put(np);
|
||||
break;
|
||||
}
|
||||
|
||||
port->master = i2c;
|
||||
port->port = port_no;
|
||||
|
|
|
@ -445,8 +445,7 @@ static int hix5hd2_i2c_probe(struct platform_device *pdev)
|
|||
hix5hd2_i2c_init(priv);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, irq, hix5hd2_i2c_irq,
|
||||
IRQF_NO_SUSPEND | IRQF_ONESHOT,
|
||||
dev_name(&pdev->dev), priv);
|
||||
IRQF_NO_SUSPEND, dev_name(&pdev->dev), priv);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "cannot request HS-I2C IRQ %d\n", irq);
|
||||
goto err_clk;
|
||||
|
|
|
@ -292,7 +292,8 @@ struct i801_priv {
|
|||
#define FEATURE_HOST_NOTIFY BIT(5)
|
||||
/* Not really a feature, but it's convenient to handle it as such */
|
||||
#define FEATURE_IDF BIT(15)
|
||||
#define FEATURE_TCO BIT(16)
|
||||
#define FEATURE_TCO_SPT BIT(16)
|
||||
#define FEATURE_TCO_CNL BIT(17)
|
||||
|
||||
static const char *i801_feature_names[] = {
|
||||
"SMBus PEC",
|
||||
|
@ -1500,57 +1501,23 @@ static inline unsigned int i801_get_adapter_class(struct i801_priv *priv)
|
|||
}
|
||||
#endif
|
||||
|
||||
static const struct itco_wdt_platform_data tco_platform_data = {
|
||||
static const struct itco_wdt_platform_data spt_tco_platform_data = {
|
||||
.name = "Intel PCH",
|
||||
.version = 4,
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(p2sb_spinlock);
|
||||
|
||||
static void i801_add_tco(struct i801_priv *priv)
|
||||
static struct platform_device *
|
||||
i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev,
|
||||
struct resource *tco_res)
|
||||
{
|
||||
struct pci_dev *pci_dev = priv->pci_dev;
|
||||
struct resource tco_res[3], *res;
|
||||
struct platform_device *pdev;
|
||||
struct resource *res;
|
||||
unsigned int devfn;
|
||||
u32 tco_base, tco_ctl;
|
||||
u32 base_addr, ctrl_val;
|
||||
u64 base64_addr;
|
||||
u32 base_addr;
|
||||
u8 hidden;
|
||||
|
||||
if (!(priv->features & FEATURE_TCO))
|
||||
return;
|
||||
|
||||
pci_read_config_dword(pci_dev, TCOBASE, &tco_base);
|
||||
pci_read_config_dword(pci_dev, TCOCTL, &tco_ctl);
|
||||
if (!(tco_ctl & TCOCTL_EN))
|
||||
return;
|
||||
|
||||
memset(tco_res, 0, sizeof(tco_res));
|
||||
|
||||
res = &tco_res[ICH_RES_IO_TCO];
|
||||
res->start = tco_base & ~1;
|
||||
res->end = res->start + 32 - 1;
|
||||
res->flags = IORESOURCE_IO;
|
||||
|
||||
/*
|
||||
* Power Management registers.
|
||||
*/
|
||||
devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 2);
|
||||
pci_bus_read_config_dword(pci_dev->bus, devfn, ACPIBASE, &base_addr);
|
||||
|
||||
res = &tco_res[ICH_RES_IO_SMI];
|
||||
res->start = (base_addr & ~1) + ACPIBASE_SMI_OFF;
|
||||
res->end = res->start + 3;
|
||||
res->flags = IORESOURCE_IO;
|
||||
|
||||
/*
|
||||
* Enable the ACPI I/O space.
|
||||
*/
|
||||
pci_bus_read_config_dword(pci_dev->bus, devfn, ACPICTRL, &ctrl_val);
|
||||
ctrl_val |= ACPICTRL_EN;
|
||||
pci_bus_write_config_dword(pci_dev->bus, devfn, ACPICTRL, ctrl_val);
|
||||
|
||||
/*
|
||||
* We must access the NO_REBOOT bit over the Primary to Sideband
|
||||
* bridge (P2SB). The BIOS prevents the P2SB device from being
|
||||
|
@ -1586,15 +1553,76 @@ static void i801_add_tco(struct i801_priv *priv)
|
|||
res->end = res->start + 3;
|
||||
res->flags = IORESOURCE_MEM;
|
||||
|
||||
pdev = platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1,
|
||||
tco_res, 3, &tco_platform_data,
|
||||
sizeof(tco_platform_data));
|
||||
if (IS_ERR(pdev)) {
|
||||
dev_warn(&pci_dev->dev, "failed to create iTCO device\n");
|
||||
return;
|
||||
}
|
||||
return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1,
|
||||
tco_res, 3, &spt_tco_platform_data,
|
||||
sizeof(spt_tco_platform_data));
|
||||
}
|
||||
|
||||
priv->tco_pdev = pdev;
|
||||
static const struct itco_wdt_platform_data cnl_tco_platform_data = {
|
||||
.name = "Intel PCH",
|
||||
.version = 6,
|
||||
};
|
||||
|
||||
static struct platform_device *
|
||||
i801_add_tco_cnl(struct i801_priv *priv, struct pci_dev *pci_dev,
|
||||
struct resource *tco_res)
|
||||
{
|
||||
return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1,
|
||||
tco_res, 2, &cnl_tco_platform_data,
|
||||
sizeof(cnl_tco_platform_data));
|
||||
}
|
||||
|
||||
static void i801_add_tco(struct i801_priv *priv)
|
||||
{
|
||||
u32 base_addr, tco_base, tco_ctl, ctrl_val;
|
||||
struct pci_dev *pci_dev = priv->pci_dev;
|
||||
struct resource tco_res[3], *res;
|
||||
unsigned int devfn;
|
||||
|
||||
/* If we have ACPI based watchdog use that instead */
|
||||
if (acpi_has_watchdog())
|
||||
return;
|
||||
|
||||
if (!(priv->features & (FEATURE_TCO_SPT | FEATURE_TCO_CNL)))
|
||||
return;
|
||||
|
||||
pci_read_config_dword(pci_dev, TCOBASE, &tco_base);
|
||||
pci_read_config_dword(pci_dev, TCOCTL, &tco_ctl);
|
||||
if (!(tco_ctl & TCOCTL_EN))
|
||||
return;
|
||||
|
||||
memset(tco_res, 0, sizeof(tco_res));
|
||||
|
||||
res = &tco_res[ICH_RES_IO_TCO];
|
||||
res->start = tco_base & ~1;
|
||||
res->end = res->start + 32 - 1;
|
||||
res->flags = IORESOURCE_IO;
|
||||
|
||||
/*
|
||||
* Power Management registers.
|
||||
*/
|
||||
devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 2);
|
||||
pci_bus_read_config_dword(pci_dev->bus, devfn, ACPIBASE, &base_addr);
|
||||
|
||||
res = &tco_res[ICH_RES_IO_SMI];
|
||||
res->start = (base_addr & ~1) + ACPIBASE_SMI_OFF;
|
||||
res->end = res->start + 3;
|
||||
res->flags = IORESOURCE_IO;
|
||||
|
||||
/*
|
||||
* Enable the ACPI I/O space.
|
||||
*/
|
||||
pci_bus_read_config_dword(pci_dev->bus, devfn, ACPICTRL, &ctrl_val);
|
||||
ctrl_val |= ACPICTRL_EN;
|
||||
pci_bus_write_config_dword(pci_dev->bus, devfn, ACPICTRL, ctrl_val);
|
||||
|
||||
if (priv->features & FEATURE_TCO_CNL)
|
||||
priv->tco_pdev = i801_add_tco_cnl(priv, pci_dev, tco_res);
|
||||
else
|
||||
priv->tco_pdev = i801_add_tco_spt(priv, pci_dev, tco_res);
|
||||
|
||||
if (IS_ERR(priv->tco_pdev))
|
||||
dev_warn(&pci_dev->dev, "failed to create iTCO device\n");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
@ -1704,13 +1732,21 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||
switch (dev->device) {
|
||||
case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_CDF_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_DNV_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS:
|
||||
priv->features |= FEATURE_I2C_BLOCK_READ;
|
||||
priv->features |= FEATURE_IRQ;
|
||||
priv->features |= FEATURE_SMBUS_PEC;
|
||||
priv->features |= FEATURE_BLOCK_BUFFER;
|
||||
priv->features |= FEATURE_TCO_SPT;
|
||||
priv->features |= FEATURE_HOST_NOTIFY;
|
||||
break;
|
||||
|
||||
case PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_CDF_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS:
|
||||
|
@ -1720,9 +1756,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||
priv->features |= FEATURE_IRQ;
|
||||
priv->features |= FEATURE_SMBUS_PEC;
|
||||
priv->features |= FEATURE_BLOCK_BUFFER;
|
||||
/* If we have ACPI based watchdog use that instead */
|
||||
if (!acpi_has_watchdog())
|
||||
priv->features |= FEATURE_TCO;
|
||||
priv->features |= FEATURE_TCO_CNL;
|
||||
priv->features |= FEATURE_HOST_NOTIFY;
|
||||
break;
|
||||
|
||||
|
@ -1921,8 +1955,7 @@ static int i801_suspend(struct device *dev)
|
|||
|
||||
static int i801_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
struct i801_priv *priv = pci_get_drvdata(pci_dev);
|
||||
struct i801_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
i801_enable_host_notify(&priv->adapter);
|
||||
|
||||
|
|
|
@ -0,0 +1,230 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* I2C driver for stand-alone PCF8584 style adapters on Zorro cards
|
||||
*
|
||||
* Original ICY documentation can be found on Aminet:
|
||||
* https://aminet.net/package/docs/hard/icy
|
||||
*
|
||||
* There has been a modern community re-print of this design in 2019:
|
||||
* https://www.a1k.org/forum/index.php?threads/70106/
|
||||
*
|
||||
* The card is basically a Philips PCF8584 connected straight to the
|
||||
* beginning of the AutoConfig'd address space (register S1 on base+2),
|
||||
* with /INT on /INT2 on the Zorro bus.
|
||||
*
|
||||
* Copyright (c) 2019 Max Staudt <max@enpas.org>
|
||||
*
|
||||
* This started as a fork of i2c-elektor.c and has evolved since.
|
||||
* Thanks go to its authors for providing a base to grow on.
|
||||
*
|
||||
*
|
||||
* IRQ support is currently not implemented.
|
||||
*
|
||||
* As it turns out, i2c-algo-pcf is really written with i2c-elektor's
|
||||
* edge-triggered ISA interrupts in mind, while the Amiga's Zorro bus has
|
||||
* level-triggered interrupts. This means that once an interrupt occurs, we
|
||||
* have to tell the PCF8584 to shut up immediately, or it will keep the
|
||||
* interrupt line busy and cause an IRQ storm.
|
||||
|
||||
* However, because of the PCF8584's host-side protocol, there is no good
|
||||
* way to just quieten it without side effects. Rather, we have to perform
|
||||
* the next read/write operation straight away, which will reset the /INT
|
||||
* pin. This entails re-designing the core of i2c-algo-pcf in the future.
|
||||
* For now, we never request an IRQ from the PCF8584, and poll it instead.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-pcf.h>
|
||||
|
||||
#include <asm/amigaints.h>
|
||||
#include <linux/zorro.h>
|
||||
|
||||
#include "../algos/i2c-algo-pcf.h"
|
||||
|
||||
struct icy_i2c {
|
||||
struct i2c_adapter adapter;
|
||||
|
||||
void __iomem *reg_s0;
|
||||
void __iomem *reg_s1;
|
||||
struct fwnode_handle *ltc2990_fwnode;
|
||||
struct i2c_client *ltc2990_client;
|
||||
};
|
||||
|
||||
/*
|
||||
* Functions called by i2c-algo-pcf
|
||||
*/
|
||||
static void icy_pcf_setpcf(void *data, int ctl, int val)
|
||||
{
|
||||
struct icy_i2c *i2c = (struct icy_i2c *)data;
|
||||
|
||||
u8 __iomem *address = ctl ? i2c->reg_s1 : i2c->reg_s0;
|
||||
|
||||
z_writeb(val, address);
|
||||
}
|
||||
|
||||
static int icy_pcf_getpcf(void *data, int ctl)
|
||||
{
|
||||
struct icy_i2c *i2c = (struct icy_i2c *)data;
|
||||
|
||||
u8 __iomem *address = ctl ? i2c->reg_s1 : i2c->reg_s0;
|
||||
|
||||
return z_readb(address);
|
||||
}
|
||||
|
||||
static int icy_pcf_getown(void *data)
|
||||
{
|
||||
return 0x55;
|
||||
}
|
||||
|
||||
static int icy_pcf_getclock(void *data)
|
||||
{
|
||||
return 0x1c;
|
||||
}
|
||||
|
||||
static void icy_pcf_waitforpin(void *data)
|
||||
{
|
||||
usleep_range(50, 150);
|
||||
}
|
||||
|
||||
/*
|
||||
* Main i2c-icy part
|
||||
*/
|
||||
static unsigned short const icy_ltc2990_addresses[] = {
|
||||
0x4c, 0x4d, 0x4e, 0x4f, I2C_CLIENT_END
|
||||
};
|
||||
|
||||
/*
|
||||
* Additional sensors exposed once this property is applied:
|
||||
*
|
||||
* in1 will be the voltage of the 5V rail, divided by 2.
|
||||
* in2 will be the voltage of the 12V rail, divided by 4.
|
||||
* temp3 will be measured using a PCB loop next the chip.
|
||||
*/
|
||||
static const u32 icy_ltc2990_meas_mode[] = {0, 3};
|
||||
|
||||
static const struct property_entry icy_ltc2990_props[] = {
|
||||
PROPERTY_ENTRY_U32_ARRAY("lltc,meas-mode", icy_ltc2990_meas_mode),
|
||||
{ }
|
||||
};
|
||||
|
||||
static int icy_probe(struct zorro_dev *z,
|
||||
const struct zorro_device_id *ent)
|
||||
{
|
||||
struct icy_i2c *i2c;
|
||||
struct i2c_algo_pcf_data *algo_data;
|
||||
struct fwnode_handle *new_fwnode;
|
||||
struct i2c_board_info ltc2990_info = {
|
||||
.type = "ltc2990",
|
||||
.addr = 0x4c,
|
||||
};
|
||||
|
||||
i2c = devm_kzalloc(&z->dev, sizeof(*i2c), GFP_KERNEL);
|
||||
if (!i2c)
|
||||
return -ENOMEM;
|
||||
|
||||
algo_data = devm_kzalloc(&z->dev, sizeof(*algo_data), GFP_KERNEL);
|
||||
if (!algo_data)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(&z->dev, i2c);
|
||||
i2c->adapter.dev.parent = &z->dev;
|
||||
i2c->adapter.owner = THIS_MODULE;
|
||||
/* i2c->adapter.algo assigned by i2c_pcf_add_bus() */
|
||||
i2c->adapter.algo_data = algo_data;
|
||||
strlcpy(i2c->adapter.name, "ICY I2C Zorro adapter",
|
||||
sizeof(i2c->adapter.name));
|
||||
|
||||
if (!devm_request_mem_region(&z->dev,
|
||||
z->resource.start,
|
||||
4, i2c->adapter.name))
|
||||
return -ENXIO;
|
||||
|
||||
/* Driver private data */
|
||||
i2c->reg_s0 = ZTWO_VADDR(z->resource.start);
|
||||
i2c->reg_s1 = ZTWO_VADDR(z->resource.start + 2);
|
||||
|
||||
algo_data->data = i2c;
|
||||
algo_data->setpcf = icy_pcf_setpcf;
|
||||
algo_data->getpcf = icy_pcf_getpcf;
|
||||
algo_data->getown = icy_pcf_getown;
|
||||
algo_data->getclock = icy_pcf_getclock;
|
||||
algo_data->waitforpin = icy_pcf_waitforpin;
|
||||
|
||||
if (i2c_pcf_add_bus(&i2c->adapter)) {
|
||||
dev_err(&z->dev, "i2c_pcf_add_bus() failed\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
dev_info(&z->dev, "ICY I2C controller at %pa, IRQ not implemented\n",
|
||||
&z->resource.start);
|
||||
|
||||
/*
|
||||
* The 2019 a1k.org PCBs have an LTC2990 at 0x4c, so start
|
||||
* it automatically once ltc2990 is modprobed.
|
||||
*
|
||||
* in0 is the voltage of the internal 5V power supply.
|
||||
* temp1 is the temperature inside the chip.
|
||||
*
|
||||
* See property_entry above for in1, in2, temp3.
|
||||
*/
|
||||
new_fwnode = fwnode_create_software_node(icy_ltc2990_props, NULL);
|
||||
if (IS_ERR(new_fwnode)) {
|
||||
dev_info(&z->dev, "Failed to create fwnode for LTC2990, error: %ld\n",
|
||||
PTR_ERR(new_fwnode));
|
||||
} else {
|
||||
/*
|
||||
* Store the fwnode so we can destroy it on .remove().
|
||||
* Only store it on success, as fwnode_remove_software_node()
|
||||
* is NULL safe, but not PTR_ERR safe.
|
||||
*/
|
||||
i2c->ltc2990_fwnode = new_fwnode;
|
||||
ltc2990_info.fwnode = new_fwnode;
|
||||
|
||||
i2c->ltc2990_client =
|
||||
i2c_new_probed_device(&i2c->adapter,
|
||||
<c2990_info,
|
||||
icy_ltc2990_addresses,
|
||||
NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void icy_remove(struct zorro_dev *z)
|
||||
{
|
||||
struct icy_i2c *i2c = dev_get_drvdata(&z->dev);
|
||||
|
||||
i2c_unregister_device(i2c->ltc2990_client);
|
||||
fwnode_remove_software_node(i2c->ltc2990_fwnode);
|
||||
|
||||
i2c_del_adapter(&i2c->adapter);
|
||||
}
|
||||
|
||||
static const struct zorro_device_id icy_zorro_tbl[] = {
|
||||
{ ZORRO_ID(VMC, 15, 0), },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(zorro, icy_zorro_tbl);
|
||||
|
||||
static struct zorro_driver icy_driver = {
|
||||
.name = "i2c-icy",
|
||||
.id_table = icy_zorro_tbl,
|
||||
.probe = icy_probe,
|
||||
.remove = icy_remove,
|
||||
};
|
||||
|
||||
module_driver(icy_driver,
|
||||
zorro_register_driver,
|
||||
zorro_unregister_driver);
|
||||
|
||||
MODULE_AUTHOR("Max Staudt <max@enpas.org>");
|
||||
MODULE_DESCRIPTION("I2C bus via PCF8584 on ICY Zorro card");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -545,7 +545,6 @@ MODULE_DEVICE_TABLE(of, lpi2c_imx_of_match);
|
|||
static int lpi2c_imx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct lpi2c_imx_struct *lpi2c_imx;
|
||||
struct resource *res;
|
||||
unsigned int temp;
|
||||
int irq, ret;
|
||||
|
||||
|
@ -553,8 +552,7 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
|
|||
if (!lpi2c_imx)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
lpi2c_imx->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
lpi2c_imx->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(lpi2c_imx->base))
|
||||
return PTR_ERR(lpi2c_imx->base);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
|
@ -255,6 +256,12 @@ static const struct of_device_id i2c_imx_dt_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids);
|
||||
|
||||
static const struct acpi_device_id i2c_imx_acpi_ids[] = {
|
||||
{"NXP0001", .driver_data = (kernel_ulong_t)&vf610_i2c_hwdata},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, i2c_imx_acpi_ids);
|
||||
|
||||
static inline int is_imx1_i2c(struct imx_i2c_struct *i2c_imx)
|
||||
{
|
||||
return i2c_imx->hwdata->devtype == IMX1_I2C;
|
||||
|
@ -1048,14 +1055,13 @@ static const struct i2c_algorithm i2c_imx_algo = {
|
|||
|
||||
static int i2c_imx_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *of_id = of_match_device(i2c_imx_dt_ids,
|
||||
&pdev->dev);
|
||||
struct imx_i2c_struct *i2c_imx;
|
||||
struct resource *res;
|
||||
struct imxi2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
void __iomem *base;
|
||||
int irq, ret;
|
||||
dma_addr_t phy_addr;
|
||||
const struct imx_i2c_hwdata *match;
|
||||
|
||||
dev_dbg(&pdev->dev, "<%s>\n", __func__);
|
||||
|
||||
|
@ -1075,8 +1081,9 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
|||
if (!i2c_imx)
|
||||
return -ENOMEM;
|
||||
|
||||
if (of_id)
|
||||
i2c_imx->hwdata = of_id->data;
|
||||
match = device_get_match_data(&pdev->dev);
|
||||
if (match)
|
||||
i2c_imx->hwdata = match;
|
||||
else
|
||||
i2c_imx->hwdata = (struct imx_i2c_hwdata *)
|
||||
platform_get_device_id(pdev)->driver_data;
|
||||
|
@ -1089,6 +1096,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
|||
i2c_imx->adapter.nr = pdev->id;
|
||||
i2c_imx->adapter.dev.of_node = pdev->dev.of_node;
|
||||
i2c_imx->base = base;
|
||||
ACPI_COMPANION_SET(&i2c_imx->adapter.dev, ACPI_COMPANION(&pdev->dev));
|
||||
|
||||
/* Get I2C clock */
|
||||
i2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
|
@ -1247,6 +1255,7 @@ static struct platform_driver i2c_imx_driver = {
|
|||
.name = DRIVER_NAME,
|
||||
.pm = &i2c_imx_pm_ops,
|
||||
.of_match_table = i2c_imx_dt_ids,
|
||||
.acpi_match_table = i2c_imx_acpi_ids,
|
||||
},
|
||||
.id_table = imx_i2c_devtype,
|
||||
};
|
||||
|
|
|
@ -781,8 +781,6 @@ static int ismt_dev_init(struct ismt_priv *priv)
|
|||
if (!priv->hw)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(priv->hw, 0, (ISMT_DESC_ENTRIES * sizeof(struct ismt_desc)));
|
||||
|
||||
priv->head = 0;
|
||||
init_completion(&priv->cmp);
|
||||
|
||||
|
|
|
@ -802,7 +802,6 @@ static int mxs_i2c_probe(struct platform_device *pdev)
|
|||
struct device *dev = &pdev->dev;
|
||||
struct mxs_i2c_dev *i2c;
|
||||
struct i2c_adapter *adap;
|
||||
struct resource *res;
|
||||
int err, irq;
|
||||
|
||||
i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
|
||||
|
@ -814,8 +813,7 @@ static int mxs_i2c_probe(struct platform_device *pdev)
|
|||
i2c->dev_type = device_id->driver_data;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2c->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
i2c->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(i2c->regs))
|
||||
return PTR_ERR(i2c->regs);
|
||||
|
||||
|
|
|
@ -703,8 +703,9 @@ static int ocores_i2c_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
if (ocores_algorithm.master_xfer != ocores_xfer_polling) {
|
||||
ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0,
|
||||
pdev->name, i2c);
|
||||
ret = devm_request_any_context_irq(&pdev->dev, irq,
|
||||
ocores_isr, 0,
|
||||
pdev->name, i2c);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Cannot claim IRQ\n");
|
||||
goto err_clk;
|
||||
|
|
|
@ -72,7 +72,8 @@
|
|||
#define PIIX4_BLOCK_DATA 0x14
|
||||
|
||||
/* Multi-port constants */
|
||||
#define PIIX4_MAX_ADAPTERS 4
|
||||
#define PIIX4_MAX_ADAPTERS 4
|
||||
#define HUDSON2_MAIN_PORTS 2 /* HUDSON2, KERNCZ reserves ports 3, 4 */
|
||||
|
||||
/* SB800 constants */
|
||||
#define SB800_PIIX4_SMB_IDX 0xcd6
|
||||
|
@ -806,10 +807,12 @@ MODULE_DEVICE_TABLE (pci, piix4_ids);
|
|||
|
||||
static struct i2c_adapter *piix4_main_adapters[PIIX4_MAX_ADAPTERS];
|
||||
static struct i2c_adapter *piix4_aux_adapter;
|
||||
static int piix4_adapter_count;
|
||||
|
||||
static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
|
||||
bool sb800_main, u8 port, bool notify_imc,
|
||||
const char *name, struct i2c_adapter **padap)
|
||||
u8 hw_port_nr, const char *name,
|
||||
struct i2c_adapter **padap)
|
||||
{
|
||||
struct i2c_adapter *adap;
|
||||
struct i2c_piix4_adapdata *adapdata;
|
||||
|
@ -841,6 +844,12 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
|
|||
/* set up the sysfs linkage to our parent device */
|
||||
adap->dev.parent = &dev->dev;
|
||||
|
||||
if (has_acpi_companion(&dev->dev)) {
|
||||
acpi_preset_companion(&adap->dev,
|
||||
ACPI_COMPANION(&dev->dev),
|
||||
hw_port_nr);
|
||||
}
|
||||
|
||||
snprintf(adap->name, sizeof(adap->name),
|
||||
"SMBus PIIX4 adapter%s at %04x", name, smba);
|
||||
|
||||
|
@ -865,8 +874,19 @@ static int piix4_add_adapters_sb800(struct pci_dev *dev, unsigned short smba,
|
|||
int port;
|
||||
int retval;
|
||||
|
||||
for (port = 0; port < PIIX4_MAX_ADAPTERS; port++) {
|
||||
if (dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS ||
|
||||
(dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS &&
|
||||
dev->revision >= 0x1F)) {
|
||||
piix4_adapter_count = HUDSON2_MAIN_PORTS;
|
||||
} else {
|
||||
piix4_adapter_count = PIIX4_MAX_ADAPTERS;
|
||||
}
|
||||
|
||||
for (port = 0; port < piix4_adapter_count; port++) {
|
||||
u8 hw_port_nr = port == 0 ? 0 : port + 1;
|
||||
|
||||
retval = piix4_add_adapter(dev, smba, true, port, notify_imc,
|
||||
hw_port_nr,
|
||||
piix4_main_port_names_sb800[port],
|
||||
&piix4_main_adapters[port]);
|
||||
if (retval < 0)
|
||||
|
@ -937,8 +957,8 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||
return retval;
|
||||
|
||||
/* Try to register main SMBus adapter, give up if we can't */
|
||||
retval = piix4_add_adapter(dev, retval, false, 0, false, "",
|
||||
&piix4_main_adapters[0]);
|
||||
retval = piix4_add_adapter(dev, retval, false, 0, false, 0,
|
||||
"", &piix4_main_adapters[0]);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
}
|
||||
|
@ -964,7 +984,7 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||
if (retval > 0) {
|
||||
/* Try to add the aux adapter if it exists,
|
||||
* piix4_add_adapter will clean up if this fails */
|
||||
piix4_add_adapter(dev, retval, false, 0, false,
|
||||
piix4_add_adapter(dev, retval, false, 0, false, 1,
|
||||
is_sb800 ? piix4_aux_port_name_sb800 : "",
|
||||
&piix4_aux_adapter);
|
||||
}
|
||||
|
@ -987,7 +1007,7 @@ static void piix4_adap_remove(struct i2c_adapter *adap)
|
|||
|
||||
static void piix4_remove(struct pci_dev *dev)
|
||||
{
|
||||
int port = PIIX4_MAX_ADAPTERS;
|
||||
int port = piix4_adapter_count;
|
||||
|
||||
while (--port >= 0) {
|
||||
if (piix4_main_adapters[port]) {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
@ -465,9 +466,9 @@ static int sprd_i2c_clk_init(struct sprd_i2c *i2c_dev)
|
|||
|
||||
i2c_dev->clk = devm_clk_get(i2c_dev->dev, "enable");
|
||||
if (IS_ERR(i2c_dev->clk)) {
|
||||
dev_warn(i2c_dev->dev, "i2c%d can't get the enable clock\n",
|
||||
i2c_dev->adap.nr);
|
||||
i2c_dev->clk = NULL;
|
||||
dev_err(i2c_dev->dev, "i2c%d can't get the enable clock\n",
|
||||
i2c_dev->adap.nr);
|
||||
return PTR_ERR(i2c_dev->clk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -477,7 +478,6 @@ static int sprd_i2c_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct sprd_i2c *i2c_dev;
|
||||
struct resource *res;
|
||||
u32 prop;
|
||||
int ret;
|
||||
|
||||
|
@ -487,8 +487,7 @@ static int sprd_i2c_probe(struct platform_device *pdev)
|
|||
if (!i2c_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2c_dev->base = devm_ioremap_resource(dev, res);
|
||||
i2c_dev->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(i2c_dev->base))
|
||||
return PTR_ERR(i2c_dev->base);
|
||||
|
||||
|
@ -520,7 +519,10 @@ static int sprd_i2c_probe(struct platform_device *pdev)
|
|||
if (i2c_dev->bus_freq != 100000 && i2c_dev->bus_freq != 400000)
|
||||
return -EINVAL;
|
||||
|
||||
sprd_i2c_clk_init(i2c_dev);
|
||||
ret = sprd_i2c_clk_init(i2c_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, i2c_dev);
|
||||
|
||||
ret = clk_prepare_enable(i2c_dev->clk);
|
||||
|
@ -644,8 +646,7 @@ static struct platform_driver sprd_i2c_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
static int sprd_i2c_init(void)
|
||||
{
|
||||
return platform_driver_register(&sprd_i2c_driver);
|
||||
}
|
||||
arch_initcall_sync(sprd_i2c_init);
|
||||
module_platform_driver(sprd_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Spreadtrum I2C master controller driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -1809,7 +1809,7 @@ static u32 stm32f7_i2c_func(struct i2c_adapter *adap)
|
|||
I2C_FUNC_SMBUS_I2C_BLOCK;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm stm32f7_i2c_algo = {
|
||||
static const struct i2c_algorithm stm32f7_i2c_algo = {
|
||||
.master_xfer = stm32f7_i2c_xfer,
|
||||
.smbus_xfer = stm32f7_i2c_smbus_xfer,
|
||||
.functionality = stm32f7_i2c_func,
|
||||
|
|
|
@ -526,7 +526,7 @@ static const struct i2c_algorithm synquacer_i2c_algo = {
|
|||
.functionality = synquacer_i2c_functionality,
|
||||
};
|
||||
|
||||
static struct i2c_adapter synquacer_i2c_ops = {
|
||||
static const struct i2c_adapter synquacer_i2c_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "synquacer_i2c-adapter",
|
||||
.algo = &synquacer_i2c_algo,
|
||||
|
|
|
@ -39,7 +39,7 @@ struct taos_data {
|
|||
};
|
||||
|
||||
/* TAOS TSL2550 EVM */
|
||||
static struct i2c_board_info tsl2550_info = {
|
||||
static const struct i2c_board_info tsl2550_info = {
|
||||
I2C_BOARD_INFO("tsl2550", 0x39),
|
||||
};
|
||||
|
||||
|
|
|
@ -636,7 +636,7 @@ static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev)
|
|||
dvc_writel(i2c_dev, val, DVC_CTRL_REG1);
|
||||
}
|
||||
|
||||
static int tegra_i2c_runtime_resume(struct device *dev)
|
||||
static int __maybe_unused tegra_i2c_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
@ -665,7 +665,7 @@ static int tegra_i2c_runtime_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_i2c_runtime_suspend(struct device *dev)
|
||||
static int __maybe_unused tegra_i2c_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
|
||||
|
@ -713,12 +713,6 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
|
|||
u32 tsu_thd;
|
||||
u8 tlow, thigh;
|
||||
|
||||
err = pm_runtime_get_sync(i2c_dev->dev);
|
||||
if (err < 0) {
|
||||
dev_err(i2c_dev->dev, "runtime resume failed %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
reset_control_assert(i2c_dev->rst);
|
||||
udelay(2);
|
||||
reset_control_deassert(i2c_dev->rst);
|
||||
|
@ -772,7 +766,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
|
|||
if (err) {
|
||||
dev_err(i2c_dev->dev,
|
||||
"failed changing clock rate: %d\n", err);
|
||||
goto err;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -787,23 +781,21 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
|
|||
|
||||
err = tegra_i2c_flush_fifos(i2c_dev);
|
||||
if (err)
|
||||
goto err;
|
||||
return err;
|
||||
|
||||
if (i2c_dev->is_multimaster_mode && i2c_dev->hw->has_slcg_override_reg)
|
||||
i2c_writel(i2c_dev, I2C_MST_CORE_CLKEN_OVR, I2C_CLKEN_OVERRIDE);
|
||||
|
||||
err = tegra_i2c_wait_for_config_load(i2c_dev);
|
||||
if (err)
|
||||
goto err;
|
||||
return err;
|
||||
|
||||
if (i2c_dev->irq_disabled) {
|
||||
i2c_dev->irq_disabled = false;
|
||||
enable_irq(i2c_dev->irq);
|
||||
}
|
||||
|
||||
err:
|
||||
pm_runtime_put(i2c_dev->dev);
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_i2c_disable_packet_mode(struct tegra_i2c_dev *i2c_dev)
|
||||
|
@ -1616,12 +1608,14 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
if (!pm_runtime_enabled(&pdev->dev)) {
|
||||
if (!pm_runtime_enabled(&pdev->dev))
|
||||
ret = tegra_i2c_runtime_resume(&pdev->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "runtime resume failed\n");
|
||||
goto unprepare_div_clk;
|
||||
}
|
||||
else
|
||||
ret = pm_runtime_get_sync(i2c_dev->dev);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "runtime resume failed\n");
|
||||
goto unprepare_div_clk;
|
||||
}
|
||||
|
||||
if (i2c_dev->is_multimaster_mode) {
|
||||
|
@ -1666,6 +1660,8 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto release_dma;
|
||||
|
||||
pm_runtime_put(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
release_dma:
|
||||
|
@ -1711,8 +1707,7 @@ static int tegra_i2c_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int tegra_i2c_suspend(struct device *dev)
|
||||
static int __maybe_unused tegra_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
|
||||
|
@ -1721,38 +1716,41 @@ static int tegra_i2c_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_i2c_resume(struct device *dev)
|
||||
static int __maybe_unused tegra_i2c_resume(struct device *dev)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
int err;
|
||||
|
||||
err = tegra_i2c_runtime_resume(dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = tegra_i2c_init(i2c_dev, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = tegra_i2c_runtime_suspend(dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
i2c_mark_adapter_resumed(&i2c_dev->adapter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops tegra_i2c_pm = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume)
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume)
|
||||
SET_RUNTIME_PM_OPS(tegra_i2c_runtime_suspend, tegra_i2c_runtime_resume,
|
||||
NULL)
|
||||
};
|
||||
|
||||
#define TEGRA_I2C_PM (&tegra_i2c_pm)
|
||||
#else
|
||||
#define TEGRA_I2C_PM NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver tegra_i2c_driver = {
|
||||
.probe = tegra_i2c_probe,
|
||||
.remove = tegra_i2c_remove,
|
||||
.driver = {
|
||||
.name = "tegra-i2c",
|
||||
.of_match_table = tegra_i2c_of_match,
|
||||
.pm = TEGRA_I2C_PM,
|
||||
.pm = &tegra_i2c_pm,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -108,7 +108,6 @@ static void uniphier_fi2c_fill_txfifo(struct uniphier_fi2c_priv *priv,
|
|||
if (fifo_space-- <= 0)
|
||||
break;
|
||||
|
||||
dev_dbg(&priv->adap.dev, "write data: %02x\n", *priv->buf);
|
||||
writel(*priv->buf++, priv->membase + UNIPHIER_FI2C_DTTX);
|
||||
priv->len--;
|
||||
}
|
||||
|
@ -124,7 +123,6 @@ static void uniphier_fi2c_drain_rxfifo(struct uniphier_fi2c_priv *priv)
|
|||
break;
|
||||
|
||||
*priv->buf++ = readl(priv->membase + UNIPHIER_FI2C_DTRX);
|
||||
dev_dbg(&priv->adap.dev, "read data: %02x\n", priv->buf[-1]);
|
||||
priv->len--;
|
||||
}
|
||||
}
|
||||
|
@ -142,8 +140,6 @@ static void uniphier_fi2c_clear_irqs(struct uniphier_fi2c_priv *priv,
|
|||
|
||||
static void uniphier_fi2c_stop(struct uniphier_fi2c_priv *priv)
|
||||
{
|
||||
dev_dbg(&priv->adap.dev, "stop condition\n");
|
||||
|
||||
priv->enabled_irqs |= UNIPHIER_FI2C_INT_STOP;
|
||||
uniphier_fi2c_set_irqs(priv);
|
||||
writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STO,
|
||||
|
@ -160,21 +156,15 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)
|
|||
irq_status = readl(priv->membase + UNIPHIER_FI2C_INT);
|
||||
irq_status &= priv->enabled_irqs;
|
||||
|
||||
dev_dbg(&priv->adap.dev,
|
||||
"interrupt: enabled_irqs=%04x, irq_status=%04x\n",
|
||||
priv->enabled_irqs, irq_status);
|
||||
|
||||
if (irq_status & UNIPHIER_FI2C_INT_STOP)
|
||||
goto complete;
|
||||
|
||||
if (unlikely(irq_status & UNIPHIER_FI2C_INT_AL)) {
|
||||
dev_dbg(&priv->adap.dev, "arbitration lost\n");
|
||||
priv->error = -EAGAIN;
|
||||
goto complete;
|
||||
}
|
||||
|
||||
if (unlikely(irq_status & UNIPHIER_FI2C_INT_NA)) {
|
||||
dev_dbg(&priv->adap.dev, "could not get ACK\n");
|
||||
priv->error = -ENXIO;
|
||||
if (priv->flags & UNIPHIER_FI2C_RD) {
|
||||
/*
|
||||
|
@ -215,18 +205,14 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)
|
|||
if (unlikely(priv->flags & UNIPHIER_FI2C_MANUAL_NACK)) {
|
||||
if (priv->len <= UNIPHIER_FI2C_FIFO_SIZE &&
|
||||
!(priv->flags & UNIPHIER_FI2C_BYTE_WISE)) {
|
||||
dev_dbg(&priv->adap.dev,
|
||||
"enable read byte count IRQ\n");
|
||||
priv->enabled_irqs |= UNIPHIER_FI2C_INT_RB;
|
||||
uniphier_fi2c_set_irqs(priv);
|
||||
priv->flags |= UNIPHIER_FI2C_BYTE_WISE;
|
||||
}
|
||||
if (priv->len <= 1) {
|
||||
dev_dbg(&priv->adap.dev, "set NACK\n");
|
||||
if (priv->len <= 1)
|
||||
writel(UNIPHIER_FI2C_CR_MST |
|
||||
UNIPHIER_FI2C_CR_NACK,
|
||||
priv->membase + UNIPHIER_FI2C_CR);
|
||||
}
|
||||
}
|
||||
|
||||
goto handled;
|
||||
|
@ -334,10 +320,6 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
|
|||
bool is_read = msg->flags & I2C_M_RD;
|
||||
unsigned long time_left, flags;
|
||||
|
||||
dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, repeat=%d, stop=%d\n",
|
||||
is_read ? "receive" : "transmit", msg->addr, msg->len,
|
||||
repeat, stop);
|
||||
|
||||
priv->len = msg->len;
|
||||
priv->buf = msg->buf;
|
||||
priv->enabled_irqs = UNIPHIER_FI2C_INT_FAULTS;
|
||||
|
@ -359,7 +341,6 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
|
|||
else
|
||||
uniphier_fi2c_tx_init(priv, msg->addr, repeat);
|
||||
|
||||
dev_dbg(&adap->dev, "start condition\n");
|
||||
/*
|
||||
* For a repeated START condition, writing a slave address to the FIFO
|
||||
* kicks the controller. So, the UNIPHIER_FI2C_CR register should be
|
||||
|
@ -383,7 +364,6 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
|
|||
uniphier_fi2c_recover(priv);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
dev_dbg(&adap->dev, "complete\n");
|
||||
|
||||
if (unlikely(priv->flags & UNIPHIER_FI2C_DEFER_STOP_COMP)) {
|
||||
u32 status;
|
||||
|
@ -538,7 +518,6 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct uniphier_fi2c_priv *priv;
|
||||
struct resource *regs;
|
||||
u32 bus_speed;
|
||||
unsigned long clk_rate;
|
||||
int irq, ret;
|
||||
|
@ -547,8 +526,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
|
|||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->membase = devm_ioremap_resource(dev, regs);
|
||||
priv->membase = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->membase))
|
||||
return PTR_ERR(priv->membase);
|
||||
|
||||
|
|
|
@ -71,7 +71,6 @@ static int uniphier_i2c_xfer_byte(struct i2c_adapter *adap, u32 txdata,
|
|||
reinit_completion(&priv->comp);
|
||||
|
||||
txdata |= UNIPHIER_I2C_DTRM_IRQEN;
|
||||
dev_dbg(&adap->dev, "write data: 0x%04x\n", txdata);
|
||||
writel(txdata, priv->membase + UNIPHIER_I2C_DTRM);
|
||||
|
||||
time_left = wait_for_completion_timeout(&priv->comp, adap->timeout);
|
||||
|
@ -81,8 +80,6 @@ static int uniphier_i2c_xfer_byte(struct i2c_adapter *adap, u32 txdata,
|
|||
}
|
||||
|
||||
rxdata = readl(priv->membase + UNIPHIER_I2C_DREC);
|
||||
dev_dbg(&adap->dev, "read data: 0x%04x\n", rxdata);
|
||||
|
||||
if (rxdatap)
|
||||
*rxdatap = rxdata;
|
||||
|
||||
|
@ -98,14 +95,11 @@ static int uniphier_i2c_send_byte(struct i2c_adapter *adap, u32 txdata)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (unlikely(rxdata & UNIPHIER_I2C_DREC_LAB)) {
|
||||
dev_dbg(&adap->dev, "arbitration lost\n");
|
||||
if (unlikely(rxdata & UNIPHIER_I2C_DREC_LAB))
|
||||
return -EAGAIN;
|
||||
}
|
||||
if (unlikely(rxdata & UNIPHIER_I2C_DREC_LRB)) {
|
||||
dev_dbg(&adap->dev, "could not get ACK\n");
|
||||
|
||||
if (unlikely(rxdata & UNIPHIER_I2C_DREC_LRB))
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -115,7 +109,6 @@ static int uniphier_i2c_tx(struct i2c_adapter *adap, u16 addr, u16 len,
|
|||
{
|
||||
int ret;
|
||||
|
||||
dev_dbg(&adap->dev, "start condition\n");
|
||||
ret = uniphier_i2c_send_byte(adap, addr << 1 |
|
||||
UNIPHIER_I2C_DTRM_STA |
|
||||
UNIPHIER_I2C_DTRM_NACK);
|
||||
|
@ -137,7 +130,6 @@ static int uniphier_i2c_rx(struct i2c_adapter *adap, u16 addr, u16 len,
|
|||
{
|
||||
int ret;
|
||||
|
||||
dev_dbg(&adap->dev, "start condition\n");
|
||||
ret = uniphier_i2c_send_byte(adap, addr << 1 |
|
||||
UNIPHIER_I2C_DTRM_STA |
|
||||
UNIPHIER_I2C_DTRM_NACK |
|
||||
|
@ -161,7 +153,6 @@ static int uniphier_i2c_rx(struct i2c_adapter *adap, u16 addr, u16 len,
|
|||
|
||||
static int uniphier_i2c_stop(struct i2c_adapter *adap)
|
||||
{
|
||||
dev_dbg(&adap->dev, "stop condition\n");
|
||||
return uniphier_i2c_send_byte(adap, UNIPHIER_I2C_DTRM_STO |
|
||||
UNIPHIER_I2C_DTRM_NACK);
|
||||
}
|
||||
|
@ -173,9 +164,6 @@ static int uniphier_i2c_master_xfer_one(struct i2c_adapter *adap,
|
|||
bool recovery = false;
|
||||
int ret;
|
||||
|
||||
dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n",
|
||||
is_read ? "receive" : "transmit", msg->addr, msg->len, stop);
|
||||
|
||||
if (is_read)
|
||||
ret = uniphier_i2c_rx(adap, msg->addr, msg->len, msg->buf);
|
||||
else
|
||||
|
@ -326,7 +314,6 @@ static int uniphier_i2c_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct uniphier_i2c_priv *priv;
|
||||
struct resource *regs;
|
||||
u32 bus_speed;
|
||||
unsigned long clk_rate;
|
||||
int irq, ret;
|
||||
|
@ -335,8 +322,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev)
|
|||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->membase = devm_ioremap_resource(dev, regs);
|
||||
priv->membase = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->membase))
|
||||
return PTR_ERR(priv->membase);
|
||||
|
||||
|
|
|
@ -350,13 +350,11 @@ static int i2c_device_probe(struct device *dev)
|
|||
return -ENODEV;
|
||||
|
||||
if (client->flags & I2C_CLIENT_WAKE) {
|
||||
int wakeirq = -ENOENT;
|
||||
int wakeirq;
|
||||
|
||||
if (dev->of_node) {
|
||||
wakeirq = of_irq_get_byname(dev->of_node, "wakeup");
|
||||
if (wakeirq == -EPROBE_DEFER)
|
||||
return wakeirq;
|
||||
}
|
||||
wakeirq = of_irq_get_byname(dev->of_node, "wakeup");
|
||||
if (wakeirq == -EPROBE_DEFER)
|
||||
return wakeirq;
|
||||
|
||||
device_init_wakeup(&client->dev, true);
|
||||
|
||||
|
@ -966,7 +964,7 @@ struct i2c_client *devm_i2c_new_dummy_device(struct device *dev,
|
|||
EXPORT_SYMBOL_GPL(devm_i2c_new_dummy_device);
|
||||
|
||||
/**
|
||||
* i2c_new_secondary_device - Helper to get the instantiated secondary address
|
||||
* i2c_new_ancillary_device - Helper to get the instantiated secondary address
|
||||
* and create the associated device
|
||||
* @client: Handle to the primary client
|
||||
* @name: Handle to specify which secondary address to get
|
||||
|
@ -985,9 +983,9 @@ EXPORT_SYMBOL_GPL(devm_i2c_new_dummy_device);
|
|||
* cell whose "reg-names" value matches the slave name.
|
||||
*
|
||||
* This returns the new i2c client, which should be saved for later use with
|
||||
* i2c_unregister_device(); or NULL to indicate an error.
|
||||
* i2c_unregister_device(); or an ERR_PTR to describe the error.
|
||||
*/
|
||||
struct i2c_client *i2c_new_secondary_device(struct i2c_client *client,
|
||||
struct i2c_client *i2c_new_ancillary_device(struct i2c_client *client,
|
||||
const char *name,
|
||||
u16 default_addr)
|
||||
{
|
||||
|
@ -1002,9 +1000,9 @@ struct i2c_client *i2c_new_secondary_device(struct i2c_client *client,
|
|||
}
|
||||
|
||||
dev_dbg(&client->adapter->dev, "Address for %s : 0x%x\n", name, addr);
|
||||
return i2c_new_dummy(client->adapter, addr);
|
||||
return i2c_new_dummy_device(client->adapter, addr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_new_secondary_device);
|
||||
EXPORT_SYMBOL_GPL(i2c_new_ancillary_device);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
|
|
|
@ -11,6 +11,13 @@
|
|||
* pointer, yet implementation is deferred until the need actually arises.
|
||||
*/
|
||||
|
||||
/*
|
||||
* FIXME: What to do if only 8 bits of a 16 bit address are sent?
|
||||
* The ST-M24C64 sends only 0xff then. Needs verification with other
|
||||
* EEPROMs, though. We currently use the 8 bit as a valid address.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -21,12 +28,18 @@
|
|||
|
||||
struct eeprom_data {
|
||||
struct bin_attribute bin;
|
||||
bool first_write;
|
||||
spinlock_t buffer_lock;
|
||||
u8 buffer_idx;
|
||||
u16 buffer_idx;
|
||||
u16 address_mask;
|
||||
u8 num_address_bytes;
|
||||
u8 idx_write_cnt;
|
||||
u8 buffer[];
|
||||
};
|
||||
|
||||
#define I2C_SLAVE_BYTELEN GENMASK(15, 0)
|
||||
#define I2C_SLAVE_FLAG_ADDR16 BIT(16)
|
||||
#define I2C_SLAVE_DEVICE_MAGIC(_len, _flags) ((_flags) | (_len))
|
||||
|
||||
static int i2c_slave_eeprom_slave_cb(struct i2c_client *client,
|
||||
enum i2c_slave_event event, u8 *val)
|
||||
{
|
||||
|
@ -34,12 +47,14 @@ static int i2c_slave_eeprom_slave_cb(struct i2c_client *client,
|
|||
|
||||
switch (event) {
|
||||
case I2C_SLAVE_WRITE_RECEIVED:
|
||||
if (eeprom->first_write) {
|
||||
eeprom->buffer_idx = *val;
|
||||
eeprom->first_write = false;
|
||||
if (eeprom->idx_write_cnt < eeprom->num_address_bytes) {
|
||||
if (eeprom->idx_write_cnt == 0)
|
||||
eeprom->buffer_idx = 0;
|
||||
eeprom->buffer_idx = *val | (eeprom->buffer_idx << 8);
|
||||
eeprom->idx_write_cnt++;
|
||||
} else {
|
||||
spin_lock(&eeprom->buffer_lock);
|
||||
eeprom->buffer[eeprom->buffer_idx++] = *val;
|
||||
eeprom->buffer[eeprom->buffer_idx++ & eeprom->address_mask] = *val;
|
||||
spin_unlock(&eeprom->buffer_lock);
|
||||
}
|
||||
break;
|
||||
|
@ -50,7 +65,7 @@ static int i2c_slave_eeprom_slave_cb(struct i2c_client *client,
|
|||
/* fallthrough */
|
||||
case I2C_SLAVE_READ_REQUESTED:
|
||||
spin_lock(&eeprom->buffer_lock);
|
||||
*val = eeprom->buffer[eeprom->buffer_idx];
|
||||
*val = eeprom->buffer[eeprom->buffer_idx & eeprom->address_mask];
|
||||
spin_unlock(&eeprom->buffer_lock);
|
||||
/*
|
||||
* Do not increment buffer_idx here, because we don't know if
|
||||
|
@ -61,7 +76,7 @@ static int i2c_slave_eeprom_slave_cb(struct i2c_client *client,
|
|||
|
||||
case I2C_SLAVE_STOP:
|
||||
case I2C_SLAVE_WRITE_REQUESTED:
|
||||
eeprom->first_write = true;
|
||||
eeprom->idx_write_cnt = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -105,13 +120,16 @@ static int i2c_slave_eeprom_probe(struct i2c_client *client, const struct i2c_de
|
|||
{
|
||||
struct eeprom_data *eeprom;
|
||||
int ret;
|
||||
unsigned size = id->driver_data;
|
||||
unsigned int size = FIELD_GET(I2C_SLAVE_BYTELEN, id->driver_data);
|
||||
unsigned int flag_addr16 = FIELD_GET(I2C_SLAVE_FLAG_ADDR16, id->driver_data);
|
||||
|
||||
eeprom = devm_kzalloc(&client->dev, sizeof(struct eeprom_data) + size, GFP_KERNEL);
|
||||
if (!eeprom)
|
||||
return -ENOMEM;
|
||||
|
||||
eeprom->first_write = true;
|
||||
eeprom->idx_write_cnt = 0;
|
||||
eeprom->num_address_bytes = flag_addr16 ? 2 : 1;
|
||||
eeprom->address_mask = size - 1;
|
||||
spin_lock_init(&eeprom->buffer_lock);
|
||||
i2c_set_clientdata(client, eeprom);
|
||||
|
||||
|
@ -146,7 +164,9 @@ static int i2c_slave_eeprom_remove(struct i2c_client *client)
|
|||
}
|
||||
|
||||
static const struct i2c_device_id i2c_slave_eeprom_id[] = {
|
||||
{ "slave-24c02", 2048 / 8 },
|
||||
{ "slave-24c02", I2C_SLAVE_DEVICE_MAGIC(2048 / 8, 0) },
|
||||
{ "slave-24c32", I2C_SLAVE_DEVICE_MAGIC(32768 / 8, I2C_SLAVE_FLAG_ADDR16) },
|
||||
{ "slave-24c64", I2C_SLAVE_DEVICE_MAGIC(65536 / 8, I2C_SLAVE_FLAG_ADDR16) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, i2c_slave_eeprom_id);
|
||||
|
|
|
@ -183,14 +183,14 @@ static int adv748x_initialise_clients(struct adv748x_state *state)
|
|||
int ret;
|
||||
|
||||
for (i = ADV748X_PAGE_DPLL; i < ADV748X_PAGE_MAX; ++i) {
|
||||
state->i2c_clients[i] = i2c_new_secondary_device(
|
||||
state->i2c_clients[i] = i2c_new_ancillary_device(
|
||||
state->client,
|
||||
adv748x_default_addresses[i].name,
|
||||
adv748x_default_addresses[i].default_addr);
|
||||
|
||||
if (state->i2c_clients[i] == NULL) {
|
||||
if (IS_ERR(state->i2c_clients[i])) {
|
||||
adv_err(state, "failed to create i2c client %u\n", i);
|
||||
return -ENOMEM;
|
||||
return PTR_ERR(state->i2c_clients[i]);
|
||||
}
|
||||
|
||||
ret = adv748x_configure_regmap(state, i);
|
||||
|
|
|
@ -2862,10 +2862,8 @@ static void adv76xx_unregister_clients(struct adv76xx_state *state)
|
|||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 1; i < ARRAY_SIZE(state->i2c_clients); ++i) {
|
||||
if (state->i2c_clients[i])
|
||||
i2c_unregister_device(state->i2c_clients[i]);
|
||||
}
|
||||
for (i = 1; i < ARRAY_SIZE(state->i2c_clients); ++i)
|
||||
i2c_unregister_device(state->i2c_clients[i]);
|
||||
}
|
||||
|
||||
static struct i2c_client *adv76xx_dummy_client(struct v4l2_subdev *sd,
|
||||
|
@ -2878,14 +2876,14 @@ static struct i2c_client *adv76xx_dummy_client(struct v4l2_subdev *sd,
|
|||
struct i2c_client *new_client;
|
||||
|
||||
if (pdata && pdata->i2c_addresses[page])
|
||||
new_client = i2c_new_dummy(client->adapter,
|
||||
new_client = i2c_new_dummy_device(client->adapter,
|
||||
pdata->i2c_addresses[page]);
|
||||
else
|
||||
new_client = i2c_new_secondary_device(client,
|
||||
new_client = i2c_new_ancillary_device(client,
|
||||
adv76xx_default_addresses[page].name,
|
||||
adv76xx_default_addresses[page].default_addr);
|
||||
|
||||
if (new_client)
|
||||
if (!IS_ERR(new_client))
|
||||
io_write(sd, io_reg, new_client->addr << 1);
|
||||
|
||||
return new_client;
|
||||
|
@ -3516,15 +3514,19 @@ static int adv76xx_probe(struct i2c_client *client,
|
|||
}
|
||||
|
||||
for (i = 1; i < ADV76XX_PAGE_MAX; ++i) {
|
||||
struct i2c_client *dummy_client;
|
||||
|
||||
if (!(BIT(i) & state->info->page_mask))
|
||||
continue;
|
||||
|
||||
state->i2c_clients[i] = adv76xx_dummy_client(sd, i);
|
||||
if (!state->i2c_clients[i]) {
|
||||
err = -EINVAL;
|
||||
dummy_client = adv76xx_dummy_client(sd, i);
|
||||
if (IS_ERR(dummy_client)) {
|
||||
err = PTR_ERR(dummy_client);
|
||||
v4l2_err(sd, "failed to create i2c client %u\n", i);
|
||||
goto err_i2c;
|
||||
}
|
||||
|
||||
state->i2c_clients[i] = dummy_client;
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug,
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/property.h>
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
|
||||
/* Includes */
|
||||
#include <linux/acpi.h> /* For ACPI support */
|
||||
#include <linux/bits.h> /* For BIT() */
|
||||
#include <linux/module.h> /* For module specific items */
|
||||
#include <linux/moduleparam.h> /* For new moduleparam's */
|
||||
#include <linux/types.h> /* For standard types (like size_t) */
|
||||
|
@ -215,6 +216,23 @@ static int update_no_reboot_bit_mem(void *priv, bool set)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int update_no_reboot_bit_cnt(void *priv, bool set)
|
||||
{
|
||||
struct iTCO_wdt_private *p = priv;
|
||||
u16 val, newval;
|
||||
|
||||
val = inw(TCO1_CNT(p));
|
||||
if (set)
|
||||
val |= BIT(0);
|
||||
else
|
||||
val &= ~BIT(0);
|
||||
outw(val, TCO1_CNT(p));
|
||||
newval = inw(TCO1_CNT(p));
|
||||
|
||||
/* make sure the update is successful */
|
||||
return val != newval ? -EIO : 0;
|
||||
}
|
||||
|
||||
static void iTCO_wdt_no_reboot_bit_setup(struct iTCO_wdt_private *p,
|
||||
struct itco_wdt_platform_data *pdata)
|
||||
{
|
||||
|
@ -224,7 +242,9 @@ static void iTCO_wdt_no_reboot_bit_setup(struct iTCO_wdt_private *p,
|
|||
return;
|
||||
}
|
||||
|
||||
if (p->iTCO_version >= 2)
|
||||
if (p->iTCO_version >= 6)
|
||||
p->update_no_reboot_bit = update_no_reboot_bit_cnt;
|
||||
else if (p->iTCO_version >= 2)
|
||||
p->update_no_reboot_bit = update_no_reboot_bit_mem;
|
||||
else if (p->iTCO_version == 1)
|
||||
p->update_no_reboot_bit = update_no_reboot_bit_pci;
|
||||
|
@ -452,7 +472,8 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
|
|||
* Get the Memory-Mapped GCS or PMC register, we need it for the
|
||||
* NO_REBOOT flag (TCO v2 and v3).
|
||||
*/
|
||||
if (p->iTCO_version >= 2 && !pdata->update_no_reboot_bit) {
|
||||
if (p->iTCO_version >= 2 && p->iTCO_version < 6 &&
|
||||
!pdata->update_no_reboot_bit) {
|
||||
p->gcs_pmc_res = platform_get_resource(pdev,
|
||||
IORESOURCE_MEM,
|
||||
ICH_RES_MEM_GCS_PMC);
|
||||
|
@ -502,6 +523,7 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
|
|||
|
||||
/* Clear out the (probably old) status */
|
||||
switch (p->iTCO_version) {
|
||||
case 6:
|
||||
case 5:
|
||||
case 4:
|
||||
outw(0x0008, TCO1_STS(p)); /* Clear the Time Out Status bit */
|
||||
|
|
|
@ -473,7 +473,7 @@ extern struct i2c_client *
|
|||
devm_i2c_new_dummy_device(struct device *dev, struct i2c_adapter *adap, u16 address);
|
||||
|
||||
extern struct i2c_client *
|
||||
i2c_new_secondary_device(struct i2c_client *client,
|
||||
i2c_new_ancillary_device(struct i2c_client *client,
|
||||
const char *name,
|
||||
u16 default_addr);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче