Merge branch 'i2c/for-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: "Highlights: - class based instantiation finally dropped for most embedded drivers bringing boot up performance gains - removed two drivers (one outdated, one a duplicate) - ACPI has now operation region support (thanks to Lan Tianyu) - the i2c-stub driver got overhauled and gained new features to become more useful when writing i2c client drivers (thanks to Guenter Roeck and Jean Delvare) The rest is driver bugfixes, added bindings/ids, cleanups..." * 'i2c/for-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (43 commits) i2c: mpc: delete unneeded test before of_node_put i2c: rk3x: fix interrupt handling issue i2c: imx: Fix format warning for dev_dbg i2c: qup: disable clks and return instead of just returning error i2c: exynos5: always enable HSI2C i2c: designware: add new bindings i2c: gpio: Drop dead code in i2c_gpio_remove i2c: pca954x: put the mux to disconnected state after resume i2c: st: Update i2c timings drivers/i2c/busses: use correct type for dma_map/unmap i2c: i2c-st: Use %pa to print 'resource_size_t' type i2c: s3c2410: resume the I2C controller earlier i2c: stub: Avoid an array overrun on I2C block transfers i2c: i801: Add device ID for Intel Wildcat Point PCH i2c: i801: Fix the alignment of the device table i2c: stub: Add support for banked register ranges i2c: stub: Remember the number of emulated chips i2c: stub: Add support for SMBus block commands i2c: efm32: correct namespacing of location property i2c: exynos5: remove extra line and fix an assignment ...
This commit is contained in:
commit
f7dbaef505
@ -10,7 +10,7 @@ Required properties :
|
||||
Recommended properties :
|
||||
|
||||
- clock-frequency : maximal I2C bus clock frequency in Hz.
|
||||
- efm32,location : Decides the location of the USART I/O pins.
|
||||
- energymicro,location : Decides the location of the USART I/O pins.
|
||||
Allowed range : [0 .. 6]
|
||||
|
||||
Example:
|
||||
@ -23,7 +23,7 @@ Example:
|
||||
clocks = <&cmu clk_HFPERCLKI2C0>;
|
||||
clock-frequency = <100000>;
|
||||
status = "ok";
|
||||
efm32,location = <3>;
|
||||
energymicro,location = <3>;
|
||||
|
||||
eeprom@50 {
|
||||
compatible = "microchip,24c02";
|
||||
|
@ -25,6 +25,7 @@ Supported adapters:
|
||||
* Intel Avoton (SOC)
|
||||
* Intel Wellsburg (PCH)
|
||||
* Intel Coleto Creek (PCH)
|
||||
* Intel Wildcat Point (PCH)
|
||||
* Intel Wildcat Point-LP (PCH)
|
||||
* Intel BayTrail (SOC)
|
||||
Datasheets: Publicly available at the Intel website
|
||||
|
@ -2,9 +2,9 @@ MODULE: i2c-stub
|
||||
|
||||
DESCRIPTION:
|
||||
|
||||
This module is a very simple fake I2C/SMBus driver. It implements five
|
||||
This module is a very simple fake I2C/SMBus driver. It implements six
|
||||
types of SMBus commands: write quick, (r/w) byte, (r/w) byte data, (r/w)
|
||||
word data, and (r/w) I2C block data.
|
||||
word data, (r/w) I2C block data, and (r/w) SMBus block data.
|
||||
|
||||
You need to provide chip addresses as a module parameter when loading this
|
||||
driver, which will then only react to SMBus commands to these addresses.
|
||||
@ -19,6 +19,14 @@ A pointer register with auto-increment is implemented for all byte
|
||||
operations. This allows for continuous byte reads like those supported by
|
||||
EEPROMs, among others.
|
||||
|
||||
SMBus block command support is disabled by default, and must be enabled
|
||||
explicitly by setting the respective bits (0x03000000) in the functionality
|
||||
module parameter.
|
||||
|
||||
SMBus block commands must be written to configure an SMBus command for
|
||||
SMBus block operations. Writes can be partial. Block read commands always
|
||||
return the number of bytes selected with the largest write so far.
|
||||
|
||||
The typical use-case is like this:
|
||||
1. load this module
|
||||
2. use i2cset (from the i2c-tools project) to pre-load some data
|
||||
@ -39,15 +47,18 @@ unsigned long functionality:
|
||||
value 0x1f0000 would only enable the quick, byte and byte data
|
||||
commands.
|
||||
|
||||
u8 bank_reg[10]
|
||||
u8 bank_mask[10]
|
||||
u8 bank_start[10]
|
||||
u8 bank_end[10]:
|
||||
Optional bank settings. They tell which bits in which register
|
||||
select the active bank, as well as the range of banked registers.
|
||||
|
||||
CAVEATS:
|
||||
|
||||
If your target driver polls some byte or word waiting for it to change, the
|
||||
stub could lock it up. Use i2cset to unlock it.
|
||||
|
||||
If the hardware for your driver has banked registers (e.g. Winbond sensors
|
||||
chips) this module will not work well - although it could be extended to
|
||||
support that pretty easily.
|
||||
|
||||
If you spam it hard enough, printk can be lossy. This module really wants
|
||||
something like relayfs.
|
||||
|
||||
|
@ -2,7 +2,9 @@
|
||||
# I2C subsystem configuration
|
||||
#
|
||||
|
||||
menuconfig I2C
|
||||
menu "I2C support"
|
||||
|
||||
config I2C
|
||||
tristate "I2C support"
|
||||
select RT_MUTEXES
|
||||
---help---
|
||||
@ -21,6 +23,18 @@ menuconfig I2C
|
||||
This I2C support can also be built as a module. If so, the module
|
||||
will be called i2c-core.
|
||||
|
||||
config I2C_ACPI
|
||||
bool "I2C ACPI support"
|
||||
select I2C
|
||||
depends on ACPI
|
||||
default y
|
||||
help
|
||||
Say Y here if you want to enable ACPI I2C support. This includes support
|
||||
for automatic enumeration of I2C slave devices and support for ACPI I2C
|
||||
Operation Regions. Operation Regions allow firmware (BIOS) code to
|
||||
access I2C slave devices, such as smart batteries through an I2C host
|
||||
controller driver.
|
||||
|
||||
if I2C
|
||||
|
||||
config I2C_BOARDINFO
|
||||
@ -124,3 +138,5 @@ config I2C_DEBUG_BUS
|
||||
on.
|
||||
|
||||
endif # I2C
|
||||
|
||||
endmenu
|
||||
|
@ -2,8 +2,11 @@
|
||||
# Makefile for the i2c core.
|
||||
#
|
||||
|
||||
i2ccore-y := i2c-core.o
|
||||
i2ccore-$(CONFIG_I2C_ACPI) += i2c-acpi.o
|
||||
|
||||
obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o
|
||||
obj-$(CONFIG_I2C) += i2c-core.o
|
||||
obj-$(CONFIG_I2C) += i2ccore.o
|
||||
obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o
|
||||
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
|
||||
obj-$(CONFIG_I2C_MUX) += i2c-mux.o
|
||||
|
@ -109,6 +109,7 @@ config I2C_I801
|
||||
Avoton (SOC)
|
||||
Wellsburg (PCH)
|
||||
Coleto Creek (PCH)
|
||||
Wildcat Point (PCH)
|
||||
Wildcat Point-LP (PCH)
|
||||
BayTrail (SOC)
|
||||
|
||||
@ -465,9 +466,9 @@ config I2C_EG20T
|
||||
config I2C_EXYNOS5
|
||||
tristate "Exynos5 high-speed I2C driver"
|
||||
depends on ARCH_EXYNOS5 && OF
|
||||
default y
|
||||
help
|
||||
Say Y here to include support for high-speed I2C controller in the
|
||||
Exynos5 based Samsung SoCs.
|
||||
High-speed I2C controller on Exynos5 based Samsung SoCs.
|
||||
|
||||
config I2C_GPIO
|
||||
tristate "GPIO-based bitbanging I2C"
|
||||
@ -700,16 +701,6 @@ config I2C_S3C2410
|
||||
Say Y here to include support for I2C controller in the
|
||||
Samsung SoCs.
|
||||
|
||||
config I2C_S6000
|
||||
tristate "S6000 I2C support"
|
||||
depends on XTENSA_VARIANT_S6000
|
||||
help
|
||||
This driver supports the on chip I2C device on the
|
||||
S6000 xtensa processor family.
|
||||
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called i2c-s6000.
|
||||
|
||||
config I2C_SH7760
|
||||
tristate "Renesas SH7760 I2C Controller"
|
||||
depends on CPU_SUBTYPE_SH7760
|
||||
@ -1018,37 +1009,6 @@ config I2C_CROS_EC_TUNNEL
|
||||
connected there. This will work whatever the interface used to
|
||||
talk to the EC (SPI, I2C or LPC).
|
||||
|
||||
config SCx200_I2C
|
||||
tristate "NatSemi SCx200 I2C using GPIO pins (DEPRECATED)"
|
||||
depends on SCx200_GPIO
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
Enable the use of two GPIO pins of a SCx200 processor as an I2C bus.
|
||||
|
||||
If you don't know what to do here, say N.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
will be called scx200_i2c.
|
||||
|
||||
This driver is deprecated and will be dropped soon. Use i2c-gpio
|
||||
(or scx200_acb) instead.
|
||||
|
||||
config SCx200_I2C_SCL
|
||||
int "GPIO pin used for SCL"
|
||||
depends on SCx200_I2C
|
||||
default "12"
|
||||
help
|
||||
Enter the GPIO pin number used for the SCL signal. This value can
|
||||
also be specified with a module parameter.
|
||||
|
||||
config SCx200_I2C_SDA
|
||||
int "GPIO pin used for SDA"
|
||||
depends on SCx200_I2C
|
||||
default "13"
|
||||
help
|
||||
Enter the GPIO pin number used for the SSA signal. This value can
|
||||
also be specified with a module parameter.
|
||||
|
||||
config SCx200_ACB
|
||||
tristate "Geode ACCESS.bus support"
|
||||
depends on X86_32 && PCI
|
||||
|
@ -68,7 +68,6 @@ obj-$(CONFIG_I2C_QUP) += i2c-qup.o
|
||||
obj-$(CONFIG_I2C_RIIC) += i2c-riic.o
|
||||
obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o
|
||||
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
|
||||
obj-$(CONFIG_I2C_S6000) += i2c-s6000.o
|
||||
obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o
|
||||
obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o
|
||||
obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
|
||||
@ -101,6 +100,5 @@ obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
|
||||
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
|
||||
obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
|
||||
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
|
||||
obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
|
||||
|
||||
ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
|
||||
|
@ -210,7 +210,7 @@ static void at91_twi_write_data_dma_callback(void *data)
|
||||
struct at91_twi_dev *dev = (struct at91_twi_dev *)data;
|
||||
|
||||
dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg),
|
||||
dev->buf_len, DMA_MEM_TO_DEV);
|
||||
dev->buf_len, DMA_TO_DEVICE);
|
||||
|
||||
at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
|
||||
}
|
||||
@ -289,7 +289,7 @@ static void at91_twi_read_data_dma_callback(void *data)
|
||||
struct at91_twi_dev *dev = (struct at91_twi_dev *)data;
|
||||
|
||||
dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg),
|
||||
dev->buf_len, DMA_DEV_TO_MEM);
|
||||
dev->buf_len, DMA_FROM_DEVICE);
|
||||
|
||||
/* The last two bytes have to be read without using dma */
|
||||
dev->buf += dev->buf_len - 2;
|
||||
@ -768,7 +768,7 @@ static int at91_twi_probe(struct platform_device *pdev)
|
||||
snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91");
|
||||
i2c_set_adapdata(&dev->adapter, dev);
|
||||
dev->adapter.owner = THIS_MODULE;
|
||||
dev->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
|
||||
dev->adapter.class = I2C_CLASS_DEPRECATED;
|
||||
dev->adapter.algo = &at91_twi_algorithm;
|
||||
dev->adapter.dev.parent = dev->dev;
|
||||
dev->adapter.nr = pdev->id;
|
||||
|
@ -277,7 +277,7 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
|
||||
adap = &i2c_dev->adapter;
|
||||
i2c_set_adapdata(adap, i2c_dev);
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
|
||||
adap->class = I2C_CLASS_DEPRECATED;
|
||||
strlcpy(adap->name, "bcm2835 I2C adapter", sizeof(adap->name));
|
||||
adap->algo = &bcm2835_i2c_algo;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
|
@ -648,7 +648,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
|
||||
strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name));
|
||||
p_adap->algo = &bfin_twi_algorithm;
|
||||
p_adap->algo_data = iface;
|
||||
p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
|
||||
p_adap->class = I2C_CLASS_DEPRECATED;
|
||||
p_adap->dev.parent = &pdev->dev;
|
||||
p_adap->timeout = 5 * HZ;
|
||||
p_adap->retries = 3;
|
||||
|
@ -712,7 +712,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
|
||||
adap = &dev->adapter;
|
||||
i2c_set_adapdata(adap, dev);
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
|
||||
adap->class = I2C_CLASS_DEPRECATED;
|
||||
strlcpy(adap->name, "DaVinci I2C adapter", sizeof(adap->name));
|
||||
adap->algo = &i2c_davinci_algo;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
|
@ -188,6 +188,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
|
||||
.scl_sda_cfg = &hsw_config,
|
||||
},
|
||||
};
|
||||
|
||||
static struct i2c_algorithm i2c_dw_algo = {
|
||||
.master_xfer = i2c_dw_xfer,
|
||||
.functionality = i2c_dw_func,
|
||||
@ -350,6 +351,14 @@ static const struct pci_device_id i2_designware_pci_ids[] = {
|
||||
/* Haswell */
|
||||
{ PCI_VDEVICE(INTEL, 0x9c61), haswell },
|
||||
{ PCI_VDEVICE(INTEL, 0x9c62), haswell },
|
||||
/* Braswell / Cherrytrail */
|
||||
{ PCI_VDEVICE(INTEL, 0x22C1), baytrail,},
|
||||
{ PCI_VDEVICE(INTEL, 0x22C2), baytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C3), baytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C4), baytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C5), baytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C6), baytrail },
|
||||
{ PCI_VDEVICE(INTEL, 0x22C7), baytrail },
|
||||
{ 0,}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids);
|
||||
|
@ -106,6 +106,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
|
||||
{ "INT3432", 0 },
|
||||
{ "INT3433", 0 },
|
||||
{ "80860F41", 0 },
|
||||
{ "808622C1", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
|
||||
@ -202,7 +203,7 @@ static int dw_i2c_probe(struct platform_device *pdev)
|
||||
adap = &dev->adapter;
|
||||
i2c_set_adapdata(adap, dev);
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
|
||||
adap->class = I2C_CLASS_DEPRECATED;
|
||||
strlcpy(adap->name, "Synopsys DesignWare I2C adapter",
|
||||
sizeof(adap->name));
|
||||
adap->algo = &i2c_dw_algo;
|
||||
|
@ -370,7 +370,13 @@ static int efm32_i2c_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "efm32,location", &location);
|
||||
|
||||
ret = of_property_read_u32(np, "energymicro,location", &location);
|
||||
|
||||
if (ret)
|
||||
/* fall back to wrongly namespaced property */
|
||||
ret = of_property_read_u32(np, "efm32,location", &location);
|
||||
|
||||
if (!ret) {
|
||||
dev_dbg(&pdev->dev, "using location %u\n", location);
|
||||
} else {
|
||||
|
@ -405,7 +405,6 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id)
|
||||
|
||||
int_status = readl(i2c->regs + HSI2C_INT_STATUS);
|
||||
writel(int_status, i2c->regs + HSI2C_INT_STATUS);
|
||||
fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS);
|
||||
|
||||
/* handle interrupt related to the transfer status */
|
||||
if (int_status & HSI2C_INT_I2C) {
|
||||
@ -526,7 +525,7 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop)
|
||||
if (i2c->msg->flags & I2C_M_RD) {
|
||||
i2c_ctl |= HSI2C_RXCHON;
|
||||
|
||||
i2c_auto_conf = HSI2C_READ_WRITE;
|
||||
i2c_auto_conf |= HSI2C_READ_WRITE;
|
||||
|
||||
trig_lvl = (i2c->msg->len > i2c->variant->fifo_depth) ?
|
||||
(i2c->variant->fifo_depth * 3 / 4) : i2c->msg->len;
|
||||
@ -549,7 +548,6 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop)
|
||||
writel(fifo_ctl, i2c->regs + HSI2C_FIFO_CTL);
|
||||
writel(i2c_ctl, i2c->regs + HSI2C_CTL);
|
||||
|
||||
|
||||
/*
|
||||
* Enable interrupts before starting the transfer so that we don't
|
||||
* miss any INT_I2C interrupts.
|
||||
@ -789,8 +787,16 @@ static int exynos5_i2c_resume_noirq(struct device *dev)
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(exynos5_i2c_dev_pm_ops, exynos5_i2c_suspend_noirq,
|
||||
exynos5_i2c_resume_noirq);
|
||||
static const struct dev_pm_ops exynos5_i2c_dev_pm_ops = {
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.suspend_noirq = exynos5_i2c_suspend_noirq,
|
||||
.resume_noirq = exynos5_i2c_resume_noirq,
|
||||
.freeze_noirq = exynos5_i2c_suspend_noirq,
|
||||
.thaw_noirq = exynos5_i2c_resume_noirq,
|
||||
.poweroff_noirq = exynos5_i2c_suspend_noirq,
|
||||
.restore_noirq = exynos5_i2c_resume_noirq,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct platform_driver exynos5_i2c_driver = {
|
||||
.probe = exynos5_i2c_probe,
|
||||
|
@ -238,12 +238,10 @@ static int i2c_gpio_probe(struct platform_device *pdev)
|
||||
static int i2c_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct i2c_gpio_private_data *priv;
|
||||
struct i2c_gpio_platform_data *pdata;
|
||||
struct i2c_adapter *adap;
|
||||
|
||||
priv = platform_get_drvdata(pdev);
|
||||
adap = &priv->adap;
|
||||
pdata = &priv->pdata;
|
||||
|
||||
i2c_del_adapter(adap);
|
||||
|
||||
|
@ -22,57 +22,58 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
Supports the following Intel I/O Controller Hubs (ICH):
|
||||
|
||||
I/O Block I2C
|
||||
region SMBus Block proc. block
|
||||
Chip name PCI ID size PEC buffer call read
|
||||
----------------------------------------------------------------------
|
||||
82801AA (ICH) 0x2413 16 no no no no
|
||||
82801AB (ICH0) 0x2423 16 no no no no
|
||||
82801BA (ICH2) 0x2443 16 no no no no
|
||||
82801CA (ICH3) 0x2483 32 soft no no no
|
||||
82801DB (ICH4) 0x24c3 32 hard yes no no
|
||||
82801E (ICH5) 0x24d3 32 hard yes yes yes
|
||||
6300ESB 0x25a4 32 hard yes yes yes
|
||||
82801F (ICH6) 0x266a 32 hard yes yes yes
|
||||
6310ESB/6320ESB 0x269b 32 hard yes yes yes
|
||||
82801G (ICH7) 0x27da 32 hard yes yes yes
|
||||
82801H (ICH8) 0x283e 32 hard yes yes yes
|
||||
82801I (ICH9) 0x2930 32 hard yes yes yes
|
||||
EP80579 (Tolapai) 0x5032 32 hard yes yes yes
|
||||
ICH10 0x3a30 32 hard yes yes yes
|
||||
ICH10 0x3a60 32 hard yes yes yes
|
||||
5/3400 Series (PCH) 0x3b30 32 hard yes yes yes
|
||||
6 Series (PCH) 0x1c22 32 hard yes yes yes
|
||||
Patsburg (PCH) 0x1d22 32 hard yes yes yes
|
||||
Patsburg (PCH) IDF 0x1d70 32 hard yes yes yes
|
||||
Patsburg (PCH) IDF 0x1d71 32 hard yes yes yes
|
||||
Patsburg (PCH) IDF 0x1d72 32 hard yes yes yes
|
||||
DH89xxCC (PCH) 0x2330 32 hard yes yes yes
|
||||
Panther Point (PCH) 0x1e22 32 hard yes yes yes
|
||||
Lynx Point (PCH) 0x8c22 32 hard yes yes yes
|
||||
Lynx Point-LP (PCH) 0x9c22 32 hard yes yes yes
|
||||
Avoton (SOC) 0x1f3c 32 hard yes yes yes
|
||||
Wellsburg (PCH) 0x8d22 32 hard yes yes yes
|
||||
Wellsburg (PCH) MS 0x8d7d 32 hard yes yes yes
|
||||
Wellsburg (PCH) MS 0x8d7e 32 hard yes yes yes
|
||||
Wellsburg (PCH) MS 0x8d7f 32 hard yes yes yes
|
||||
Coleto Creek (PCH) 0x23b0 32 hard yes yes yes
|
||||
Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes
|
||||
BayTrail (SOC) 0x0f12 32 hard yes yes yes
|
||||
|
||||
Features supported by this driver:
|
||||
Software PEC no
|
||||
Hardware PEC yes
|
||||
Block buffer yes
|
||||
Block process call transaction no
|
||||
I2C block read transaction yes (doesn't use the block buffer)
|
||||
Slave mode no
|
||||
Interrupt processing yes
|
||||
|
||||
See the file Documentation/i2c/busses/i2c-i801 for details.
|
||||
*/
|
||||
* Supports the following Intel I/O Controller Hubs (ICH):
|
||||
*
|
||||
* I/O Block I2C
|
||||
* region SMBus Block proc. block
|
||||
* Chip name PCI ID size PEC buffer call read
|
||||
* ---------------------------------------------------------------------------
|
||||
* 82801AA (ICH) 0x2413 16 no no no no
|
||||
* 82801AB (ICH0) 0x2423 16 no no no no
|
||||
* 82801BA (ICH2) 0x2443 16 no no no no
|
||||
* 82801CA (ICH3) 0x2483 32 soft no no no
|
||||
* 82801DB (ICH4) 0x24c3 32 hard yes no no
|
||||
* 82801E (ICH5) 0x24d3 32 hard yes yes yes
|
||||
* 6300ESB 0x25a4 32 hard yes yes yes
|
||||
* 82801F (ICH6) 0x266a 32 hard yes yes yes
|
||||
* 6310ESB/6320ESB 0x269b 32 hard yes yes yes
|
||||
* 82801G (ICH7) 0x27da 32 hard yes yes yes
|
||||
* 82801H (ICH8) 0x283e 32 hard yes yes yes
|
||||
* 82801I (ICH9) 0x2930 32 hard yes yes yes
|
||||
* EP80579 (Tolapai) 0x5032 32 hard yes yes yes
|
||||
* ICH10 0x3a30 32 hard yes yes yes
|
||||
* ICH10 0x3a60 32 hard yes yes yes
|
||||
* 5/3400 Series (PCH) 0x3b30 32 hard yes yes yes
|
||||
* 6 Series (PCH) 0x1c22 32 hard yes yes yes
|
||||
* Patsburg (PCH) 0x1d22 32 hard yes yes yes
|
||||
* Patsburg (PCH) IDF 0x1d70 32 hard yes yes yes
|
||||
* Patsburg (PCH) IDF 0x1d71 32 hard yes yes yes
|
||||
* Patsburg (PCH) IDF 0x1d72 32 hard yes yes yes
|
||||
* DH89xxCC (PCH) 0x2330 32 hard yes yes yes
|
||||
* Panther Point (PCH) 0x1e22 32 hard yes yes yes
|
||||
* Lynx Point (PCH) 0x8c22 32 hard yes yes yes
|
||||
* Lynx Point-LP (PCH) 0x9c22 32 hard yes yes yes
|
||||
* Avoton (SOC) 0x1f3c 32 hard yes yes yes
|
||||
* Wellsburg (PCH) 0x8d22 32 hard yes yes yes
|
||||
* Wellsburg (PCH) MS 0x8d7d 32 hard yes yes yes
|
||||
* Wellsburg (PCH) MS 0x8d7e 32 hard yes yes yes
|
||||
* Wellsburg (PCH) MS 0x8d7f 32 hard yes yes yes
|
||||
* Coleto Creek (PCH) 0x23b0 32 hard yes yes yes
|
||||
* Wildcat Point (PCH) 0x8ca2 32 hard yes yes yes
|
||||
* Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes
|
||||
* BayTrail (SOC) 0x0f12 32 hard yes yes yes
|
||||
*
|
||||
* Features supported by this driver:
|
||||
* Software PEC no
|
||||
* Hardware PEC yes
|
||||
* Block buffer yes
|
||||
* Block process call transaction no
|
||||
* I2C block read transaction yes (doesn't use the block buffer)
|
||||
* Slave mode no
|
||||
* Interrupt processing yes
|
||||
*
|
||||
* See the file Documentation/i2c/busses/i2c-i801 for details.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
@ -162,24 +163,25 @@
|
||||
STATUS_ERROR_FLAGS)
|
||||
|
||||
/* Older devices have their ID defined in <linux/pci_ids.h> */
|
||||
#define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12
|
||||
#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22
|
||||
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22
|
||||
#define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12
|
||||
#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 */
|
||||
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0 0x1d70
|
||||
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1 0x1d71
|
||||
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72
|
||||
#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22
|
||||
#define PCI_DEVICE_ID_INTEL_AVOTON_SMBUS 0x1f3c
|
||||
#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330
|
||||
#define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS 0x23b0
|
||||
#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
|
||||
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
|
||||
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS 0x8d22
|
||||
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0 0x8d7d
|
||||
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1 0x8d7e
|
||||
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2 0x8d7f
|
||||
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22
|
||||
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0 0x1d70
|
||||
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1 0x1d71
|
||||
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72
|
||||
#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22
|
||||
#define PCI_DEVICE_ID_INTEL_AVOTON_SMBUS 0x1f3c
|
||||
#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330
|
||||
#define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS 0x23b0
|
||||
#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
|
||||
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
|
||||
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS 0x8ca2
|
||||
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS 0x8d22
|
||||
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0 0x8d7d
|
||||
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1 0x8d7e
|
||||
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2 0x8d7f
|
||||
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22
|
||||
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS 0x9ca2
|
||||
|
||||
struct i801_mux_config {
|
||||
@ -823,6 +825,7 @@ static const struct pci_device_id i801_ids[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) },
|
||||
{ 0, }
|
||||
|
@ -735,10 +735,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
||||
clk_disable_unprepare(i2c_imx->clk);
|
||||
|
||||
dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", irq);
|
||||
dev_dbg(&i2c_imx->adapter.dev, "device resources from 0x%x to 0x%x\n",
|
||||
res->start, res->end);
|
||||
dev_dbg(&i2c_imx->adapter.dev, "allocated %d bytes at 0x%x\n",
|
||||
resource_size(res), res->start);
|
||||
dev_dbg(&i2c_imx->adapter.dev, "device resources: %pR\n", res);
|
||||
dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n",
|
||||
i2c_imx->adapter.name);
|
||||
dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
|
||||
|
@ -341,8 +341,7 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void)
|
||||
iounmap(reg);
|
||||
}
|
||||
}
|
||||
if (node)
|
||||
of_node_put(node);
|
||||
of_node_put(node);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
@ -863,7 +863,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
|
||||
drv_data->adapter.dev.parent = &pd->dev;
|
||||
drv_data->adapter.algo = &mv64xxx_i2c_algo;
|
||||
drv_data->adapter.owner = THIS_MODULE;
|
||||
drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
|
||||
drv_data->adapter.class = I2C_CLASS_DEPRECATED;
|
||||
drv_data->adapter.nr = pd->id;
|
||||
drv_data->adapter.dev.of_node = pd->dev.of_node;
|
||||
platform_set_drvdata(pd, drv_data);
|
||||
|
@ -1032,10 +1032,10 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
adap = &dev->adap;
|
||||
adap->dev.of_node = np;
|
||||
adap->dev.parent = &adev->dev;
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
|
||||
adap->algo = &nmk_i2c_algo;
|
||||
adap->timeout = msecs_to_jiffies(dev->timeout);
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->class = I2C_CLASS_DEPRECATED;
|
||||
adap->algo = &nmk_i2c_algo;
|
||||
adap->timeout = msecs_to_jiffies(dev->timeout);
|
||||
snprintf(adap->name, sizeof(adap->name),
|
||||
"Nomadik I2C at %pR", &adev->res);
|
||||
|
||||
|
@ -239,15 +239,15 @@ static u32 ocores_func(struct i2c_adapter *adap)
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm ocores_algorithm = {
|
||||
.master_xfer = ocores_xfer,
|
||||
.functionality = ocores_func,
|
||||
.master_xfer = ocores_xfer,
|
||||
.functionality = ocores_func,
|
||||
};
|
||||
|
||||
static struct i2c_adapter ocores_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "i2c-ocores",
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED,
|
||||
.algo = &ocores_algorithm,
|
||||
.owner = THIS_MODULE,
|
||||
.name = "i2c-ocores",
|
||||
.class = I2C_CLASS_DEPRECATED,
|
||||
.algo = &ocores_algorithm,
|
||||
};
|
||||
|
||||
static const struct of_device_id ocores_i2c_match[] = {
|
||||
|
@ -1236,7 +1236,7 @@ omap_i2c_probe(struct platform_device *pdev)
|
||||
adap = &dev->adapter;
|
||||
i2c_set_adapdata(adap, dev);
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
|
||||
adap->class = I2C_CLASS_DEPRECATED;
|
||||
strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
|
||||
adap->algo = &omap_i2c_algo;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
|
@ -633,13 +633,17 @@ static int qup_i2c_probe(struct platform_device *pdev)
|
||||
* associated with each byte written/received
|
||||
*/
|
||||
size = QUP_OUTPUT_BLOCK_SIZE(io_mode);
|
||||
if (size >= ARRAY_SIZE(blk_sizes))
|
||||
return -EIO;
|
||||
if (size >= ARRAY_SIZE(blk_sizes)) {
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
qup->out_blk_sz = blk_sizes[size] / 2;
|
||||
|
||||
size = QUP_INPUT_BLOCK_SIZE(io_mode);
|
||||
if (size >= ARRAY_SIZE(blk_sizes))
|
||||
return -EIO;
|
||||
if (size >= ARRAY_SIZE(blk_sizes)) {
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
qup->in_blk_sz = blk_sizes[size] / 2;
|
||||
|
||||
size = QUP_OUTPUT_FIFO_SIZE(io_mode);
|
||||
|
@ -541,13 +541,13 @@ static int rcar_i2c_probe(struct platform_device *pdev)
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
init_waitqueue_head(&priv->wait);
|
||||
|
||||
adap = &priv->adap;
|
||||
adap->nr = pdev->id;
|
||||
adap->algo = &rcar_i2c_algo;
|
||||
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
|
||||
adap->retries = 3;
|
||||
adap->dev.parent = dev;
|
||||
adap->dev.of_node = dev->of_node;
|
||||
adap = &priv->adap;
|
||||
adap->nr = pdev->id;
|
||||
adap->algo = &rcar_i2c_algo;
|
||||
adap->class = I2C_CLASS_DEPRECATED;
|
||||
adap->retries = 3;
|
||||
adap->dev.parent = dev;
|
||||
adap->dev.of_node = dev->of_node;
|
||||
i2c_set_adapdata(adap, priv);
|
||||
strlcpy(adap->name, pdev->name, sizeof(adap->name));
|
||||
|
||||
|
@ -399,7 +399,7 @@ static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id)
|
||||
}
|
||||
|
||||
/* is there anything left to handle? */
|
||||
if (unlikely(ipd == 0))
|
||||
if (unlikely((ipd & REG_INT_ALL) == 0))
|
||||
goto out;
|
||||
|
||||
switch (i2c->state) {
|
||||
|
@ -1128,11 +1128,11 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
|
||||
s3c24xx_i2c_parse_dt(pdev->dev.of_node, i2c);
|
||||
|
||||
strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
|
||||
i2c->adap.owner = THIS_MODULE;
|
||||
i2c->adap.algo = &s3c24xx_i2c_algorithm;
|
||||
i2c->adap.owner = THIS_MODULE;
|
||||
i2c->adap.algo = &s3c24xx_i2c_algorithm;
|
||||
i2c->adap.retries = 2;
|
||||
i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
|
||||
i2c->tx_setup = 50;
|
||||
i2c->adap.class = I2C_CLASS_DEPRECATED;
|
||||
i2c->tx_setup = 50;
|
||||
|
||||
init_waitqueue_head(&i2c->wait);
|
||||
|
||||
@ -1267,7 +1267,7 @@ static int s3c24xx_i2c_suspend_noirq(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s3c24xx_i2c_resume(struct device *dev)
|
||||
static int s3c24xx_i2c_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
|
||||
@ -1285,7 +1285,11 @@ static int s3c24xx_i2c_resume(struct device *dev)
|
||||
static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = {
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.suspend_noirq = s3c24xx_i2c_suspend_noirq,
|
||||
.resume = s3c24xx_i2c_resume,
|
||||
.resume_noirq = s3c24xx_i2c_resume_noirq,
|
||||
.freeze_noirq = s3c24xx_i2c_suspend_noirq,
|
||||
.thaw_noirq = s3c24xx_i2c_resume_noirq,
|
||||
.poweroff_noirq = s3c24xx_i2c_suspend_noirq,
|
||||
.restore_noirq = s3c24xx_i2c_resume_noirq,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -1,404 +0,0 @@
|
||||
/*
|
||||
* drivers/i2c/busses/i2c-s6000.c
|
||||
*
|
||||
* Description: Driver for S6000 Family I2C Interface
|
||||
* Copyright (c) 2008 emlix GmbH
|
||||
* Author: Oskar Schirmer <oskar@scara.com>
|
||||
*
|
||||
* Partially based on i2c-bfin-twi.c driver by <sonic.zhang@analog.com>
|
||||
* Copyright (c) 2005-2007 Analog Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c/s6000.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "i2c-s6000.h"
|
||||
|
||||
#define DRV_NAME "i2c-s6000"
|
||||
|
||||
#define POLL_TIMEOUT (2 * HZ)
|
||||
|
||||
struct s6i2c_if {
|
||||
u8 __iomem *reg; /* memory mapped registers */
|
||||
int irq;
|
||||
spinlock_t lock;
|
||||
struct i2c_msg *msgs; /* messages currently handled */
|
||||
int msgs_num; /* nb of msgs to do */
|
||||
int msgs_push; /* nb of msgs read/written */
|
||||
int msgs_done; /* nb of msgs finally handled */
|
||||
unsigned push; /* nb of bytes read/written in msg */
|
||||
unsigned done; /* nb of bytes finally handled */
|
||||
int timeout_count; /* timeout retries left */
|
||||
struct timer_list timeout_timer;
|
||||
struct i2c_adapter adap;
|
||||
struct completion complete;
|
||||
struct clk *clk;
|
||||
struct resource *res;
|
||||
};
|
||||
|
||||
static inline u16 i2c_rd16(struct s6i2c_if *iface, unsigned n)
|
||||
{
|
||||
return readw(iface->reg + (n));
|
||||
}
|
||||
|
||||
static inline void i2c_wr16(struct s6i2c_if *iface, unsigned n, u16 v)
|
||||
{
|
||||
writew(v, iface->reg + (n));
|
||||
}
|
||||
|
||||
static inline u32 i2c_rd32(struct s6i2c_if *iface, unsigned n)
|
||||
{
|
||||
return readl(iface->reg + (n));
|
||||
}
|
||||
|
||||
static inline void i2c_wr32(struct s6i2c_if *iface, unsigned n, u32 v)
|
||||
{
|
||||
writel(v, iface->reg + (n));
|
||||
}
|
||||
|
||||
static struct s6i2c_if s6i2c_if;
|
||||
|
||||
static void s6i2c_handle_interrupt(struct s6i2c_if *iface)
|
||||
{
|
||||
if (i2c_rd16(iface, S6_I2C_INTRSTAT) & (1 << S6_I2C_INTR_TXABRT)) {
|
||||
i2c_rd16(iface, S6_I2C_CLRTXABRT);
|
||||
i2c_wr16(iface, S6_I2C_INTRMASK, 0);
|
||||
complete(&iface->complete);
|
||||
return;
|
||||
}
|
||||
if (iface->msgs_done >= iface->msgs_num) {
|
||||
dev_err(&iface->adap.dev, "s6i2c: spurious I2C irq: %04x\n",
|
||||
i2c_rd16(iface, S6_I2C_INTRSTAT));
|
||||
i2c_wr16(iface, S6_I2C_INTRMASK, 0);
|
||||
return;
|
||||
}
|
||||
while ((iface->msgs_push < iface->msgs_num)
|
||||
&& (i2c_rd16(iface, S6_I2C_STATUS) & (1 << S6_I2C_STATUS_TFNF))) {
|
||||
struct i2c_msg *m = &iface->msgs[iface->msgs_push];
|
||||
if (!(m->flags & I2C_M_RD))
|
||||
i2c_wr16(iface, S6_I2C_DATACMD, m->buf[iface->push]);
|
||||
else
|
||||
i2c_wr16(iface, S6_I2C_DATACMD,
|
||||
1 << S6_I2C_DATACMD_READ);
|
||||
if (++iface->push >= m->len) {
|
||||
iface->push = 0;
|
||||
iface->msgs_push += 1;
|
||||
}
|
||||
}
|
||||
do {
|
||||
struct i2c_msg *m = &iface->msgs[iface->msgs_done];
|
||||
if (!(m->flags & I2C_M_RD)) {
|
||||
if (iface->msgs_done < iface->msgs_push)
|
||||
iface->msgs_done += 1;
|
||||
else
|
||||
break;
|
||||
} else if (i2c_rd16(iface, S6_I2C_STATUS)
|
||||
& (1 << S6_I2C_STATUS_RFNE)) {
|
||||
m->buf[iface->done] = i2c_rd16(iface, S6_I2C_DATACMD);
|
||||
if (++iface->done >= m->len) {
|
||||
iface->done = 0;
|
||||
iface->msgs_done += 1;
|
||||
}
|
||||
} else{
|
||||
break;
|
||||
}
|
||||
} while (iface->msgs_done < iface->msgs_num);
|
||||
if (iface->msgs_done >= iface->msgs_num) {
|
||||
i2c_wr16(iface, S6_I2C_INTRMASK, 1 << S6_I2C_INTR_TXABRT);
|
||||
complete(&iface->complete);
|
||||
} else if (iface->msgs_push >= iface->msgs_num) {
|
||||
i2c_wr16(iface, S6_I2C_INTRMASK, (1 << S6_I2C_INTR_TXABRT) |
|
||||
(1 << S6_I2C_INTR_RXFULL));
|
||||
} else {
|
||||
i2c_wr16(iface, S6_I2C_INTRMASK, (1 << S6_I2C_INTR_TXABRT) |
|
||||
(1 << S6_I2C_INTR_TXEMPTY) |
|
||||
(1 << S6_I2C_INTR_RXFULL));
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t s6i2c_interrupt_entry(int irq, void *dev_id)
|
||||
{
|
||||
struct s6i2c_if *iface = dev_id;
|
||||
if (!(i2c_rd16(iface, S6_I2C_STATUS) & ((1 << S6_I2C_INTR_RXUNDER)
|
||||
| (1 << S6_I2C_INTR_RXOVER)
|
||||
| (1 << S6_I2C_INTR_RXFULL)
|
||||
| (1 << S6_I2C_INTR_TXOVER)
|
||||
| (1 << S6_I2C_INTR_TXEMPTY)
|
||||
| (1 << S6_I2C_INTR_RDREQ)
|
||||
| (1 << S6_I2C_INTR_TXABRT)
|
||||
| (1 << S6_I2C_INTR_RXDONE)
|
||||
| (1 << S6_I2C_INTR_ACTIVITY)
|
||||
| (1 << S6_I2C_INTR_STOPDET)
|
||||
| (1 << S6_I2C_INTR_STARTDET)
|
||||
| (1 << S6_I2C_INTR_GENCALL))))
|
||||
return IRQ_NONE;
|
||||
|
||||
spin_lock(&iface->lock);
|
||||
del_timer(&iface->timeout_timer);
|
||||
s6i2c_handle_interrupt(iface);
|
||||
spin_unlock(&iface->lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void s6i2c_timeout(unsigned long data)
|
||||
{
|
||||
struct s6i2c_if *iface = (struct s6i2c_if *)data;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&iface->lock, flags);
|
||||
s6i2c_handle_interrupt(iface);
|
||||
if (--iface->timeout_count > 0) {
|
||||
iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
|
||||
add_timer(&iface->timeout_timer);
|
||||
} else {
|
||||
complete(&iface->complete);
|
||||
i2c_wr16(iface, S6_I2C_INTRMASK, 0);
|
||||
}
|
||||
spin_unlock_irqrestore(&iface->lock, flags);
|
||||
}
|
||||
|
||||
static int s6i2c_master_xfer(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
struct s6i2c_if *iface = adap->algo_data;
|
||||
int i;
|
||||
if (num == 0)
|
||||
return 0;
|
||||
if (i2c_rd16(iface, S6_I2C_STATUS) & (1 << S6_I2C_STATUS_ACTIVITY))
|
||||
yield();
|
||||
i2c_wr16(iface, S6_I2C_INTRMASK, 0);
|
||||
i2c_rd16(iface, S6_I2C_CLRINTR);
|
||||
for (i = 0; i < num; i++) {
|
||||
if (msgs[i].flags & I2C_M_TEN) {
|
||||
dev_err(&adap->dev,
|
||||
"s6i2c: 10 bits addr not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (msgs[i].len == 0) {
|
||||
dev_err(&adap->dev,
|
||||
"s6i2c: zero length message not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (msgs[i].addr != msgs[0].addr) {
|
||||
dev_err(&adap->dev,
|
||||
"s6i2c: multiple xfer cannot change target\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
iface->msgs = msgs;
|
||||
iface->msgs_num = num;
|
||||
iface->msgs_push = 0;
|
||||
iface->msgs_done = 0;
|
||||
iface->push = 0;
|
||||
iface->done = 0;
|
||||
iface->timeout_count = 10;
|
||||
i2c_wr16(iface, S6_I2C_TAR, msgs[0].addr);
|
||||
i2c_wr16(iface, S6_I2C_ENABLE, 1);
|
||||
i2c_wr16(iface, S6_I2C_INTRMASK, (1 << S6_I2C_INTR_TXEMPTY) |
|
||||
(1 << S6_I2C_INTR_TXABRT));
|
||||
|
||||
iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
|
||||
add_timer(&iface->timeout_timer);
|
||||
wait_for_completion(&iface->complete);
|
||||
del_timer_sync(&iface->timeout_timer);
|
||||
while (i2c_rd32(iface, S6_I2C_TXFLR) > 0)
|
||||
schedule();
|
||||
while (i2c_rd16(iface, S6_I2C_STATUS) & (1 << S6_I2C_STATUS_ACTIVITY))
|
||||
schedule();
|
||||
|
||||
i2c_wr16(iface, S6_I2C_INTRMASK, 0);
|
||||
i2c_wr16(iface, S6_I2C_ENABLE, 0);
|
||||
return iface->msgs_done;
|
||||
}
|
||||
|
||||
static u32 s6i2c_functionality(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm s6i2c_algorithm = {
|
||||
.master_xfer = s6i2c_master_xfer,
|
||||
.functionality = s6i2c_functionality,
|
||||
};
|
||||
|
||||
static u16 nanoseconds_on_clk(struct s6i2c_if *iface, u32 ns)
|
||||
{
|
||||
u32 dividend = ((clk_get_rate(iface->clk) / 1000) * ns) / 1000000;
|
||||
if (dividend > 0xffff)
|
||||
return 0xffff;
|
||||
return dividend;
|
||||
}
|
||||
|
||||
static int s6i2c_probe(struct platform_device *dev)
|
||||
{
|
||||
struct s6i2c_if *iface = &s6i2c_if;
|
||||
struct i2c_adapter *p_adap;
|
||||
const char *clock;
|
||||
int bus_num, rc;
|
||||
spin_lock_init(&iface->lock);
|
||||
init_completion(&iface->complete);
|
||||
iface->irq = platform_get_irq(dev, 0);
|
||||
if (iface->irq < 0) {
|
||||
rc = iface->irq;
|
||||
goto err_out;
|
||||
}
|
||||
iface->res = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
||||
if (!iface->res) {
|
||||
rc = -ENXIO;
|
||||
goto err_out;
|
||||
}
|
||||
iface->res = request_mem_region(iface->res->start,
|
||||
resource_size(iface->res),
|
||||
dev->dev.bus_id);
|
||||
if (!iface->res) {
|
||||
rc = -EBUSY;
|
||||
goto err_out;
|
||||
}
|
||||
iface->reg = ioremap_nocache(iface->res->start,
|
||||
resource_size(iface->res));
|
||||
if (!iface->reg) {
|
||||
rc = -ENOMEM;
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
clock = 0;
|
||||
bus_num = -1;
|
||||
if (dev_get_platdata(&dev->dev)) {
|
||||
struct s6_i2c_platform_data *pdata =
|
||||
dev_get_platdata(&dev->dev);
|
||||
bus_num = pdata->bus_num;
|
||||
clock = pdata->clock;
|
||||
}
|
||||
iface->clk = clk_get(&dev->dev, clock);
|
||||
if (IS_ERR(iface->clk)) {
|
||||
rc = PTR_ERR(iface->clk);
|
||||
goto err_map;
|
||||
}
|
||||
rc = clk_enable(iface->clk);
|
||||
if (rc < 0)
|
||||
goto err_clk_put;
|
||||
init_timer(&iface->timeout_timer);
|
||||
iface->timeout_timer.function = s6i2c_timeout;
|
||||
iface->timeout_timer.data = (unsigned long)iface;
|
||||
|
||||
p_adap = &iface->adap;
|
||||
strlcpy(p_adap->name, dev->name, sizeof(p_adap->name));
|
||||
p_adap->algo = &s6i2c_algorithm;
|
||||
p_adap->algo_data = iface;
|
||||
p_adap->nr = bus_num;
|
||||
p_adap->class = 0;
|
||||
p_adap->dev.parent = &dev->dev;
|
||||
i2c_wr16(iface, S6_I2C_INTRMASK, 0);
|
||||
rc = request_irq(iface->irq, s6i2c_interrupt_entry,
|
||||
IRQF_SHARED, dev->name, iface);
|
||||
if (rc) {
|
||||
dev_err(&p_adap->dev, "s6i2c: can't get IRQ %d\n", iface->irq);
|
||||
goto err_clk_dis;
|
||||
}
|
||||
|
||||
i2c_wr16(iface, S6_I2C_ENABLE, 0);
|
||||
udelay(1);
|
||||
i2c_wr32(iface, S6_I2C_SRESET, 1 << S6_I2C_SRESET_IC_SRST);
|
||||
i2c_wr16(iface, S6_I2C_CLRTXABRT, 1);
|
||||
i2c_wr16(iface, S6_I2C_CON,
|
||||
(1 << S6_I2C_CON_MASTER) |
|
||||
(S6_I2C_CON_SPEED_NORMAL << S6_I2C_CON_SPEED) |
|
||||
(0 << S6_I2C_CON_10BITSLAVE) |
|
||||
(0 << S6_I2C_CON_10BITMASTER) |
|
||||
(1 << S6_I2C_CON_RESTARTENA) |
|
||||
(1 << S6_I2C_CON_SLAVEDISABLE));
|
||||
i2c_wr16(iface, S6_I2C_SSHCNT, nanoseconds_on_clk(iface, 4000));
|
||||
i2c_wr16(iface, S6_I2C_SSLCNT, nanoseconds_on_clk(iface, 4700));
|
||||
i2c_wr16(iface, S6_I2C_FSHCNT, nanoseconds_on_clk(iface, 600));
|
||||
i2c_wr16(iface, S6_I2C_FSLCNT, nanoseconds_on_clk(iface, 1300));
|
||||
i2c_wr16(iface, S6_I2C_RXTL, 0);
|
||||
i2c_wr16(iface, S6_I2C_TXTL, 0);
|
||||
|
||||
platform_set_drvdata(dev, iface);
|
||||
rc = i2c_add_numbered_adapter(p_adap);
|
||||
if (rc)
|
||||
goto err_irq_free;
|
||||
return 0;
|
||||
|
||||
err_irq_free:
|
||||
free_irq(iface->irq, iface);
|
||||
err_clk_dis:
|
||||
clk_disable(iface->clk);
|
||||
err_clk_put:
|
||||
clk_put(iface->clk);
|
||||
err_map:
|
||||
iounmap(iface->reg);
|
||||
err_reg:
|
||||
release_mem_region(iface->res->start,
|
||||
resource_size(iface->res));
|
||||
err_out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int s6i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct s6i2c_if *iface = platform_get_drvdata(pdev);
|
||||
i2c_wr16(iface, S6_I2C_ENABLE, 0);
|
||||
i2c_del_adapter(&iface->adap);
|
||||
free_irq(iface->irq, iface);
|
||||
clk_disable(iface->clk);
|
||||
clk_put(iface->clk);
|
||||
iounmap(iface->reg);
|
||||
release_mem_region(iface->res->start,
|
||||
resource_size(iface->res));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver s6i2c_driver = {
|
||||
.probe = s6i2c_probe,
|
||||
.remove = s6i2c_remove,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init s6i2c_init(void)
|
||||
{
|
||||
pr_info("I2C: S6000 I2C driver\n");
|
||||
return platform_driver_register(&s6i2c_driver);
|
||||
}
|
||||
|
||||
static void __exit s6i2c_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&s6i2c_driver);
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("I2C-Bus adapter routines for S6000 I2C");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
|
||||
subsys_initcall(s6i2c_init);
|
||||
module_exit(s6i2c_exit);
|
@ -1,79 +0,0 @@
|
||||
/*
|
||||
* drivers/i2c/busses/i2c-s6000.h
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 2008 Emlix GmbH <info@emlix.com>
|
||||
* Author: Oskar Schirmer <oskar@scara.com>
|
||||
*/
|
||||
|
||||
#ifndef __DRIVERS_I2C_BUSSES_I2C_S6000_H
|
||||
#define __DRIVERS_I2C_BUSSES_I2C_S6000_H
|
||||
|
||||
#define S6_I2C_CON 0x000
|
||||
#define S6_I2C_CON_MASTER 0
|
||||
#define S6_I2C_CON_SPEED 1
|
||||
#define S6_I2C_CON_SPEED_NORMAL 1
|
||||
#define S6_I2C_CON_SPEED_FAST 2
|
||||
#define S6_I2C_CON_SPEED_MASK 3
|
||||
#define S6_I2C_CON_10BITSLAVE 3
|
||||
#define S6_I2C_CON_10BITMASTER 4
|
||||
#define S6_I2C_CON_RESTARTENA 5
|
||||
#define S6_I2C_CON_SLAVEDISABLE 6
|
||||
#define S6_I2C_TAR 0x004
|
||||
#define S6_I2C_TAR_GCORSTART 10
|
||||
#define S6_I2C_TAR_SPECIAL 11
|
||||
#define S6_I2C_SAR 0x008
|
||||
#define S6_I2C_HSMADDR 0x00C
|
||||
#define S6_I2C_DATACMD 0x010
|
||||
#define S6_I2C_DATACMD_READ 8
|
||||
#define S6_I2C_SSHCNT 0x014
|
||||
#define S6_I2C_SSLCNT 0x018
|
||||
#define S6_I2C_FSHCNT 0x01C
|
||||
#define S6_I2C_FSLCNT 0x020
|
||||
#define S6_I2C_INTRSTAT 0x02C
|
||||
#define S6_I2C_INTRMASK 0x030
|
||||
#define S6_I2C_RAWINTR 0x034
|
||||
#define S6_I2C_INTR_RXUNDER 0
|
||||
#define S6_I2C_INTR_RXOVER 1
|
||||
#define S6_I2C_INTR_RXFULL 2
|
||||
#define S6_I2C_INTR_TXOVER 3
|
||||
#define S6_I2C_INTR_TXEMPTY 4
|
||||
#define S6_I2C_INTR_RDREQ 5
|
||||
#define S6_I2C_INTR_TXABRT 6
|
||||
#define S6_I2C_INTR_RXDONE 7
|
||||
#define S6_I2C_INTR_ACTIVITY 8
|
||||
#define S6_I2C_INTR_STOPDET 9
|
||||
#define S6_I2C_INTR_STARTDET 10
|
||||
#define S6_I2C_INTR_GENCALL 11
|
||||
#define S6_I2C_RXTL 0x038
|
||||
#define S6_I2C_TXTL 0x03C
|
||||
#define S6_I2C_CLRINTR 0x040
|
||||
#define S6_I2C_CLRRXUNDER 0x044
|
||||
#define S6_I2C_CLRRXOVER 0x048
|
||||
#define S6_I2C_CLRTXOVER 0x04C
|
||||
#define S6_I2C_CLRRDREQ 0x050
|
||||
#define S6_I2C_CLRTXABRT 0x054
|
||||
#define S6_I2C_CLRRXDONE 0x058
|
||||
#define S6_I2C_CLRACTIVITY 0x05C
|
||||
#define S6_I2C_CLRSTOPDET 0x060
|
||||
#define S6_I2C_CLRSTARTDET 0x064
|
||||
#define S6_I2C_CLRGENCALL 0x068
|
||||
#define S6_I2C_ENABLE 0x06C
|
||||
#define S6_I2C_STATUS 0x070
|
||||
#define S6_I2C_STATUS_ACTIVITY 0
|
||||
#define S6_I2C_STATUS_TFNF 1
|
||||
#define S6_I2C_STATUS_TFE 2
|
||||
#define S6_I2C_STATUS_RFNE 3
|
||||
#define S6_I2C_STATUS_RFF 4
|
||||
#define S6_I2C_TXFLR 0x074
|
||||
#define S6_I2C_RXFLR 0x078
|
||||
#define S6_I2C_SRESET 0x07C
|
||||
#define S6_I2C_SRESET_IC_SRST 0
|
||||
#define S6_I2C_SRESET_IC_MASTER_SRST 1
|
||||
#define S6_I2C_SRESET_IC_SLAVE_SRST 2
|
||||
#define S6_I2C_TXABRTSOURCE 0x080
|
||||
|
||||
#endif
|
@ -311,7 +311,7 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev)
|
||||
goto out;
|
||||
}
|
||||
adap = &siic->adapter;
|
||||
adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
|
||||
adap->class = I2C_CLASS_DEPRECATED;
|
||||
|
||||
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
siic->base = devm_ioremap_resource(&pdev->dev, mem_res);
|
||||
|
@ -206,25 +206,31 @@ static inline void st_i2c_clr_bits(void __iomem *reg, u32 mask)
|
||||
writel_relaxed(readl_relaxed(reg) & ~mask, reg);
|
||||
}
|
||||
|
||||
/* From I2C Specifications v0.5 */
|
||||
/*
|
||||
* From I2C Specifications v0.5.
|
||||
*
|
||||
* All the values below have +10% margin added to be
|
||||
* compatible with some out-of-spec devices,
|
||||
* like HDMI link of the Toshiba 19AV600 TV.
|
||||
*/
|
||||
static struct st_i2c_timings i2c_timings[] = {
|
||||
[I2C_MODE_STANDARD] = {
|
||||
.rate = 100000,
|
||||
.rep_start_hold = 4000,
|
||||
.rep_start_setup = 4700,
|
||||
.start_hold = 4000,
|
||||
.data_setup_time = 250,
|
||||
.stop_setup_time = 4000,
|
||||
.bus_free_time = 4700,
|
||||
.rep_start_hold = 4400,
|
||||
.rep_start_setup = 5170,
|
||||
.start_hold = 4400,
|
||||
.data_setup_time = 275,
|
||||
.stop_setup_time = 4400,
|
||||
.bus_free_time = 5170,
|
||||
},
|
||||
[I2C_MODE_FAST] = {
|
||||
.rate = 400000,
|
||||
.rep_start_hold = 600,
|
||||
.rep_start_setup = 600,
|
||||
.start_hold = 600,
|
||||
.data_setup_time = 100,
|
||||
.stop_setup_time = 600,
|
||||
.bus_free_time = 1300,
|
||||
.rep_start_hold = 660,
|
||||
.rep_start_setup = 660,
|
||||
.start_hold = 660,
|
||||
.data_setup_time = 110,
|
||||
.stop_setup_time = 660,
|
||||
.bus_free_time = 1430,
|
||||
},
|
||||
};
|
||||
|
||||
@ -815,7 +821,7 @@ static int st_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
adap = &i2c_dev->adap;
|
||||
i2c_set_adapdata(adap, i2c_dev);
|
||||
snprintf(adap->name, sizeof(adap->name), "ST I2C(0x%x)", res->start);
|
||||
snprintf(adap->name, sizeof(adap->name), "ST I2C(0x%pa)", &res->start);
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->timeout = 2 * HZ;
|
||||
adap->retries = 0;
|
||||
|
@ -909,7 +909,7 @@ static int stu300_probe(struct platform_device *pdev)
|
||||
adap = &dev->adapter;
|
||||
adap->owner = THIS_MODULE;
|
||||
/* DDC class but actually often used for more generic I2C */
|
||||
adap->class = I2C_CLASS_DDC | I2C_CLASS_DEPRECATED;
|
||||
adap->class = I2C_CLASS_DEPRECATED;
|
||||
strlcpy(adap->name, "ST Microelectronics DDC I2C adapter",
|
||||
sizeof(adap->name));
|
||||
adap->nr = bus_nr;
|
||||
|
@ -311,19 +311,8 @@ static struct serio_driver taos_drv = {
|
||||
.interrupt = taos_interrupt,
|
||||
};
|
||||
|
||||
static int __init taos_init(void)
|
||||
{
|
||||
return serio_register_driver(&taos_drv);
|
||||
}
|
||||
|
||||
static void __exit taos_exit(void)
|
||||
{
|
||||
serio_unregister_driver(&taos_drv);
|
||||
}
|
||||
module_serio_driver(taos_drv);
|
||||
|
||||
MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
|
||||
MODULE_DESCRIPTION("TAOS evaluation module driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(taos_init);
|
||||
module_exit(taos_exit);
|
||||
|
@ -792,7 +792,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
|
||||
i2c_dev->adapter.owner = THIS_MODULE;
|
||||
i2c_dev->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
|
||||
i2c_dev->adapter.class = I2C_CLASS_DEPRECATED;
|
||||
strlcpy(i2c_dev->adapter.name, "Tegra I2C adapter",
|
||||
sizeof(i2c_dev->adapter.name));
|
||||
i2c_dev->adapter.algo = &tegra_i2c_algo;
|
||||
|
@ -677,15 +677,15 @@ static u32 xiic_func(struct i2c_adapter *adap)
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm xiic_algorithm = {
|
||||
.master_xfer = xiic_xfer,
|
||||
.functionality = xiic_func,
|
||||
.master_xfer = xiic_xfer,
|
||||
.functionality = xiic_func,
|
||||
};
|
||||
|
||||
static struct i2c_adapter xiic_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRIVER_NAME,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED,
|
||||
.algo = &xiic_algorithm,
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRIVER_NAME,
|
||||
.class = I2C_CLASS_DEPRECATED,
|
||||
.algo = &xiic_algorithm,
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,129 +0,0 @@
|
||||
/* linux/drivers/i2c/busses/scx200_i2c.c
|
||||
|
||||
Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
|
||||
|
||||
National Semiconductor SCx200 I2C bus on GPIO pins
|
||||
|
||||
Based on i2c-velleman.c Copyright (C) 1995-96, 2000 Simon G. Vogl
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <linux/scx200_gpio.h>
|
||||
|
||||
MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
|
||||
MODULE_DESCRIPTION("NatSemi SCx200 I2C Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int scl = CONFIG_SCx200_I2C_SCL;
|
||||
static int sda = CONFIG_SCx200_I2C_SDA;
|
||||
|
||||
module_param(scl, int, 0);
|
||||
MODULE_PARM_DESC(scl, "GPIO line for SCL");
|
||||
module_param(sda, int, 0);
|
||||
MODULE_PARM_DESC(sda, "GPIO line for SDA");
|
||||
|
||||
static void scx200_i2c_setscl(void *data, int state)
|
||||
{
|
||||
scx200_gpio_set(scl, state);
|
||||
}
|
||||
|
||||
static void scx200_i2c_setsda(void *data, int state)
|
||||
{
|
||||
scx200_gpio_set(sda, state);
|
||||
}
|
||||
|
||||
static int scx200_i2c_getscl(void *data)
|
||||
{
|
||||
return scx200_gpio_get(scl);
|
||||
}
|
||||
|
||||
static int scx200_i2c_getsda(void *data)
|
||||
{
|
||||
return scx200_gpio_get(sda);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* Encapsulate the above functions in the correct operations structure.
|
||||
* This is only done when more than one hardware adapter is supported.
|
||||
*/
|
||||
|
||||
static struct i2c_algo_bit_data scx200_i2c_data = {
|
||||
.setsda = scx200_i2c_setsda,
|
||||
.setscl = scx200_i2c_setscl,
|
||||
.getsda = scx200_i2c_getsda,
|
||||
.getscl = scx200_i2c_getscl,
|
||||
.udelay = 10,
|
||||
.timeout = HZ,
|
||||
};
|
||||
|
||||
static struct i2c_adapter scx200_i2c_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
|
||||
.algo_data = &scx200_i2c_data,
|
||||
.name = "NatSemi SCx200 I2C",
|
||||
};
|
||||
|
||||
static int scx200_i2c_init(void)
|
||||
{
|
||||
pr_debug("NatSemi SCx200 I2C Driver\n");
|
||||
|
||||
if (!scx200_gpio_present()) {
|
||||
pr_err("no SCx200 gpio pins available\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pr_debug("SCL=GPIO%02u, SDA=GPIO%02u\n", scl, sda);
|
||||
|
||||
if (scl == -1 || sda == -1 || scl == sda) {
|
||||
pr_err("scl and sda must be specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Configure GPIOs as open collector outputs */
|
||||
scx200_gpio_configure(scl, ~2, 5);
|
||||
scx200_gpio_configure(sda, ~2, 5);
|
||||
|
||||
if (i2c_bit_add_bus(&scx200_i2c_ops) < 0) {
|
||||
pr_err("adapter %s registration failed\n", scx200_i2c_ops.name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void scx200_i2c_cleanup(void)
|
||||
{
|
||||
i2c_del_adapter(&scx200_i2c_ops);
|
||||
}
|
||||
|
||||
module_init(scx200_i2c_init);
|
||||
module_exit(scx200_i2c_cleanup);
|
||||
|
||||
/*
|
||||
Local variables:
|
||||
compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
|
||||
c-basic-offset: 8
|
||||
End:
|
||||
*/
|
362
drivers/i2c/i2c-acpi.c
Normal file
362
drivers/i2c/i2c-acpi.c
Normal file
@ -0,0 +1,362 @@
|
||||
/*
|
||||
* I2C ACPI code
|
||||
*
|
||||
* Copyright (C) 2014 Intel Corp
|
||||
*
|
||||
* Author: Lan Tianyu <tianyu.lan@intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
#define pr_fmt(fmt) "I2C/ACPI : " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
struct acpi_i2c_handler_data {
|
||||
struct acpi_connection_info info;
|
||||
struct i2c_adapter *adapter;
|
||||
};
|
||||
|
||||
struct gsb_buffer {
|
||||
u8 status;
|
||||
u8 len;
|
||||
union {
|
||||
u16 wdata;
|
||||
u8 bdata;
|
||||
u8 data[0];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
|
||||
{
|
||||
struct i2c_board_info *info = data;
|
||||
|
||||
if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
|
||||
struct acpi_resource_i2c_serialbus *sb;
|
||||
|
||||
sb = &ares->data.i2c_serial_bus;
|
||||
if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
|
||||
info->addr = sb->slave_address;
|
||||
if (sb->access_mode == ACPI_I2C_10BIT_MODE)
|
||||
info->flags |= I2C_CLIENT_TEN;
|
||||
}
|
||||
} else if (info->irq < 0) {
|
||||
struct resource r;
|
||||
|
||||
if (acpi_dev_resource_interrupt(ares, 0, &r))
|
||||
info->irq = r.start;
|
||||
}
|
||||
|
||||
/* Tell the ACPI core to skip this resource */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
|
||||
void *data, void **return_value)
|
||||
{
|
||||
struct i2c_adapter *adapter = data;
|
||||
struct list_head resource_list;
|
||||
struct i2c_board_info info;
|
||||
struct acpi_device *adev;
|
||||
int ret;
|
||||
|
||||
if (acpi_bus_get_device(handle, &adev))
|
||||
return AE_OK;
|
||||
if (acpi_bus_get_status(adev) || !adev->status.present)
|
||||
return AE_OK;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.acpi_node.companion = adev;
|
||||
info.irq = -1;
|
||||
|
||||
INIT_LIST_HEAD(&resource_list);
|
||||
ret = acpi_dev_get_resources(adev, &resource_list,
|
||||
acpi_i2c_add_resource, &info);
|
||||
acpi_dev_free_resource_list(&resource_list);
|
||||
|
||||
if (ret < 0 || !info.addr)
|
||||
return AE_OK;
|
||||
|
||||
adev->power.flags.ignore_parent = true;
|
||||
strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type));
|
||||
if (!i2c_new_device(adapter, &info)) {
|
||||
adev->power.flags.ignore_parent = false;
|
||||
dev_err(&adapter->dev,
|
||||
"failed to add I2C device %s from ACPI\n",
|
||||
dev_name(&adev->dev));
|
||||
}
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_i2c_register_devices - enumerate I2C slave devices behind adapter
|
||||
* @adap: pointer to adapter
|
||||
*
|
||||
* Enumerate all I2C slave devices behind this adapter by walking the ACPI
|
||||
* namespace. When a device is found it will be added to the Linux device
|
||||
* model and bound to the corresponding ACPI handle.
|
||||
*/
|
||||
void acpi_i2c_register_devices(struct i2c_adapter *adap)
|
||||
{
|
||||
acpi_handle handle;
|
||||
acpi_status status;
|
||||
|
||||
if (!adap->dev.parent)
|
||||
return;
|
||||
|
||||
handle = ACPI_HANDLE(adap->dev.parent);
|
||||
if (!handle)
|
||||
return;
|
||||
|
||||
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
|
||||
acpi_i2c_add_device, NULL,
|
||||
adap, NULL);
|
||||
if (ACPI_FAILURE(status))
|
||||
dev_warn(&adap->dev, "failed to enumerate I2C slaves\n");
|
||||
}
|
||||
|
||||
static int acpi_gsb_i2c_read_bytes(struct i2c_client *client,
|
||||
u8 cmd, u8 *data, u8 data_len)
|
||||
{
|
||||
|
||||
struct i2c_msg msgs[2];
|
||||
int ret;
|
||||
u8 *buffer;
|
||||
|
||||
buffer = kzalloc(data_len, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return AE_NO_MEMORY;
|
||||
|
||||
msgs[0].addr = client->addr;
|
||||
msgs[0].flags = client->flags;
|
||||
msgs[0].len = 1;
|
||||
msgs[0].buf = &cmd;
|
||||
|
||||
msgs[1].addr = client->addr;
|
||||
msgs[1].flags = client->flags | I2C_M_RD;
|
||||
msgs[1].len = data_len;
|
||||
msgs[1].buf = buffer;
|
||||
|
||||
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (ret < 0)
|
||||
dev_err(&client->adapter->dev, "i2c read failed\n");
|
||||
else
|
||||
memcpy(data, buffer, data_len);
|
||||
|
||||
kfree(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int acpi_gsb_i2c_write_bytes(struct i2c_client *client,
|
||||
u8 cmd, u8 *data, u8 data_len)
|
||||
{
|
||||
|
||||
struct i2c_msg msgs[1];
|
||||
u8 *buffer;
|
||||
int ret = AE_OK;
|
||||
|
||||
buffer = kzalloc(data_len + 1, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return AE_NO_MEMORY;
|
||||
|
||||
buffer[0] = cmd;
|
||||
memcpy(buffer + 1, data, data_len);
|
||||
|
||||
msgs[0].addr = client->addr;
|
||||
msgs[0].flags = client->flags;
|
||||
msgs[0].len = data_len + 1;
|
||||
msgs[0].buf = buffer;
|
||||
|
||||
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (ret < 0)
|
||||
dev_err(&client->adapter->dev, "i2c write failed\n");
|
||||
|
||||
kfree(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static acpi_status
|
||||
acpi_i2c_space_handler(u32 function, acpi_physical_address command,
|
||||
u32 bits, u64 *value64,
|
||||
void *handler_context, void *region_context)
|
||||
{
|
||||
struct gsb_buffer *gsb = (struct gsb_buffer *)value64;
|
||||
struct acpi_i2c_handler_data *data = handler_context;
|
||||
struct acpi_connection_info *info = &data->info;
|
||||
struct acpi_resource_i2c_serialbus *sb;
|
||||
struct i2c_adapter *adapter = data->adapter;
|
||||
struct i2c_client client;
|
||||
struct acpi_resource *ares;
|
||||
u32 accessor_type = function >> 16;
|
||||
u8 action = function & ACPI_IO_MASK;
|
||||
acpi_status ret = AE_OK;
|
||||
int status;
|
||||
|
||||
ret = acpi_buffer_to_resource(info->connection, info->length, &ares);
|
||||
if (ACPI_FAILURE(ret))
|
||||
return ret;
|
||||
|
||||
if (!value64 || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) {
|
||||
ret = AE_BAD_PARAMETER;
|
||||
goto err;
|
||||
}
|
||||
|
||||
sb = &ares->data.i2c_serial_bus;
|
||||
if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) {
|
||||
ret = AE_BAD_PARAMETER;
|
||||
goto err;
|
||||
}
|
||||
|
||||
memset(&client, 0, sizeof(client));
|
||||
client.adapter = adapter;
|
||||
client.addr = sb->slave_address;
|
||||
client.flags = 0;
|
||||
|
||||
if (sb->access_mode == ACPI_I2C_10BIT_MODE)
|
||||
client.flags |= I2C_CLIENT_TEN;
|
||||
|
||||
switch (accessor_type) {
|
||||
case ACPI_GSB_ACCESS_ATTRIB_SEND_RCV:
|
||||
if (action == ACPI_READ) {
|
||||
status = i2c_smbus_read_byte(&client);
|
||||
if (status >= 0) {
|
||||
gsb->bdata = status;
|
||||
status = 0;
|
||||
}
|
||||
} else {
|
||||
status = i2c_smbus_write_byte(&client, gsb->bdata);
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_GSB_ACCESS_ATTRIB_BYTE:
|
||||
if (action == ACPI_READ) {
|
||||
status = i2c_smbus_read_byte_data(&client, command);
|
||||
if (status >= 0) {
|
||||
gsb->bdata = status;
|
||||
status = 0;
|
||||
}
|
||||
} else {
|
||||
status = i2c_smbus_write_byte_data(&client, command,
|
||||
gsb->bdata);
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_GSB_ACCESS_ATTRIB_WORD:
|
||||
if (action == ACPI_READ) {
|
||||
status = i2c_smbus_read_word_data(&client, command);
|
||||
if (status >= 0) {
|
||||
gsb->wdata = status;
|
||||
status = 0;
|
||||
}
|
||||
} else {
|
||||
status = i2c_smbus_write_word_data(&client, command,
|
||||
gsb->wdata);
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_GSB_ACCESS_ATTRIB_BLOCK:
|
||||
if (action == ACPI_READ) {
|
||||
status = i2c_smbus_read_block_data(&client, command,
|
||||
gsb->data);
|
||||
if (status >= 0) {
|
||||
gsb->len = status;
|
||||
status = 0;
|
||||
}
|
||||
} else {
|
||||
status = i2c_smbus_write_block_data(&client, command,
|
||||
gsb->len, gsb->data);
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE:
|
||||
if (action == ACPI_READ) {
|
||||
status = acpi_gsb_i2c_read_bytes(&client, command,
|
||||
gsb->data, info->access_length);
|
||||
if (status > 0)
|
||||
status = 0;
|
||||
} else {
|
||||
status = acpi_gsb_i2c_write_bytes(&client, command,
|
||||
gsb->data, info->access_length);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_info("protocol(0x%02x) is not supported.\n", accessor_type);
|
||||
ret = AE_BAD_PARAMETER;
|
||||
goto err;
|
||||
}
|
||||
|
||||
gsb->status = status;
|
||||
|
||||
err:
|
||||
ACPI_FREE(ares);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int acpi_i2c_install_space_handler(struct i2c_adapter *adapter)
|
||||
{
|
||||
acpi_handle handle = ACPI_HANDLE(adapter->dev.parent);
|
||||
struct acpi_i2c_handler_data *data;
|
||||
acpi_status status;
|
||||
|
||||
if (!handle)
|
||||
return -ENODEV;
|
||||
|
||||
data = kzalloc(sizeof(struct acpi_i2c_handler_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->adapter = adapter;
|
||||
status = acpi_bus_attach_private_data(handle, (void *)data);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
kfree(data);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
status = acpi_install_address_space_handler(handle,
|
||||
ACPI_ADR_SPACE_GSBUS,
|
||||
&acpi_i2c_space_handler,
|
||||
NULL,
|
||||
data);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_err(&adapter->dev, "Error installing i2c space handler\n");
|
||||
acpi_bus_detach_private_data(handle);
|
||||
kfree(data);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter)
|
||||
{
|
||||
acpi_handle handle = ACPI_HANDLE(adapter->dev.parent);
|
||||
struct acpi_i2c_handler_data *data;
|
||||
acpi_status status;
|
||||
|
||||
if (!handle)
|
||||
return;
|
||||
|
||||
acpi_remove_address_space_handler(handle,
|
||||
ACPI_ADR_SPACE_GSBUS,
|
||||
&acpi_i2c_space_handler);
|
||||
|
||||
status = acpi_bus_get_private_data(handle, (void **)&data);
|
||||
if (ACPI_SUCCESS(status))
|
||||
kfree(data);
|
||||
|
||||
acpi_bus_detach_private_data(handle);
|
||||
}
|
@ -1097,101 +1097,6 @@ EXPORT_SYMBOL(of_find_i2c_adapter_by_node);
|
||||
static void of_i2c_register_devices(struct i2c_adapter *adap) { }
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
/* ACPI support code */
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
|
||||
{
|
||||
struct i2c_board_info *info = data;
|
||||
|
||||
if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
|
||||
struct acpi_resource_i2c_serialbus *sb;
|
||||
|
||||
sb = &ares->data.i2c_serial_bus;
|
||||
if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
|
||||
info->addr = sb->slave_address;
|
||||
if (sb->access_mode == ACPI_I2C_10BIT_MODE)
|
||||
info->flags |= I2C_CLIENT_TEN;
|
||||
}
|
||||
} else if (info->irq < 0) {
|
||||
struct resource r;
|
||||
|
||||
if (acpi_dev_resource_interrupt(ares, 0, &r))
|
||||
info->irq = r.start;
|
||||
}
|
||||
|
||||
/* Tell the ACPI core to skip this resource */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
|
||||
void *data, void **return_value)
|
||||
{
|
||||
struct i2c_adapter *adapter = data;
|
||||
struct list_head resource_list;
|
||||
struct i2c_board_info info;
|
||||
struct acpi_device *adev;
|
||||
int ret;
|
||||
|
||||
if (acpi_bus_get_device(handle, &adev))
|
||||
return AE_OK;
|
||||
if (acpi_bus_get_status(adev) || !adev->status.present)
|
||||
return AE_OK;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.acpi_node.companion = adev;
|
||||
info.irq = -1;
|
||||
|
||||
INIT_LIST_HEAD(&resource_list);
|
||||
ret = acpi_dev_get_resources(adev, &resource_list,
|
||||
acpi_i2c_add_resource, &info);
|
||||
acpi_dev_free_resource_list(&resource_list);
|
||||
|
||||
if (ret < 0 || !info.addr)
|
||||
return AE_OK;
|
||||
|
||||
adev->power.flags.ignore_parent = true;
|
||||
strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type));
|
||||
if (!i2c_new_device(adapter, &info)) {
|
||||
adev->power.flags.ignore_parent = false;
|
||||
dev_err(&adapter->dev,
|
||||
"failed to add I2C device %s from ACPI\n",
|
||||
dev_name(&adev->dev));
|
||||
}
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_i2c_register_devices - enumerate I2C slave devices behind adapter
|
||||
* @adap: pointer to adapter
|
||||
*
|
||||
* Enumerate all I2C slave devices behind this adapter by walking the ACPI
|
||||
* namespace. When a device is found it will be added to the Linux device
|
||||
* model and bound to the corresponding ACPI handle.
|
||||
*/
|
||||
static void acpi_i2c_register_devices(struct i2c_adapter *adap)
|
||||
{
|
||||
acpi_handle handle;
|
||||
acpi_status status;
|
||||
|
||||
if (!adap->dev.parent)
|
||||
return;
|
||||
|
||||
handle = ACPI_HANDLE(adap->dev.parent);
|
||||
if (!handle)
|
||||
return;
|
||||
|
||||
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
|
||||
acpi_i2c_add_device, NULL,
|
||||
adap, NULL);
|
||||
if (ACPI_FAILURE(status))
|
||||
dev_warn(&adap->dev, "failed to enumerate I2C slaves\n");
|
||||
}
|
||||
#else
|
||||
static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) {}
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
static int i2c_do_add_adapter(struct i2c_driver *driver,
|
||||
struct i2c_adapter *adap)
|
||||
{
|
||||
@ -1298,6 +1203,7 @@ exit_recovery:
|
||||
/* create pre-declared device nodes */
|
||||
of_i2c_register_devices(adap);
|
||||
acpi_i2c_register_devices(adap);
|
||||
acpi_i2c_install_space_handler(adap);
|
||||
|
||||
if (adap->nr < __i2c_first_dynamic_bus_num)
|
||||
i2c_scan_static_board_info(adap);
|
||||
@ -1471,6 +1377,7 @@ void i2c_del_adapter(struct i2c_adapter *adap)
|
||||
return;
|
||||
}
|
||||
|
||||
acpi_i2c_remove_space_handler(adap);
|
||||
/* Tell drivers about this removal */
|
||||
mutex_lock(&core_lock);
|
||||
bus_for_each_drv(&i2c_bus_type, NULL, adap,
|
||||
@ -2013,6 +1920,16 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
|
||||
if (!driver->detect || !address_list)
|
||||
return 0;
|
||||
|
||||
/* Warn that the adapter lost class based instantiation */
|
||||
if (adapter->class == I2C_CLASS_DEPRECATED) {
|
||||
dev_dbg(&adapter->dev,
|
||||
"This adapter dropped support for I2C classes and "
|
||||
"won't auto-detect %s devices anymore. If you need it, check "
|
||||
"'Documentation/i2c/instantiating-devices' for alternatives.\n",
|
||||
driver->driver.name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Stop here if the classes do not match */
|
||||
if (!(adapter->class & driver->class))
|
||||
return 0;
|
||||
|
@ -2,7 +2,7 @@
|
||||
i2c-stub.c - I2C/SMBus chip emulator
|
||||
|
||||
Copyright (c) 2004 Mark M. Hoffman <mhoffman@lightlink.com>
|
||||
Copyright (C) 2007, 2012 Jean Delvare <jdelvare@suse.de>
|
||||
Copyright (C) 2007-2014 Jean Delvare <jdelvare@suse.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -27,28 +27,109 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#define MAX_CHIPS 10
|
||||
#define STUB_FUNC (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | \
|
||||
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | \
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK)
|
||||
|
||||
/*
|
||||
* Support for I2C_FUNC_SMBUS_BLOCK_DATA is disabled by default and must
|
||||
* be enabled explicitly by setting the I2C_FUNC_SMBUS_BLOCK_DATA bits
|
||||
* in the 'functionality' module parameter.
|
||||
*/
|
||||
#define STUB_FUNC_DEFAULT \
|
||||
(I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | \
|
||||
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | \
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK)
|
||||
|
||||
#define STUB_FUNC_ALL \
|
||||
(STUB_FUNC_DEFAULT | I2C_FUNC_SMBUS_BLOCK_DATA)
|
||||
|
||||
static unsigned short chip_addr[MAX_CHIPS];
|
||||
module_param_array(chip_addr, ushort, NULL, S_IRUGO);
|
||||
MODULE_PARM_DESC(chip_addr,
|
||||
"Chip addresses (up to 10, between 0x03 and 0x77)");
|
||||
|
||||
static unsigned long functionality = STUB_FUNC;
|
||||
static unsigned long functionality = STUB_FUNC_DEFAULT;
|
||||
module_param(functionality, ulong, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(functionality, "Override functionality bitfield");
|
||||
|
||||
/* Some chips have banked register ranges */
|
||||
|
||||
static u8 bank_reg[MAX_CHIPS];
|
||||
module_param_array(bank_reg, byte, NULL, S_IRUGO);
|
||||
MODULE_PARM_DESC(bank_reg, "Bank register");
|
||||
|
||||
static u8 bank_mask[MAX_CHIPS];
|
||||
module_param_array(bank_mask, byte, NULL, S_IRUGO);
|
||||
MODULE_PARM_DESC(bank_mask, "Bank value mask");
|
||||
|
||||
static u8 bank_start[MAX_CHIPS];
|
||||
module_param_array(bank_start, byte, NULL, S_IRUGO);
|
||||
MODULE_PARM_DESC(bank_start, "First banked register");
|
||||
|
||||
static u8 bank_end[MAX_CHIPS];
|
||||
module_param_array(bank_end, byte, NULL, S_IRUGO);
|
||||
MODULE_PARM_DESC(bank_end, "Last banked register");
|
||||
|
||||
struct smbus_block_data {
|
||||
struct list_head node;
|
||||
u8 command;
|
||||
u8 len;
|
||||
u8 block[I2C_SMBUS_BLOCK_MAX];
|
||||
};
|
||||
|
||||
struct stub_chip {
|
||||
u8 pointer;
|
||||
u16 words[256]; /* Byte operations use the LSB as per SMBus
|
||||
specification */
|
||||
struct list_head smbus_blocks;
|
||||
|
||||
/* For chips with banks, extra registers are allocated dynamically */
|
||||
u8 bank_reg;
|
||||
u8 bank_shift;
|
||||
u8 bank_mask;
|
||||
u8 bank_sel; /* Currently selected bank */
|
||||
u8 bank_start;
|
||||
u8 bank_end;
|
||||
u16 bank_size;
|
||||
u16 *bank_words; /* Room for bank_mask * bank_size registers */
|
||||
};
|
||||
|
||||
static struct stub_chip *stub_chips;
|
||||
static int stub_chips_nr;
|
||||
|
||||
static struct smbus_block_data *stub_find_block(struct device *dev,
|
||||
struct stub_chip *chip,
|
||||
u8 command, bool create)
|
||||
{
|
||||
struct smbus_block_data *b, *rb = NULL;
|
||||
|
||||
list_for_each_entry(b, &chip->smbus_blocks, node) {
|
||||
if (b->command == command) {
|
||||
rb = b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rb == NULL && create) {
|
||||
rb = devm_kzalloc(dev, sizeof(*rb), GFP_KERNEL);
|
||||
if (rb == NULL)
|
||||
return rb;
|
||||
rb->command = command;
|
||||
list_add(&rb->node, &chip->smbus_blocks);
|
||||
}
|
||||
return rb;
|
||||
}
|
||||
|
||||
static u16 *stub_get_wordp(struct stub_chip *chip, u8 offset)
|
||||
{
|
||||
if (chip->bank_sel &&
|
||||
offset >= chip->bank_start && offset <= chip->bank_end)
|
||||
return chip->bank_words +
|
||||
(chip->bank_sel - 1) * chip->bank_size +
|
||||
offset - chip->bank_start;
|
||||
else
|
||||
return chip->words + offset;
|
||||
}
|
||||
|
||||
/* Return negative errno on error. */
|
||||
static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
|
||||
@ -57,9 +138,11 @@ static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
|
||||
s32 ret;
|
||||
int i, len;
|
||||
struct stub_chip *chip = NULL;
|
||||
struct smbus_block_data *b;
|
||||
u16 *wordp;
|
||||
|
||||
/* Search for the right chip */
|
||||
for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) {
|
||||
for (i = 0; i < stub_chips_nr; i++) {
|
||||
if (addr == chip_addr[i]) {
|
||||
chip = stub_chips + i;
|
||||
break;
|
||||
@ -82,7 +165,8 @@ static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
|
||||
"smbus byte - addr 0x%02x, wrote 0x%02x.\n",
|
||||
addr, command);
|
||||
} else {
|
||||
data->byte = chip->words[chip->pointer++] & 0xff;
|
||||
wordp = stub_get_wordp(chip, chip->pointer++);
|
||||
data->byte = *wordp & 0xff;
|
||||
dev_dbg(&adap->dev,
|
||||
"smbus byte - addr 0x%02x, read 0x%02x.\n",
|
||||
addr, data->byte);
|
||||
@ -92,14 +176,25 @@ static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
wordp = stub_get_wordp(chip, command);
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
chip->words[command] &= 0xff00;
|
||||
chip->words[command] |= data->byte;
|
||||
*wordp &= 0xff00;
|
||||
*wordp |= data->byte;
|
||||
dev_dbg(&adap->dev,
|
||||
"smbus byte data - addr 0x%02x, wrote 0x%02x at 0x%02x.\n",
|
||||
addr, data->byte, command);
|
||||
|
||||
/* Set the bank as needed */
|
||||
if (chip->bank_words && command == chip->bank_reg) {
|
||||
chip->bank_sel =
|
||||
(data->byte >> chip->bank_shift)
|
||||
& chip->bank_mask;
|
||||
dev_dbg(&adap->dev,
|
||||
"switching to bank %u.\n",
|
||||
chip->bank_sel);
|
||||
}
|
||||
} else {
|
||||
data->byte = chip->words[command] & 0xff;
|
||||
data->byte = *wordp & 0xff;
|
||||
dev_dbg(&adap->dev,
|
||||
"smbus byte data - addr 0x%02x, read 0x%02x at 0x%02x.\n",
|
||||
addr, data->byte, command);
|
||||
@ -110,13 +205,14 @@ static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
wordp = stub_get_wordp(chip, command);
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
chip->words[command] = data->word;
|
||||
*wordp = data->word;
|
||||
dev_dbg(&adap->dev,
|
||||
"smbus word data - addr 0x%02x, wrote 0x%04x at 0x%02x.\n",
|
||||
addr, data->word, command);
|
||||
} else {
|
||||
data->word = chip->words[command];
|
||||
data->word = *wordp;
|
||||
dev_dbg(&adap->dev,
|
||||
"smbus word data - addr 0x%02x, read 0x%04x at 0x%02x.\n",
|
||||
addr, data->word, command);
|
||||
@ -126,6 +222,12 @@ static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||
/*
|
||||
* We ignore banks here, because banked chips don't use I2C
|
||||
* block transfers
|
||||
*/
|
||||
if (data->block[0] > 256 - command) /* Avoid overrun */
|
||||
data->block[0] = 256 - command;
|
||||
len = data->block[0];
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
for (i = 0; i < len; i++) {
|
||||
@ -148,6 +250,55 @@ static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
/*
|
||||
* We ignore banks here, because chips typically don't use both
|
||||
* banks and SMBus block transfers
|
||||
*/
|
||||
b = stub_find_block(&adap->dev, chip, command, false);
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
len = data->block[0];
|
||||
if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (b == NULL) {
|
||||
b = stub_find_block(&adap->dev, chip, command,
|
||||
true);
|
||||
if (b == NULL) {
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Largest write sets read block length */
|
||||
if (len > b->len)
|
||||
b->len = len;
|
||||
for (i = 0; i < len; i++)
|
||||
b->block[i] = data->block[i + 1];
|
||||
/* update for byte and word commands */
|
||||
chip->words[command] = (b->block[0] << 8) | b->len;
|
||||
dev_dbg(&adap->dev,
|
||||
"smbus block data - addr 0x%02x, wrote %d bytes at 0x%02x.\n",
|
||||
addr, len, command);
|
||||
} else {
|
||||
if (b == NULL) {
|
||||
dev_dbg(&adap->dev,
|
||||
"SMBus block read command without prior block write not supported\n");
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
len = b->len;
|
||||
data->block[0] = len;
|
||||
for (i = 0; i < len; i++)
|
||||
data->block[i + 1] = b->block[i];
|
||||
dev_dbg(&adap->dev,
|
||||
"smbus block data - addr 0x%02x, read %d bytes at 0x%02x.\n",
|
||||
addr, len, command);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_dbg(&adap->dev, "Unsupported I2C/SMBus command\n");
|
||||
ret = -EOPNOTSUPP;
|
||||
@ -159,7 +310,7 @@ static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
|
||||
|
||||
static u32 stub_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return STUB_FUNC & functionality;
|
||||
return STUB_FUNC_ALL & functionality;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm smbus_algorithm = {
|
||||
@ -174,6 +325,43 @@ static struct i2c_adapter stub_adapter = {
|
||||
.name = "SMBus stub driver",
|
||||
};
|
||||
|
||||
static int __init i2c_stub_allocate_banks(int i)
|
||||
{
|
||||
struct stub_chip *chip = stub_chips + i;
|
||||
|
||||
chip->bank_reg = bank_reg[i];
|
||||
chip->bank_start = bank_start[i];
|
||||
chip->bank_end = bank_end[i];
|
||||
chip->bank_size = bank_end[i] - bank_start[i] + 1;
|
||||
|
||||
/* We assume that all bits in the mask are contiguous */
|
||||
chip->bank_mask = bank_mask[i];
|
||||
while (!(chip->bank_mask & 1)) {
|
||||
chip->bank_shift++;
|
||||
chip->bank_mask >>= 1;
|
||||
}
|
||||
|
||||
chip->bank_words = kzalloc(chip->bank_mask * chip->bank_size *
|
||||
sizeof(u16), GFP_KERNEL);
|
||||
if (!chip->bank_words)
|
||||
return -ENOMEM;
|
||||
|
||||
pr_debug("i2c-stub: Allocated %u banks of %u words each (registers 0x%02x to 0x%02x)\n",
|
||||
chip->bank_mask, chip->bank_size, chip->bank_start,
|
||||
chip->bank_end);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void i2c_stub_free(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < stub_chips_nr; i++)
|
||||
kfree(stub_chips[i].bank_words);
|
||||
kfree(stub_chips);
|
||||
}
|
||||
|
||||
static int __init i2c_stub_init(void)
|
||||
{
|
||||
int i, ret;
|
||||
@ -194,22 +382,39 @@ static int __init i2c_stub_init(void)
|
||||
}
|
||||
|
||||
/* Allocate memory for all chips at once */
|
||||
stub_chips = kzalloc(i * sizeof(struct stub_chip), GFP_KERNEL);
|
||||
stub_chips_nr = i;
|
||||
stub_chips = kcalloc(stub_chips_nr, sizeof(struct stub_chip),
|
||||
GFP_KERNEL);
|
||||
if (!stub_chips) {
|
||||
pr_err("i2c-stub: Out of memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
for (i = 0; i < stub_chips_nr; i++) {
|
||||
INIT_LIST_HEAD(&stub_chips[i].smbus_blocks);
|
||||
|
||||
/* Allocate extra memory for banked register ranges */
|
||||
if (bank_mask[i]) {
|
||||
ret = i2c_stub_allocate_banks(i);
|
||||
if (ret)
|
||||
goto fail_free;
|
||||
}
|
||||
}
|
||||
|
||||
ret = i2c_add_adapter(&stub_adapter);
|
||||
if (ret)
|
||||
kfree(stub_chips);
|
||||
goto fail_free;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_free:
|
||||
i2c_stub_free();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit i2c_stub_exit(void)
|
||||
{
|
||||
i2c_del_adapter(&stub_adapter);
|
||||
kfree(stub_chips);
|
||||
i2c_stub_free();
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <linux/i2c-mux.h>
|
||||
#include <linux/i2c/pca954x.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define PCA954X_MAX_NCHANS 8
|
||||
@ -273,9 +274,23 @@ static int pca954x_remove(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int pca954x_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pca954x *data = i2c_get_clientdata(client);
|
||||
|
||||
data->last_chan = 0;
|
||||
return i2c_smbus_write_byte(client, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pca954x_pm, NULL, pca954x_resume);
|
||||
|
||||
static struct i2c_driver pca954x_driver = {
|
||||
.driver = {
|
||||
.name = "pca954x",
|
||||
.pm = &pca954x_pm,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = pca954x_probe,
|
||||
|
@ -364,6 +364,17 @@ extern bool osc_sb_apei_support_acked;
|
||||
#define OSC_PCI_EXPRESS_CAPABILITY_CONTROL 0x00000010
|
||||
#define OSC_PCI_CONTROL_MASKS 0x0000001f
|
||||
|
||||
#define ACPI_GSB_ACCESS_ATTRIB_QUICK 0x00000002
|
||||
#define ACPI_GSB_ACCESS_ATTRIB_SEND_RCV 0x00000004
|
||||
#define ACPI_GSB_ACCESS_ATTRIB_BYTE 0x00000006
|
||||
#define ACPI_GSB_ACCESS_ATTRIB_WORD 0x00000008
|
||||
#define ACPI_GSB_ACCESS_ATTRIB_BLOCK 0x0000000A
|
||||
#define ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE 0x0000000B
|
||||
#define ACPI_GSB_ACCESS_ATTRIB_WORD_CALL 0x0000000C
|
||||
#define ACPI_GSB_ACCESS_ATTRIB_BLOCK_CALL 0x0000000D
|
||||
#define ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES 0x0000000E
|
||||
#define ACPI_GSB_ACCESS_ATTRIB_RAW_PROCESS 0x0000000F
|
||||
|
||||
extern acpi_status acpi_pci_osc_control_set(acpi_handle handle,
|
||||
u32 *mask, u32 req);
|
||||
|
||||
|
@ -577,4 +577,16 @@ static inline struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
#ifdef CONFIG_I2C_ACPI
|
||||
int acpi_i2c_install_space_handler(struct i2c_adapter *adapter);
|
||||
void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter);
|
||||
void acpi_i2c_register_devices(struct i2c_adapter *adap);
|
||||
#else
|
||||
static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) { }
|
||||
static inline void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter)
|
||||
{ }
|
||||
static inline int acpi_i2c_install_space_handler(struct i2c_adapter *adapter)
|
||||
{ return 0; }
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_I2C_H */
|
||||
|
@ -1,10 +0,0 @@
|
||||
#ifndef __LINUX_I2C_S6000_H
|
||||
#define __LINUX_I2C_S6000_H
|
||||
|
||||
struct s6_i2c_platform_data {
|
||||
const char *clock; /* the clock to use */
|
||||
int bus_num; /* the bus number to register */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user