Merge branch 'i2c/for-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang:
"Here is the I2C pull request for 4.8:
- the core and i801 driver gained support for SMBus Host Notify
- core support for more than one address in DT
- i2c_add_adapter() has now better error messages. We can remove all
error messages from drivers calling it as a next step.
- bigger updates to rk3x driver to support rk3399 SoC
- the at24 eeprom driver got refactored and can now read special
variants with unique serials or fixed MAC addresses.
The rest is regular driver updates and bugfixes"
* 'i2c/for-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (66 commits)
i2c: i801: use IS_ENABLED() instead of checking for built-in or module
Documentation: i2c: slave: give proper example for pm usage
Documentation: i2c: slave: describe buffer problems a bit better
i2c: bcm2835: Don't complain on -EPROBE_DEFER from getting our clock
i2c: i2c-smbus: drop useless stubs
i2c: efm32: fix a failure path in efm32_i2c_probe()
Revert "i2c: core: Cleanup I2C ACPI namespace"
Revert "i2c: core: Add function for finding the bus speed from ACPI"
i2c: Update the description of I2C_SMBUS
i2c: i2c-smbus: fix i2c_handle_smbus_host_notify documentation
eeprom: at24: tweak the loop_until_timeout() macro
eeprom: at24: add support for at24mac series
eeprom: at24: support reading the serial number for 24csxx
eeprom: at24: platform_data: use BIT() macro
eeprom: at24: split at24_eeprom_write() into specialized functions
eeprom: at24: split at24_eeprom_read() into specialized functions
eeprom: at24: hide the read/write loop behind a macro
eeprom: at24: call read/write functions via function pointers
eeprom: at24: coding style fixes
eeprom: at24: move at24_read() below at24_eeprom_write()
...
diff --git a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
index 0b4a85f..bbc5a1e 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
@@ -6,10 +6,20 @@
Required properties :
- reg : Offset and length of the register set for the device
- - compatible : should be "rockchip,rk3066-i2c", "rockchip,rk3188-i2c",
- "rockchip,rk3228-i2c" or "rockchip,rk3288-i2c".
+ - compatible: should be one of the following:
+ - "rockchip,rk3066-i2c": for rk3066
+ - "rockchip,rk3188-i2c": for rk3188
+ - "rockchip,rk3228-i2c": for rk3228
+ - "rockchip,rk3288-i2c": for rk3288
+ - "rockchip,rk3399-i2c": for rk3399
- interrupts : interrupt number
- - clocks : parent clock
+ - clocks: See ../clock/clock-bindings.txt
+ - For older hardware (rk3066, rk3188, rk3228, rk3288):
+ - There is one clock that's used both to derive the functional clock
+ for the device and as the bus clock.
+ - For newer hardware (rk3399): specified by name
+ - "i2c": This is used to derive the functional clock.
+ - "pclk": This is the bus clock.
Required on RK3066, RK3188 :
diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt
index c8d977e..f31b2ad 100644
--- a/Documentation/devicetree/bindings/i2c/i2c.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c.txt
@@ -62,6 +62,13 @@
- wakeup-source
device can be used as a wakeup source.
+- reg
+ I2C slave addresses
+
+- reg-names
+ Names of map programmable addresses.
+ It can contain any map needing another address than default one.
+
Binding may contain optional "interrupts" property, describing interrupts
used by the device. I2C core will assign "irq" interrupt (or the very first
interrupt if not using interrupt names) as primary interrupt for the slave.
diff --git a/Documentation/i2c/slave-interface b/Documentation/i2c/slave-interface
index 61ed05c..80807ad 100644
--- a/Documentation/i2c/slave-interface
+++ b/Documentation/i2c/slave-interface
@@ -139,9 +139,9 @@
* implement calls to register/unregister the slave and add those to the
struct i2c_algorithm. When registering, you probably need to set the i2c
slave address and enable slave specific interrupts. If you use runtime pm, you
- should use pm_runtime_forbid() because your device usually needs to be powered
- on always to be able to detect its slave address. When unregistering, do the
- inverse of the above.
+ should use pm_runtime_get_sync() because your device usually needs to be
+ powered on always to be able to detect its slave address. When unregistering,
+ do the inverse of the above.
* Catch the slave interrupts and send appropriate i2c_slave_events to the backend.
@@ -173,13 +173,14 @@
bytes came up. Such an extension might be possible, usefulness is unclear at
this time of writing. Some points to keep in mind when using buffers:
-* Buffers should be opt-in and slave drivers will always have to support
- byte-based transactions as the ultimate fallback because this is how the
- majority of HW works.
+* Buffers should be opt-in and backend drivers will always have to support
+ byte-based transactions as the ultimate fallback anyhow because this is how
+ the majority of HW works.
-* For backends simulating hardware registers, buffers are not helpful because
- on writes an action should be immediately triggered. For reads, the data in
- the buffer might get stale.
+* For backends simulating hardware registers, buffers are largely not helpful
+ because after each byte written an action should be immediately triggered.
+ For reads, the data kept in the buffer might get stale if the backend just
+ updated a register because of internal processing.
* A master can send STOP at any time. For partially transferred buffers, this
means additional code to handle this exception. Such code tends to be
diff --git a/Documentation/i2c/smbus-protocol b/Documentation/i2c/smbus-protocol
index 6012b12..14d4ec1 100644
--- a/Documentation/i2c/smbus-protocol
+++ b/Documentation/i2c/smbus-protocol
@@ -199,6 +199,12 @@
[S] [HostAddr] [Wr] A [DevAddr] A [DataLow] A [DataHigh] A [P]
+This is implemented in the following way in the Linux kernel:
+* I2C bus drivers which support SMBus Host Notify should call
+ i2c_setup_smbus_host_notify() to setup SMBus Host Notify support.
+* I2C drivers for devices which can trigger SMBus Host Notify should implement
+ the optional alert() callback.
+
Packet Error Checking (PEC)
===========================
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index 097c868..5673fff 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -568,12 +568,16 @@
}
-static void ssif_alert(struct i2c_client *client, unsigned int data)
+static void ssif_alert(struct i2c_client *client, enum i2c_alert_protocol type,
+ unsigned int data)
{
struct ssif_info *ssif_info = i2c_get_clientdata(client);
unsigned long oflags, *flags;
bool do_get = false;
+ if (type != I2C_PROTOCOL_SMBUS_ALERT)
+ return;
+
ssif_inc_stat(ssif_info, alerts);
flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index f51e758..1e82374 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -1719,10 +1719,14 @@
return 0;
}
-static void lm90_alert(struct i2c_client *client, unsigned int flag)
+static void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type,
+ unsigned int flag)
{
u16 alarms;
+ if (type != I2C_PROTOCOL_SMBUS_ALERT)
+ return;
+
if (lm90_is_tripped(client, &alarms)) {
/*
* Disable ALERT# output, because these chips don't implement
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 78fbee4..d223650 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -88,8 +88,8 @@
tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO
help
Say Y here if you want support for SMBus extensions to the I2C
- specification. At the moment, the only supported extension is
- the SMBus alert protocol.
+ specification. At the moment, two extensions are supported:
+ the SMBus Alert protocol and the SMBus Host Notify protocol.
This support is also available as a module. If so, the module
will be called i2c-smbus.
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index f167021..5c3993b 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -91,6 +91,7 @@
tristate "Intel 82801 (ICH/PCH)"
depends on PCI
select CHECK_SIGNATURE if X86 && DMI
+ select I2C_SMBUS
help
If you say yes to this option, support will be included for the Intel
801 family of mainboard I2C interfaces. Specifically, the following
@@ -397,7 +398,7 @@
config I2C_BRCMSTB
tristate "BRCM Settop I2C controller"
- depends on ARCH_BRCMSTB || COMPILE_TEST
+ depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
default y
help
If you say yes to this option, support will be included for the
@@ -490,7 +491,9 @@
config I2C_DESIGNWARE_BAYTRAIL
bool "Intel Baytrail I2C semaphore support"
- depends on I2C_DESIGNWARE_PLATFORM && IOSF_MBI=y && ACPI
+ depends on ACPI
+ depends on (I2C_DESIGNWARE_PLATFORM=m && IOSF_MBI) || \
+ (I2C_DESIGNWARE_PLATFORM=y && IOSF_MBI=y)
help
This driver enables managed host access to the PMIC I2C bus on select
Intel BayTrail platforms using the X-Powers AXP288 PMIC. It allows
@@ -635,7 +638,7 @@
config I2C_MESON
tristate "Amlogic Meson I2C controller"
- depends on ARCH_MESON
+ depends on ARCH_MESON || COMPILE_TEST
help
If you say yes to this option, support will be included for the
I2C interface on the Amlogic Meson family of SoCs.
@@ -924,7 +927,7 @@
config I2C_VERSATILE
tristate "ARM Versatile/Realview I2C bus support"
- depends on ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS
+ depends on ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS || COMPILE_TEST
select I2C_ALGOBIT
help
Say yes if you want to support the I2C serial bus on ARMs Versatile
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index 818b051..d4f3239 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -253,7 +253,8 @@
i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(i2c_dev->clk)) {
- dev_err(&pdev->dev, "Could not get clock\n");
+ if (PTR_ERR(i2c_dev->clk) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Could not get clock\n");
return PTR_ERR(i2c_dev->clk);
}
diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c
index 6a8cfc1..3f5a4d7 100644
--- a/drivers/i2c/busses/i2c-brcmstb.c
+++ b/drivers/i2c/busses/i2c-brcmstb.c
@@ -343,10 +343,9 @@
struct bsc_regs *pi2creg = dev->bsc_regmap;
int no_ack = pmsg->flags & I2C_M_IGNORE_NAK;
int data_regsz = brcmstb_i2c_get_data_regsz(dev);
- int xfersz = brcmstb_i2c_get_xfersz(dev);
/* see if the transaction needs to check NACK conditions */
- if (no_ack || len <= xfersz) {
+ if (no_ack) {
cmd = (pmsg->flags & I2C_M_RD) ? CMD_RD_NOACK
: CMD_WR_NOACK;
pi2creg->ctlhi_reg |= BSC_CTLHI_REG_IGNORE_ACK_MASK;
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index 99b54be..c6922b8 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -663,7 +663,7 @@
i2c_dw_xfer_init(dev);
/* wait for tx to complete */
- if (!wait_for_completion_timeout(&dev->cmd_complete, HZ)) {
+ if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) {
dev_err(dev->dev, "controller timed out\n");
/* i2c_dw_init implicitly disables the adapter */
i2c_dw_init(dev);
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index cd409e7..38493a7 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -26,6 +26,7 @@
#define DW_IC_CON_MASTER 0x1
#define DW_IC_CON_SPEED_STD 0x2
#define DW_IC_CON_SPEED_FAST 0x4
+#define DW_IC_CON_SPEED_MASK 0x6
#define DW_IC_CON_10BITADDR_MASTER 0x10
#define DW_IC_CON_RESTART_EN 0x20
#define DW_IC_CON_SLAVE_DISABLE 0x40
diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
index 7368be0..96f8230 100644
--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
+++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
@@ -6,7 +6,7 @@
* Copyright (C) 2006 Texas Instruments.
* Copyright (C) 2007 MontaVista Software Inc.
* Copyright (C) 2009 Provigent Ltd.
- * Copyright (C) 2011, 2015 Intel Corporation.
+ * Copyright (C) 2011, 2015, 2016 Intel Corporation.
*
* ----------------------------------------------------------------------------
*
@@ -23,31 +23,27 @@
*
*/
-#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/acpi.h>
#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
-#include <linux/acpi.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
#include "i2c-designware-core.h"
#define DRIVER_NAME "i2c-designware-pci"
enum dw_pci_ctl_id_t {
- medfield_0,
- medfield_1,
- medfield_2,
- medfield_3,
- medfield_4,
- medfield_5,
-
+ medfield,
+ merrifield,
baytrail,
haswell,
};
@@ -68,6 +64,7 @@
u32 clk_khz;
u32 functionality;
struct dw_scl_sda_cfg *scl_sda_cfg;
+ int (*setup)(struct pci_dev *pdev, struct dw_pci_controller *c);
};
#define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \
@@ -80,6 +77,14 @@
I2C_FUNC_SMBUS_WORD_DATA | \
I2C_FUNC_SMBUS_I2C_BLOCK)
+/* Merrifield HCNT/LCNT/SDA hold time */
+static struct dw_scl_sda_cfg mrfld_config = {
+ .ss_hcnt = 0x2f8,
+ .fs_hcnt = 0x87,
+ .ss_lcnt = 0x37b,
+ .fs_lcnt = 0x10a,
+};
+
/* BayTrail HCNT/LCNT/SDA hold time */
static struct dw_scl_sda_cfg byt_config = {
.ss_hcnt = 0x200,
@@ -98,48 +103,60 @@
.sda_hold = 0x9,
};
+static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
+{
+ switch (pdev->device) {
+ case 0x0817:
+ c->bus_cfg &= ~DW_IC_CON_SPEED_MASK;
+ c->bus_cfg |= DW_IC_CON_SPEED_STD;
+ case 0x0818:
+ case 0x0819:
+ c->bus_num = pdev->device - 0x817 + 3;
+ return 0;
+ case 0x082C:
+ case 0x082D:
+ case 0x082E:
+ c->bus_num = pdev->device - 0x82C + 0;
+ return 0;
+ }
+ return -ENODEV;
+}
+
+static int mrfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
+{
+ /*
+ * On Intel Merrifield the user visible i2c busses are enumerated
+ * [1..7]. So, we add 1 to shift the default range. Besides that the
+ * first PCI slot provides 4 functions, that's why we have to add 0 to
+ * the first slot and 4 to the next one.
+ */
+ switch (PCI_SLOT(pdev->devfn)) {
+ case 8:
+ c->bus_num = PCI_FUNC(pdev->devfn) + 0 + 1;
+ return 0;
+ case 9:
+ c->bus_num = PCI_FUNC(pdev->devfn) + 4 + 1;
+ return 0;
+ }
+ return -ENODEV;
+}
+
static struct dw_pci_controller dw_pci_controllers[] = {
- [medfield_0] = {
- .bus_num = 0,
+ [medfield] = {
+ .bus_num = -1,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
+ .setup = mfld_setup,
},
- [medfield_1] = {
- .bus_num = 1,
- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
- },
- [medfield_2] = {
- .bus_num = 2,
- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
- },
- [medfield_3] = {
- .bus_num = 3,
- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_STD,
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
- },
- [medfield_4] = {
- .bus_num = 4,
- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
- },
- [medfield_5] = {
- .bus_num = 5,
- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
+ [merrifield] = {
+ .bus_num = -1,
+ .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+ .tx_fifo_depth = 64,
+ .rx_fifo_depth = 64,
+ .scl_sda_cfg = &mrfld_config,
+ .setup = mrfld_setup,
},
[baytrail] = {
.bus_num = -1,
@@ -190,7 +207,7 @@
struct dw_i2c_dev *dev;
struct i2c_adapter *adap;
int r;
- struct dw_pci_controller *controller;
+ struct dw_pci_controller *controller;
struct dw_scl_sda_cfg *cfg;
if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) {
@@ -224,6 +241,13 @@
dev->base = pcim_iomap_table(pdev)[0];
dev->dev = &pdev->dev;
dev->irq = pdev->irq;
+
+ if (controller->setup) {
+ r = controller->setup(pdev, controller);
+ if (r)
+ return r;
+ }
+
dev->functionality = controller->functionality |
DW_DEFAULT_FUNCTIONALITY;
@@ -276,12 +300,15 @@
static const struct pci_device_id i2_designware_pci_ids[] = {
/* Medfield */
- { PCI_VDEVICE(INTEL, 0x0817), medfield_3 },
- { PCI_VDEVICE(INTEL, 0x0818), medfield_4 },
- { PCI_VDEVICE(INTEL, 0x0819), medfield_5 },
- { PCI_VDEVICE(INTEL, 0x082C), medfield_0 },
- { PCI_VDEVICE(INTEL, 0x082D), medfield_1 },
- { PCI_VDEVICE(INTEL, 0x082E), medfield_2 },
+ { PCI_VDEVICE(INTEL, 0x0817), medfield },
+ { PCI_VDEVICE(INTEL, 0x0818), medfield },
+ { PCI_VDEVICE(INTEL, 0x0819), medfield },
+ { PCI_VDEVICE(INTEL, 0x082C), medfield },
+ { PCI_VDEVICE(INTEL, 0x082D), medfield },
+ { PCI_VDEVICE(INTEL, 0x082E), medfield },
+ /* Merrifield */
+ { PCI_VDEVICE(INTEL, 0x1195), merrifield },
+ { PCI_VDEVICE(INTEL, 0x1196), merrifield },
/* Baytrail */
{ PCI_VDEVICE(INTEL, 0x0F41), baytrail },
{ PCI_VDEVICE(INTEL, 0x0F42), baytrail },
diff --git a/drivers/i2c/busses/i2c-efm32.c b/drivers/i2c/busses/i2c-efm32.c
index 8eff627..e253598 100644
--- a/drivers/i2c/busses/i2c-efm32.c
+++ b/drivers/i2c/busses/i2c-efm32.c
@@ -433,7 +433,7 @@
ret = request_irq(ddata->irq, efm32_i2c_irq, 0, DRIVER_NAME, ddata);
if (ret < 0) {
dev_err(&pdev->dev, "failed to request irq (%d)\n", ret);
- return ret;
+ goto err_disable_clk;
}
ret = i2c_add_adapter(&ddata->adapter);
diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c
index 92e8c0c..8af62fb 100644
--- a/drivers/i2c/busses/i2c-elektor.c
+++ b/drivers/i2c/busses/i2c-elektor.c
@@ -319,16 +319,6 @@
},
};
-static int __init i2c_pcfisa_init(void)
-{
- return isa_register_driver(&i2c_elektor_driver, 1);
-}
-
-static void __exit i2c_pcfisa_exit(void)
-{
- isa_unregister_driver(&i2c_elektor_driver);
-}
-
MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter");
MODULE_LICENSE("GPL");
@@ -338,6 +328,4 @@
module_param(clock, int, 0);
module_param(own, int, 0);
module_param(mmapped, int, 0);
-
-module_init(i2c_pcfisa_init);
-module_exit(i2c_pcfisa_exit);
+module_isa_driver(i2c_elektor_driver, 1);
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 4a60ad2..5ef9b73 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -72,6 +72,7 @@
* Block process call transaction no
* I2C block read transaction yes (doesn't use the block buffer)
* Slave mode no
+ * SMBus Host Notify yes
* Interrupt processing yes
*
* See the file Documentation/i2c/busses/i2c-i801 for details.
@@ -86,6 +87,7 @@
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/i2c.h>
+#include <linux/i2c-smbus.h>
#include <linux/acpi.h>
#include <linux/io.h>
#include <linux/dmi.h>
@@ -96,8 +98,7 @@
#include <linux/platform_data/itco_wdt.h>
#include <linux/pm_runtime.h>
-#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \
- defined CONFIG_DMI
+#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
#include <linux/gpio.h>
#include <linux/i2c-mux-gpio.h>
#endif
@@ -113,6 +114,10 @@
#define SMBPEC(p) (8 + (p)->smba) /* ICH3 and later */
#define SMBAUXSTS(p) (12 + (p)->smba) /* ICH4 and later */
#define SMBAUXCTL(p) (13 + (p)->smba) /* ICH4 and later */
+#define SMBSLVSTS(p) (16 + (p)->smba) /* ICH3 and later */
+#define SMBSLVCMD(p) (17 + (p)->smba) /* ICH3 and later */
+#define SMBNTFDADD(p) (20 + (p)->smba) /* ICH3 and later */
+#define SMBNTFDDAT(p) (22 + (p)->smba) /* ICH3 and later */
/* PCI Address Constants */
#define SMBBAR 4
@@ -144,6 +149,10 @@
/* TCO configuration bits for TCOCTL */
#define TCOCTL_EN 0x0100
+/* Auxiliary status register bits, ICH4+ only */
+#define SMBAUXSTS_CRCE 1
+#define SMBAUXSTS_STCO 2
+
/* Auxiliary control register bits, ICH4+ only */
#define SMBAUXCTL_CRC 1
#define SMBAUXCTL_E32B 2
@@ -177,6 +186,12 @@
#define SMBHSTSTS_INTR 0x02
#define SMBHSTSTS_HOST_BUSY 0x01
+/* Host Notify Status registers bits */
+#define SMBSLVSTS_HST_NTFY_STS 1
+
+/* Host Notify Command registers bits */
+#define SMBSLVCMD_HST_NTFY_INTREN 0x01
+
#define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | \
SMBHSTSTS_DEV_ERR)
@@ -239,8 +254,7 @@
int len;
u8 *data;
-#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \
- defined CONFIG_DMI
+#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
const struct i801_mux_config *mux_drvdata;
struct platform_device *mux_pdev;
#endif
@@ -252,13 +266,17 @@
*/
bool acpi_reserved;
struct mutex acpi_lock;
+ struct smbus_host_notify *host_notify;
};
+#define SMBHSTNTFY_SIZE 8
+
#define FEATURE_SMBUS_PEC (1 << 0)
#define FEATURE_BLOCK_BUFFER (1 << 1)
#define FEATURE_BLOCK_PROC (1 << 2)
#define FEATURE_I2C_BLOCK_READ (1 << 3)
#define FEATURE_IRQ (1 << 4)
+#define FEATURE_HOST_NOTIFY (1 << 5)
/* Not really a feature, but it's convenient to handle it as such */
#define FEATURE_IDF (1 << 15)
#define FEATURE_TCO (1 << 16)
@@ -269,6 +287,7 @@
"Block process call",
"I2C block read",
"Interrupt",
+ "SMBus Host Notify",
};
static unsigned int disable_features;
@@ -277,7 +296,8 @@
"\t\t 0x01 disable SMBus PEC\n"
"\t\t 0x02 disable the block buffer\n"
"\t\t 0x08 disable the I2C block read functionality\n"
- "\t\t 0x10 don't use interrupts ");
+ "\t\t 0x10 don't use interrupts\n"
+ "\t\t 0x20 disable SMBus Host Notify ");
/* Make sure the SMBus host is ready to start transmitting.
Return 0 if it is, -EBUSY if it is not. */
@@ -305,6 +325,29 @@
}
}
+ /*
+ * Clear CRC status if needed.
+ * During normal operation, i801_check_post() takes care
+ * of it after every operation. We do it here only in case
+ * the hardware was already in this state when the driver
+ * started.
+ */
+ if (priv->features & FEATURE_SMBUS_PEC) {
+ status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE;
+ if (status) {
+ dev_dbg(&priv->pci_dev->dev,
+ "Clearing aux status flags (%02x)\n", status);
+ outb_p(status, SMBAUXSTS(priv));
+ status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE;
+ if (status) {
+ dev_err(&priv->pci_dev->dev,
+ "Failed clearing aux status flags (%02x)\n",
+ status);
+ return -EBUSY;
+ }
+ }
+ }
+
return 0;
}
@@ -348,8 +391,30 @@
dev_err(&priv->pci_dev->dev, "Transaction failed\n");
}
if (status & SMBHSTSTS_DEV_ERR) {
- result = -ENXIO;
- dev_dbg(&priv->pci_dev->dev, "No response\n");
+ /*
+ * This may be a PEC error, check and clear it.
+ *
+ * AUXSTS is handled differently from HSTSTS.
+ * For HSTSTS, i801_isr() or i801_wait_intr()
+ * has already cleared the error bits in hardware,
+ * and we are passed a copy of the original value
+ * in "status".
+ * For AUXSTS, the hardware register is left
+ * for us to handle here.
+ * This is asymmetric, slightly iffy, but safe,
+ * since all this code is serialized and the CRCE
+ * bit is harmless as long as it's cleared before
+ * the next operation.
+ */
+ if ((priv->features & FEATURE_SMBUS_PEC) &&
+ (inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE)) {
+ outb_p(SMBAUXSTS_CRCE, SMBAUXSTS(priv));
+ result = -EBADMSG;
+ dev_dbg(&priv->pci_dev->dev, "PEC error\n");
+ } else {
+ result = -ENXIO;
+ dev_dbg(&priv->pci_dev->dev, "No response\n");
+ }
}
if (status & SMBHSTSTS_BUS_ERR) {
result = -EAGAIN;
@@ -511,8 +576,23 @@
outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
}
+static irqreturn_t i801_host_notify_isr(struct i801_priv *priv)
+{
+ unsigned short addr;
+ unsigned int data;
+
+ addr = inb_p(SMBNTFDADD(priv)) >> 1;
+ data = inw_p(SMBNTFDDAT(priv));
+
+ i2c_handle_smbus_host_notify(priv->host_notify, addr, data);
+
+ /* clear Host Notify bit and return */
+ outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv));
+ return IRQ_HANDLED;
+}
+
/*
- * There are two kinds of interrupts:
+ * There are three kinds of interrupts:
*
* 1) i801 signals transaction completion with one of these interrupts:
* INTR - Success
@@ -524,6 +604,8 @@
*
* 2) For byte-by-byte (I2C read/write) transactions, one BYTE_DONE interrupt
* occurs for each byte of a byte-by-byte to prepare the next byte.
+ *
+ * 3) Host Notify interrupts
*/
static irqreturn_t i801_isr(int irq, void *dev_id)
{
@@ -536,6 +618,12 @@
if (!(pcists & SMBPCISTS_INTS))
return IRQ_NONE;
+ if (priv->features & FEATURE_HOST_NOTIFY) {
+ status = inb_p(SMBSLVSTS(priv));
+ if (status & SMBSLVSTS_HST_NTFY_STS)
+ return i801_host_notify_isr(priv);
+ }
+
status = inb_p(SMBHSTSTS(priv));
if (status & SMBHSTSTS_BYTE_DONE)
i801_isr_byte_done(priv);
@@ -547,7 +635,7 @@
status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS;
if (status) {
outb_p(status, SMBHSTSTS(priv));
- priv->status |= status;
+ priv->status = status;
wake_up(&priv->waitq);
}
@@ -847,7 +935,28 @@
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
((priv->features & FEATURE_I2C_BLOCK_READ) ?
- I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0);
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0) |
+ ((priv->features & FEATURE_HOST_NOTIFY) ?
+ I2C_FUNC_SMBUS_HOST_NOTIFY : 0);
+}
+
+static int i801_enable_host_notify(struct i2c_adapter *adapter)
+{
+ struct i801_priv *priv = i2c_get_adapdata(adapter);
+
+ if (!(priv->features & FEATURE_HOST_NOTIFY))
+ return -ENOTSUPP;
+
+ if (!priv->host_notify)
+ priv->host_notify = i2c_setup_smbus_host_notify(adapter);
+ if (!priv->host_notify)
+ return -ENOMEM;
+
+ outb_p(SMBSLVCMD_HST_NTFY_INTREN, SMBSLVCMD(priv));
+ /* clear Host Notify bit to allow a new notification */
+ outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv));
+
+ return 0;
}
static const struct i2c_algorithm smbus_algorithm = {
@@ -1022,8 +1131,7 @@
static void i801_probe_optional_slaves(struct i801_priv *priv) {}
#endif /* CONFIG_X86 && CONFIG_DMI */
-#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \
- defined CONFIG_DMI
+#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
static struct i801_mux_config i801_mux_config_asus_z8_d12 = {
.gpio_chip = "gpio_ich",
.values = { 0x02, 0x03 },
@@ -1379,6 +1487,7 @@
priv->features |= FEATURE_SMBUS_PEC;
priv->features |= FEATURE_BLOCK_BUFFER;
priv->features |= FEATURE_TCO;
+ priv->features |= FEATURE_HOST_NOTIFY;
break;
case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0:
@@ -1398,6 +1507,8 @@
priv->features |= FEATURE_BLOCK_BUFFER;
/* fall through */
case PCI_DEVICE_ID_INTEL_82801CA_3:
+ priv->features |= FEATURE_HOST_NOTIFY;
+ /* fall through */
case PCI_DEVICE_ID_INTEL_82801BA_2:
case PCI_DEVICE_ID_INTEL_82801AB_3:
case PCI_DEVICE_ID_INTEL_82801AA_3:
@@ -1507,6 +1618,15 @@
return err;
}
+ /*
+ * Enable Host Notify for chips that supports it.
+ * It is done after i2c_add_adapter() so that we are sure the work queue
+ * is not used if i2c_add_adapter() fails.
+ */
+ err = i801_enable_host_notify(&priv->adapter);
+ if (err && err != -ENOTSUPP)
+ dev_warn(&dev->dev, "Unable to enable SMBus Host Notify\n");
+
i801_probe_optional_slaves(priv);
/* We ignore errors - multiplexing is optional */
i801_add_mux(priv);
@@ -1553,6 +1673,14 @@
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);
+ int err;
+
+ err = i801_enable_host_notify(&priv->adapter);
+ if (err && err != -ENOTSUPP)
+ dev_warn(dev, "Unable to enable SMBus Host Notify\n");
+
return 0;
}
#endif
diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c
index ba14a86..cd98725 100644
--- a/drivers/i2c/busses/i2c-jz4780.c
+++ b/drivers/i2c/busses/i2c-jz4780.c
@@ -791,10 +791,6 @@
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0x0);
- i2c->cmd = 0;
- memset(i2c->cmd_buf, 0, BUFSIZE);
- memset(i2c->data_buf, 0, BUFSIZE);
-
i2c->irq = platform_get_irq(pdev, 0);
ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0,
dev_name(&pdev->dev), i2c);
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
index e0eb4ca..ba88f17 100644
--- a/drivers/i2c/busses/i2c-pca-isa.c
+++ b/drivers/i2c/busses/i2c-pca-isa.c
@@ -193,23 +193,12 @@
}
};
-static int __init pca_isa_init(void)
-{
- return isa_register_driver(&pca_isa_driver, 1);
-}
-
-static void __exit pca_isa_exit(void)
-{
- isa_unregister_driver(&pca_isa_driver);
-}
-
MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
MODULE_DESCRIPTION("ISA base PCA9564/PCA9665 driver");
MODULE_LICENSE("GPL");
module_param(base, ulong, 0);
MODULE_PARM_DESC(base, "I/O base address");
-
module_param(irq, int, 0);
MODULE_PARM_DESC(irq, "IRQ");
module_param(clock, int, 0);
@@ -220,6 +209,4 @@
"\t\t\t\tFast: 100100 - 400099\n"
"\t\t\t\tFast+: 400100 - 10000099\n"
"\t\t\t\tTurbo: Up to 1265800");
-
-module_init(pca_isa_init);
-module_exit(pca_isa_exit);
+module_isa_driver(pca_isa_driver, 1);
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 041050e..501bd15 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -213,14 +213,16 @@
bus_err &= I2C_STATUS_ERROR_MASK;
qup_err &= QUP_STATUS_ERROR_FLAGS;
- if (qup_err) {
- /* Clear Error interrupt */
+ /* Clear the error bits in QUP_ERROR_FLAGS */
+ if (qup_err)
writel(qup_err, qup->base + QUP_ERROR_FLAGS);
- goto done;
- }
- if (bus_err) {
- /* Clear Error interrupt */
+ /* Clear the error bits in QUP_I2C_STATUS */
+ if (bus_err)
+ writel(bus_err, qup->base + QUP_I2C_STATUS);
+
+ /* Reset the QUP State in case of error */
+ if (qup_err || bus_err) {
writel(QUP_RESET_STATE, qup->base + QUP_STATE);
goto done;
}
@@ -310,6 +312,7 @@
u32 opflags;
u32 status;
u32 shift = __ffs(op);
+ int ret = 0;
len *= qup->one_byte_t;
/* timeout after a wait of twice the max time */
@@ -321,18 +324,28 @@
if (((opflags & op) >> shift) == val) {
if ((op == QUP_OUT_NOT_EMPTY) && qup->is_last) {
- if (!(status & I2C_STATUS_BUS_ACTIVE))
- return 0;
+ if (!(status & I2C_STATUS_BUS_ACTIVE)) {
+ ret = 0;
+ goto done;
+ }
} else {
- return 0;
+ ret = 0;
+ goto done;
}
}
- if (time_after(jiffies, timeout))
- return -ETIMEDOUT;
-
+ if (time_after(jiffies, timeout)) {
+ ret = -ETIMEDOUT;
+ goto done;
+ }
usleep_range(len, len * 2);
}
+
+done:
+ if (qup->bus_err || qup->qup_err)
+ ret = (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO;
+
+ return ret;
}
static void qup_i2c_set_write_mode_v2(struct qup_i2c_dev *qup,
@@ -585,8 +598,8 @@
}
static int qup_sg_set_buf(struct scatterlist *sg, void *buf,
- struct qup_i2c_tag *tg, unsigned int buflen,
- struct qup_i2c_dev *qup, int map, int dir)
+ unsigned int buflen, struct qup_i2c_dev *qup,
+ int dir)
{
int ret;
@@ -595,9 +608,6 @@
if (!ret)
return -EINVAL;
- if (!map)
- sg_dma_address(sg) = tg->addr + ((u8 *)buf - tg->start);
-
return 0;
}
@@ -649,37 +659,37 @@
u8 *tags;
while (idx < num) {
- blocks = (msg->len + limit) / limit;
- rem = msg->len % limit;
tx_len = 0, len = 0, i = 0;
qup->is_last = (idx == (num - 1));
qup_i2c_set_blk_data(qup, msg);
+ blocks = qup->blk.count;
+ rem = msg->len - (blocks - 1) * limit;
+
if (msg->flags & I2C_M_RD) {
rx_nents += (blocks * 2) + 1;
tx_nents += 1;
while (qup->blk.pos < blocks) {
- /* length set to '0' implies 256 bytes */
- tlen = (i == (blocks - 1)) ? rem : 0;
+ tlen = (i == (blocks - 1)) ? rem : limit;
tags = &qup->start_tag.start[off + len];
len += qup_i2c_set_tags(tags, qup, msg, 1);
+ qup->blk.data_len -= tlen;
/* scratch buf to read the start and len tags */
ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
&qup->brx.tag.start[0],
- &qup->brx.tag,
- 2, qup, 0, 0);
+ 2, qup, DMA_FROM_DEVICE);
if (ret)
return ret;
ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
&msg->buf[limit * i],
- NULL, tlen, qup,
- 1, DMA_FROM_DEVICE);
+ tlen, qup,
+ DMA_FROM_DEVICE);
if (ret)
return ret;
@@ -688,7 +698,7 @@
}
ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
&qup->start_tag.start[off],
- &qup->start_tag, len, qup, 0, 0);
+ len, qup, DMA_TO_DEVICE);
if (ret)
return ret;
@@ -696,30 +706,28 @@
/* scratch buf to read the BAM EOT and FLUSH tags */
ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
&qup->brx.tag.start[0],
- &qup->brx.tag, 2,
- qup, 0, 0);
+ 2, qup, DMA_FROM_DEVICE);
if (ret)
return ret;
} else {
tx_nents += (blocks * 2);
while (qup->blk.pos < blocks) {
- tlen = (i == (blocks - 1)) ? rem : 0;
+ tlen = (i == (blocks - 1)) ? rem : limit;
tags = &qup->start_tag.start[off + tx_len];
len = qup_i2c_set_tags(tags, qup, msg, 1);
+ qup->blk.data_len -= tlen;
ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
- tags,
- &qup->start_tag, len,
- qup, 0, 0);
+ tags, len,
+ qup, DMA_TO_DEVICE);
if (ret)
return ret;
tx_len += len;
ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
&msg->buf[limit * i],
- NULL, tlen, qup, 1,
- DMA_TO_DEVICE);
+ tlen, qup, DMA_TO_DEVICE);
if (ret)
return ret;
i++;
@@ -738,8 +746,7 @@
QUP_BAM_FLUSH_STOP;
ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
&qup->btx.tag.start[0],
- &qup->btx.tag, len,
- qup, 0, 0);
+ len, qup, DMA_TO_DEVICE);
if (ret)
return ret;
tx_nents += 1;
@@ -801,39 +808,35 @@
}
if (ret || qup->bus_err || qup->qup_err) {
- if (qup->bus_err & QUP_I2C_NACK_FLAG) {
- msg--;
- dev_err(qup->dev, "NACK from %x\n", msg->addr);
- ret = -EIO;
+ if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
+ dev_err(qup->dev, "change to run state timed out");
+ goto desc_err;
+ }
- if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
- dev_err(qup->dev, "change to run state timed out");
- return ret;
- }
-
- if (rx_nents)
- writel(QUP_BAM_INPUT_EOT,
- qup->base + QUP_OUT_FIFO_BASE);
-
- writel(QUP_BAM_FLUSH_STOP,
+ if (rx_nents)
+ writel(QUP_BAM_INPUT_EOT,
qup->base + QUP_OUT_FIFO_BASE);
- qup_i2c_flush(qup);
+ writel(QUP_BAM_FLUSH_STOP, qup->base + QUP_OUT_FIFO_BASE);
- /* wait for remaining interrupts to occur */
- if (!wait_for_completion_timeout(&qup->xfer, HZ))
- dev_err(qup->dev, "flush timed out\n");
+ qup_i2c_flush(qup);
- qup_i2c_rel_dma(qup);
- }
+ /* wait for remaining interrupts to occur */
+ if (!wait_for_completion_timeout(&qup->xfer, HZ))
+ dev_err(qup->dev, "flush timed out\n");
+
+ qup_i2c_rel_dma(qup);
+
+ ret = (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO;
}
+desc_err:
dma_unmap_sg(qup->dev, qup->btx.sg, tx_nents, DMA_TO_DEVICE);
if (rx_nents)
dma_unmap_sg(qup->dev, qup->brx.sg, rx_nents,
DMA_FROM_DEVICE);
-desc_err:
+
return ret;
}
@@ -849,9 +852,6 @@
if (ret)
goto out;
- qup->bus_err = 0;
- qup->qup_err = 0;
-
writel(0, qup->base + QUP_MX_INPUT_CNT);
writel(0, qup->base + QUP_MX_OUTPUT_CNT);
@@ -889,12 +889,8 @@
ret = -ETIMEDOUT;
}
- if (qup->bus_err || qup->qup_err) {
- if (qup->bus_err & QUP_I2C_NACK_FLAG) {
- dev_err(qup->dev, "NACK from %x\n", msg->addr);
- ret = -EIO;
- }
- }
+ if (qup->bus_err || qup->qup_err)
+ ret = (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO;
return ret;
}
@@ -1020,7 +1016,7 @@
{
u32 addr, len, val;
- addr = (msg->addr << 1) | 1;
+ addr = i2c_8bit_addr_from_msg(msg);
/* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
@@ -1186,6 +1182,9 @@
if (ret < 0)
goto out;
+ qup->bus_err = 0;
+ qup->qup_err = 0;
+
writel(1, qup->base + QUP_SW_RESET);
ret = qup_i2c_poll_state(qup, QUP_RESET_STATE);
if (ret)
@@ -1235,6 +1234,9 @@
struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
int ret, len, idx = 0, use_dma = 0;
+ qup->bus_err = 0;
+ qup->qup_err = 0;
+
ret = pm_runtime_get_sync(qup->dev);
if (ret < 0)
goto out;
@@ -1409,27 +1411,21 @@
/* 2 tag bytes for each block + 5 for start, stop tags */
size = blocks * 2 + 5;
- qup->dpool = dma_pool_create("qup_i2c-dma-pool", &pdev->dev,
- size, 4, 0);
- qup->start_tag.start = dma_pool_alloc(qup->dpool, GFP_KERNEL,
- &qup->start_tag.addr);
+ qup->start_tag.start = devm_kzalloc(&pdev->dev,
+ size, GFP_KERNEL);
if (!qup->start_tag.start) {
ret = -ENOMEM;
goto fail_dma;
}
- qup->brx.tag.start = dma_pool_alloc(qup->dpool,
- GFP_KERNEL,
- &qup->brx.tag.addr);
+ qup->brx.tag.start = devm_kzalloc(&pdev->dev, 2, GFP_KERNEL);
if (!qup->brx.tag.start) {
ret = -ENOMEM;
goto fail_dma;
}
- qup->btx.tag.start = dma_pool_alloc(qup->dpool,
- GFP_KERNEL,
- &qup->btx.tag.addr);
+ qup->btx.tag.start = devm_kzalloc(&pdev->dev, 2, GFP_KERNEL);
if (!qup->btx.tag.start) {
ret = -ENOMEM;
goto fail_dma;
@@ -1568,13 +1564,6 @@
struct qup_i2c_dev *qup = platform_get_drvdata(pdev);
if (qup->is_dma) {
- dma_pool_free(qup->dpool, qup->start_tag.start,
- qup->start_tag.addr);
- dma_pool_free(qup->dpool, qup->brx.tag.start,
- qup->brx.tag.addr);
- dma_pool_free(qup->dpool, qup->btx.tag.start,
- qup->btx.tag.addr);
- dma_pool_destroy(qup->dpool);
dma_release_channel(qup->btx.dma);
dma_release_channel(qup->brx.dma);
}
diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 80bed02..2bc8b01 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -58,6 +58,12 @@
#define REG_CON_LASTACK BIT(5) /* 1: send NACK after last received byte */
#define REG_CON_ACTACK BIT(6) /* 1: stop if NACK is received */
+#define REG_CON_TUNING_MASK GENMASK(15, 8)
+
+#define REG_CON_SDA_CFG(cfg) ((cfg) << 8)
+#define REG_CON_STA_CFG(cfg) ((cfg) << 12)
+#define REG_CON_STO_CFG(cfg) ((cfg) << 14)
+
/* REG_MRXADDR bits */
#define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */
@@ -75,6 +81,77 @@
#define WAIT_TIMEOUT 1000 /* ms */
#define DEFAULT_SCL_RATE (100 * 1000) /* Hz */
+/**
+ * struct i2c_spec_values:
+ * @min_hold_start_ns: min hold time (repeated) START condition
+ * @min_low_ns: min LOW period of the SCL clock
+ * @min_high_ns: min HIGH period of the SCL cloc
+ * @min_setup_start_ns: min set-up time for a repeated START conditio
+ * @max_data_hold_ns: max data hold time
+ * @min_data_setup_ns: min data set-up time
+ * @min_setup_stop_ns: min set-up time for STOP condition
+ * @min_hold_buffer_ns: min bus free time between a STOP and
+ * START condition
+ */
+struct i2c_spec_values {
+ unsigned long min_hold_start_ns;
+ unsigned long min_low_ns;
+ unsigned long min_high_ns;
+ unsigned long min_setup_start_ns;
+ unsigned long max_data_hold_ns;
+ unsigned long min_data_setup_ns;
+ unsigned long min_setup_stop_ns;
+ unsigned long min_hold_buffer_ns;
+};
+
+static const struct i2c_spec_values standard_mode_spec = {
+ .min_hold_start_ns = 4000,
+ .min_low_ns = 4700,
+ .min_high_ns = 4000,
+ .min_setup_start_ns = 4700,
+ .max_data_hold_ns = 3450,
+ .min_data_setup_ns = 250,
+ .min_setup_stop_ns = 4000,
+ .min_hold_buffer_ns = 4700,
+};
+
+static const struct i2c_spec_values fast_mode_spec = {
+ .min_hold_start_ns = 600,
+ .min_low_ns = 1300,
+ .min_high_ns = 600,
+ .min_setup_start_ns = 600,
+ .max_data_hold_ns = 900,
+ .min_data_setup_ns = 100,
+ .min_setup_stop_ns = 600,
+ .min_hold_buffer_ns = 1300,
+};
+
+static const struct i2c_spec_values fast_mode_plus_spec = {
+ .min_hold_start_ns = 260,
+ .min_low_ns = 500,
+ .min_high_ns = 260,
+ .min_setup_start_ns = 260,
+ .max_data_hold_ns = 400,
+ .min_data_setup_ns = 50,
+ .min_setup_stop_ns = 260,
+ .min_hold_buffer_ns = 500,
+};
+
+/**
+ * struct rk3x_i2c_calced_timings:
+ * @div_low: Divider output for low
+ * @div_high: Divider output for high
+ * @tuning: Used to adjust setup/hold data time,
+ * setup/hold start time and setup stop time for
+ * v1's calc_timings, the tuning should all be 0
+ * for old hardware anyone using v0's calc_timings.
+ */
+struct rk3x_i2c_calced_timings {
+ unsigned long div_low;
+ unsigned long div_high;
+ unsigned int tuning;
+};
+
enum rk3x_i2c_state {
STATE_IDLE,
STATE_START,
@@ -85,11 +162,35 @@
/**
* @grf_offset: offset inside the grf regmap for setting the i2c type
+ * @calc_timings: Callback function for i2c timing information calculated
*/
struct rk3x_i2c_soc_data {
int grf_offset;
+ int (*calc_timings)(unsigned long, struct i2c_timings *,
+ struct rk3x_i2c_calced_timings *);
};
+/**
+ * struct rk3x_i2c - private data of the controller
+ * @adap: corresponding I2C adapter
+ * @dev: device for this controller
+ * @soc_data: related soc data struct
+ * @regs: virtual memory area
+ * @clk: function clk for rk3399 or function & Bus clks for others
+ * @pclk: Bus clk for rk3399
+ * @clk_rate_nb: i2c clk rate change notify
+ * @t: I2C known timing information
+ * @lock: spinlock for the i2c bus
+ * @wait: the waitqueue to wait for i2c transfer
+ * @busy: the condition for the event to wait for
+ * @msg: current i2c message
+ * @addr: addr of i2c slave device
+ * @mode: mode of i2c transfer
+ * @is_last_msg: flag determines whether it is the last msg in this transfer
+ * @state: state of i2c transfer
+ * @processed: byte length which has been send or received
+ * @error: error code for i2c transfer
+ */
struct rk3x_i2c {
struct i2c_adapter adap;
struct device *dev;
@@ -98,6 +199,7 @@
/* Hardware resources */
void __iomem *regs;
struct clk *clk;
+ struct clk *pclk;
struct notifier_block clk_rate_nb;
/* Settings */
@@ -116,7 +218,7 @@
/* I2C state machine */
enum rk3x_i2c_state state;
- unsigned int processed; /* sent/received bytes */
+ unsigned int processed;
int error;
};
@@ -142,13 +244,12 @@
*/
static void rk3x_i2c_start(struct rk3x_i2c *i2c)
{
- u32 val;
+ u32 val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
- rk3x_i2c_clean_ipd(i2c);
i2c_writel(i2c, REG_INT_START, REG_IEN);
/* enable adapter with correct mode, send START condition */
- val = REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
+ val |= REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
/* if we want to react to NACK, set ACTACK bit */
if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
@@ -189,7 +290,8 @@
* get the intended effect by resetting its internal state
* and issuing an ordinary START.
*/
- i2c_writel(i2c, 0, REG_CON);
+ ctrl = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
+ i2c_writel(i2c, ctrl, REG_CON);
/* signal that we are finished with the current msg */
wake_up(&i2c->wait);
@@ -431,26 +533,37 @@
}
/**
+ * Get timing values of I2C specification
+ *
+ * @speed: Desired SCL frequency
+ *
+ * Returns: Matched i2c spec values.
+ */
+static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
+{
+ if (speed <= 100000)
+ return &standard_mode_spec;
+ else if (speed <= 400000)
+ return &fast_mode_spec;
+ else
+ return &fast_mode_plus_spec;
+}
+
+/**
* Calculate divider values for desired SCL frequency
*
* @clk_rate: I2C input clock rate
- * @t: Known I2C timing information.
- * @div_low: Divider output for low
- * @div_high: Divider output for high
+ * @t: Known I2C timing information
+ * @t_calc: Caculated rk3x private timings that would be written into regs
*
* Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
* a best-effort divider value is returned in divs. If the target rate is
* too high, we silently use the highest possible rate.
*/
-static int rk3x_i2c_calc_divs(unsigned long clk_rate,
- struct i2c_timings *t,
- unsigned long *div_low,
- unsigned long *div_high)
+static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate,
+ struct i2c_timings *t,
+ struct rk3x_i2c_calced_timings *t_calc)
{
- unsigned long spec_min_low_ns, spec_min_high_ns;
- unsigned long spec_setup_start, spec_max_data_hold_ns;
- unsigned long data_hold_buffer_ns;
-
unsigned long min_low_ns, min_high_ns;
unsigned long max_low_ns, min_total_ns;
@@ -462,6 +575,8 @@
unsigned long min_div_for_hold, min_total_div;
unsigned long extra_div, extra_low_div, ideal_low_div;
+ unsigned long data_hold_buffer_ns = 50;
+ const struct i2c_spec_values *spec;
int ret = 0;
/* Only support standard-mode and fast-mode */
@@ -484,22 +599,8 @@
* This is because the i2c host on Rockchip holds the data line
* for half the low time.
*/
- if (t->bus_freq_hz <= 100000) {
- /* Standard-mode */
- spec_min_low_ns = 4700;
- spec_setup_start = 4700;
- spec_min_high_ns = 4000;
- spec_max_data_hold_ns = 3450;
- data_hold_buffer_ns = 50;
- } else {
- /* Fast-mode */
- spec_min_low_ns = 1300;
- spec_setup_start = 600;
- spec_min_high_ns = 600;
- spec_max_data_hold_ns = 900;
- data_hold_buffer_ns = 50;
- }
- min_high_ns = t->scl_rise_ns + spec_min_high_ns;
+ spec = rk3x_i2c_get_spec(t->bus_freq_hz);
+ min_high_ns = t->scl_rise_ns + spec->min_high_ns;
/*
* Timings for repeated start:
@@ -509,14 +610,14 @@
* We need to account for those rules in picking our "high" time so
* we meet tSU;STA and tHD;STA times.
*/
- min_high_ns = max(min_high_ns,
- DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start) * 1000, 875));
- min_high_ns = max(min_high_ns,
- DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start +
- t->sda_fall_ns + spec_min_high_ns), 2));
+ min_high_ns = max(min_high_ns, DIV_ROUND_UP(
+ (t->scl_rise_ns + spec->min_setup_start_ns) * 1000, 875));
+ min_high_ns = max(min_high_ns, DIV_ROUND_UP(
+ (t->scl_rise_ns + spec->min_setup_start_ns + t->sda_fall_ns +
+ spec->min_high_ns), 2));
- min_low_ns = t->scl_fall_ns + spec_min_low_ns;
- max_low_ns = spec_max_data_hold_ns * 2 - data_hold_buffer_ns;
+ min_low_ns = t->scl_fall_ns + spec->min_low_ns;
+ max_low_ns = spec->max_data_hold_ns * 2 - data_hold_buffer_ns;
min_total_ns = min_low_ns + min_high_ns;
/* Adjust to avoid overflow */
@@ -552,8 +653,8 @@
* Time needed to meet hold requirements is important.
* Just use that.
*/
- *div_low = min_low_div;
- *div_high = min_high_div;
+ t_calc->div_low = min_low_div;
+ t_calc->div_high = min_high_div;
} else {
/*
* We've got to distribute some time among the low and high
@@ -582,25 +683,186 @@
/* Give low the "ideal" and give high whatever extra is left */
extra_low_div = ideal_low_div - min_low_div;
- *div_low = ideal_low_div;
- *div_high = min_high_div + (extra_div - extra_low_div);
+ t_calc->div_low = ideal_low_div;
+ t_calc->div_high = min_high_div + (extra_div - extra_low_div);
}
/*
* Adjust to the fact that the hardware has an implicit "+1".
* NOTE: Above calculations always produce div_low > 0 and div_high > 0.
*/
- *div_low = *div_low - 1;
- *div_high = *div_high - 1;
+ t_calc->div_low--;
+ t_calc->div_high--;
/* Maximum divider supported by hw is 0xffff */
- if (*div_low > 0xffff) {
- *div_low = 0xffff;
+ if (t_calc->div_low > 0xffff) {
+ t_calc->div_low = 0xffff;
ret = -EINVAL;
}
- if (*div_high > 0xffff) {
- *div_high = 0xffff;
+ if (t_calc->div_high > 0xffff) {
+ t_calc->div_high = 0xffff;
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+/**
+ * Calculate timing values for desired SCL frequency
+ *
+ * @clk_rate: I2C input clock rate
+ * @t: Known I2C timing information
+ * @t_calc: Caculated rk3x private timings that would be written into regs
+ *
+ * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
+ * a best-effort divider value is returned in divs. If the target rate is
+ * too high, we silently use the highest possible rate.
+ * The following formulas are v1's method to calculate timings.
+ *
+ * l = divl + 1;
+ * h = divh + 1;
+ * s = sda_update_config + 1;
+ * u = start_setup_config + 1;
+ * p = stop_setup_config + 1;
+ * T = Tclk_i2c;
+ *
+ * tHigh = 8 * h * T;
+ * tLow = 8 * l * T;
+ *
+ * tHD;sda = (l * s + 1) * T;
+ * tSU;sda = [(8 - s) * l + 1] * T;
+ * tI2C = 8 * (l + h) * T;
+ *
+ * tSU;sta = (8h * u + 1) * T;
+ * tHD;sta = [8h * (u + 1) - 1] * T;
+ * tSU;sto = (8h * p + 1) * T;
+ */
+static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
+ struct i2c_timings *t,
+ struct rk3x_i2c_calced_timings *t_calc)
+{
+ unsigned long min_low_ns, min_high_ns, min_total_ns;
+ unsigned long min_setup_start_ns, min_setup_data_ns;
+ unsigned long min_setup_stop_ns, max_hold_data_ns;
+
+ unsigned long clk_rate_khz, scl_rate_khz;
+
+ unsigned long min_low_div, min_high_div;
+
+ unsigned long min_div_for_hold, min_total_div;
+ unsigned long extra_div, extra_low_div;
+ unsigned long sda_update_cfg, stp_sta_cfg, stp_sto_cfg;
+
+ const struct i2c_spec_values *spec;
+ int ret = 0;
+
+ /* Support standard-mode, fast-mode and fast-mode plus */
+ if (WARN_ON(t->bus_freq_hz > 1000000))
+ t->bus_freq_hz = 1000000;
+
+ /* prevent scl_rate_khz from becoming 0 */
+ if (WARN_ON(t->bus_freq_hz < 1000))
+ t->bus_freq_hz = 1000;
+
+ /*
+ * min_low_ns: The minimum number of ns we need to hold low to
+ * meet I2C specification, should include fall time.
+ * min_high_ns: The minimum number of ns we need to hold high to
+ * meet I2C specification, should include rise time.
+ */
+ spec = rk3x_i2c_get_spec(t->bus_freq_hz);
+
+ /* calculate min-divh and min-divl */
+ clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000);
+ scl_rate_khz = t->bus_freq_hz / 1000;
+ min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8);
+
+ min_high_ns = t->scl_rise_ns + spec->min_high_ns;
+ min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000);
+
+ min_low_ns = t->scl_fall_ns + spec->min_low_ns;
+ min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000);
+
+ /*
+ * Final divh and divl must be greater than 0, otherwise the
+ * hardware would not output the i2c clk.
+ */
+ min_high_div = (min_high_div < 1) ? 2 : min_high_div;
+ min_low_div = (min_low_div < 1) ? 2 : min_low_div;
+
+ /* These are the min dividers needed for min hold times. */
+ min_div_for_hold = (min_low_div + min_high_div);
+ min_total_ns = min_low_ns + min_high_ns;
+
+ /*
+ * This is the maximum divider so we don't go over the maximum.
+ * We don't round up here (we round down) since this is a maximum.
+ */
+ if (min_div_for_hold >= min_total_div) {
+ /*
+ * Time needed to meet hold requirements is important.
+ * Just use that.
+ */
+ t_calc->div_low = min_low_div;
+ t_calc->div_high = min_high_div;
+ } else {
+ /*
+ * We've got to distribute some time among the low and high
+ * so we don't run too fast.
+ * We'll try to split things up by the scale of min_low_div and
+ * min_high_div, biasing slightly towards having a higher div
+ * for low (spend more time low).
+ */
+ extra_div = min_total_div - min_div_for_hold;
+ extra_low_div = DIV_ROUND_UP(min_low_div * extra_div,
+ min_div_for_hold);
+
+ t_calc->div_low = min_low_div + extra_low_div;
+ t_calc->div_high = min_high_div + (extra_div - extra_low_div);
+ }
+
+ /*
+ * calculate sda data hold count by the rules, data_upd_st:3
+ * is a appropriate value to reduce calculated times.
+ */
+ for (sda_update_cfg = 3; sda_update_cfg > 0; sda_update_cfg--) {
+ max_hold_data_ns = DIV_ROUND_UP((sda_update_cfg
+ * (t_calc->div_low) + 1)
+ * 1000000, clk_rate_khz);
+ min_setup_data_ns = DIV_ROUND_UP(((8 - sda_update_cfg)
+ * (t_calc->div_low) + 1)
+ * 1000000, clk_rate_khz);
+ if ((max_hold_data_ns < spec->max_data_hold_ns) &&
+ (min_setup_data_ns > spec->min_data_setup_ns))
+ break;
+ }
+
+ /* calculate setup start config */
+ min_setup_start_ns = t->scl_rise_ns + spec->min_setup_start_ns;
+ stp_sta_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_start_ns
+ - 1000000, 8 * 1000000 * (t_calc->div_high));
+
+ /* calculate setup stop config */
+ min_setup_stop_ns = t->scl_rise_ns + spec->min_setup_stop_ns;
+ stp_sto_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_stop_ns
+ - 1000000, 8 * 1000000 * (t_calc->div_high));
+
+ t_calc->tuning = REG_CON_SDA_CFG(--sda_update_cfg) |
+ REG_CON_STA_CFG(--stp_sta_cfg) |
+ REG_CON_STO_CFG(--stp_sto_cfg);
+
+ t_calc->div_low--;
+ t_calc->div_high--;
+
+ /* Maximum divider supported by hw is 0xffff */
+ if (t_calc->div_low > 0xffff) {
+ t_calc->div_low = 0xffff;
+ ret = -EINVAL;
+ }
+
+ if (t_calc->div_high > 0xffff) {
+ t_calc->div_high = 0xffff;
ret = -EINVAL;
}
@@ -610,19 +872,31 @@
static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
{
struct i2c_timings *t = &i2c->t;
- unsigned long div_low, div_high;
+ struct rk3x_i2c_calced_timings calc;
u64 t_low_ns, t_high_ns;
+ unsigned long flags;
+ u32 val;
int ret;
- ret = rk3x_i2c_calc_divs(clk_rate, t, &div_low, &div_high);
+ ret = i2c->soc_data->calc_timings(clk_rate, t, &calc);
WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
- clk_enable(i2c->clk);
- i2c_writel(i2c, (div_high << 16) | (div_low & 0xffff), REG_CLKDIV);
- clk_disable(i2c->clk);
+ clk_enable(i2c->pclk);
- t_low_ns = div_u64(((u64)div_low + 1) * 8 * 1000000000, clk_rate);
- t_high_ns = div_u64(((u64)div_high + 1) * 8 * 1000000000, clk_rate);
+ spin_lock_irqsave(&i2c->lock, flags);
+ val = i2c_readl(i2c, REG_CON);
+ val &= ~REG_CON_TUNING_MASK;
+ val |= calc.tuning;
+ i2c_writel(i2c, val, REG_CON);
+ i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
+ REG_CLKDIV);
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ clk_disable(i2c->pclk);
+
+ t_low_ns = div_u64(((u64)calc.div_low + 1) * 8 * 1000000000, clk_rate);
+ t_high_ns = div_u64(((u64)calc.div_high + 1) * 8 * 1000000000,
+ clk_rate);
dev_dbg(i2c->dev,
"CLK %lukhz, Req %uns, Act low %lluns high %lluns\n",
clk_rate / 1000,
@@ -652,12 +926,17 @@
{
struct clk_notifier_data *ndata = data;
struct rk3x_i2c *i2c = container_of(nb, struct rk3x_i2c, clk_rate_nb);
- unsigned long div_low, div_high;
+ struct rk3x_i2c_calced_timings calc;
switch (event) {
case PRE_RATE_CHANGE:
- if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t,
- &div_low, &div_high) != 0)
+ /*
+ * Try the calculation (but don't store the result) ahead of
+ * time to see if we need to block the clock change. Timings
+ * shouldn't actually take effect until rk3x_i2c_adapt_div().
+ */
+ if (i2c->soc_data->calc_timings(ndata->new_rate, &i2c->t,
+ &calc) != 0)
return NOTIFY_STOP;
/* scale up */
@@ -767,12 +1046,14 @@
{
struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data;
unsigned long timeout, flags;
+ u32 val;
int ret = 0;
int i;
spin_lock_irqsave(&i2c->lock, flags);
clk_enable(i2c->clk);
+ clk_enable(i2c->pclk);
i2c->is_last_msg = false;
@@ -806,7 +1087,9 @@
/* Force a STOP condition without interrupt */
i2c_writel(i2c, 0, REG_IEN);
- i2c_writel(i2c, REG_CON_EN | REG_CON_STOP, REG_CON);
+ val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
+ val |= REG_CON_EN | REG_CON_STOP;
+ i2c_writel(i2c, val, REG_CON);
i2c->state = STATE_IDLE;
@@ -820,7 +1103,9 @@
}
}
+ clk_disable(i2c->pclk);
clk_disable(i2c->clk);
+
spin_unlock_irqrestore(&i2c->lock, flags);
return ret < 0 ? ret : num;
@@ -836,17 +1121,52 @@
.functionality = rk3x_i2c_func,
};
-static struct rk3x_i2c_soc_data soc_data[3] = {
- { .grf_offset = 0x154 }, /* rk3066 */
- { .grf_offset = 0x0a4 }, /* rk3188 */
- { .grf_offset = -1 }, /* no I2C switching needed */
+static const struct rk3x_i2c_soc_data rk3066_soc_data = {
+ .grf_offset = 0x154,
+ .calc_timings = rk3x_i2c_v0_calc_timings,
+};
+
+static const struct rk3x_i2c_soc_data rk3188_soc_data = {
+ .grf_offset = 0x0a4,
+ .calc_timings = rk3x_i2c_v0_calc_timings,
+};
+
+static const struct rk3x_i2c_soc_data rk3228_soc_data = {
+ .grf_offset = -1,
+ .calc_timings = rk3x_i2c_v0_calc_timings,
+};
+
+static const struct rk3x_i2c_soc_data rk3288_soc_data = {
+ .grf_offset = -1,
+ .calc_timings = rk3x_i2c_v0_calc_timings,
+};
+
+static const struct rk3x_i2c_soc_data rk3399_soc_data = {
+ .grf_offset = -1,
+ .calc_timings = rk3x_i2c_v1_calc_timings,
};
static const struct of_device_id rk3x_i2c_match[] = {
- { .compatible = "rockchip,rk3066-i2c", .data = (void *)&soc_data[0] },
- { .compatible = "rockchip,rk3188-i2c", .data = (void *)&soc_data[1] },
- { .compatible = "rockchip,rk3228-i2c", .data = (void *)&soc_data[2] },
- { .compatible = "rockchip,rk3288-i2c", .data = (void *)&soc_data[2] },
+ {
+ .compatible = "rockchip,rk3066-i2c",
+ .data = (void *)&rk3066_soc_data
+ },
+ {
+ .compatible = "rockchip,rk3188-i2c",
+ .data = (void *)&rk3188_soc_data
+ },
+ {
+ .compatible = "rockchip,rk3228-i2c",
+ .data = (void *)&rk3228_soc_data
+ },
+ {
+ .compatible = "rockchip,rk3288-i2c",
+ .data = (void *)&rk3288_soc_data
+ },
+ {
+ .compatible = "rockchip,rk3399-i2c",
+ .data = (void *)&rk3399_soc_data
+ },
{},
};
MODULE_DEVICE_TABLE(of, rk3x_i2c_match);
@@ -886,12 +1206,6 @@
spin_lock_init(&i2c->lock);
init_waitqueue_head(&i2c->wait);
- i2c->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(i2c->clk)) {
- dev_err(&pdev->dev, "cannot get clock\n");
- return PTR_ERR(i2c->clk);
- }
-
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i2c->regs = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(i2c->regs))
@@ -945,17 +1259,44 @@
platform_set_drvdata(pdev, i2c);
+ if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) {
+ /* Only one clock to use for bus clock and peripheral clock */
+ i2c->clk = devm_clk_get(&pdev->dev, NULL);
+ i2c->pclk = i2c->clk;
+ } else {
+ i2c->clk = devm_clk_get(&pdev->dev, "i2c");
+ i2c->pclk = devm_clk_get(&pdev->dev, "pclk");
+ }
+
+ if (IS_ERR(i2c->clk)) {
+ ret = PTR_ERR(i2c->clk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Can't get bus clk: %d\n", ret);
+ return ret;
+ }
+ if (IS_ERR(i2c->pclk)) {
+ ret = PTR_ERR(i2c->pclk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Can't get periph clk: %d\n", ret);
+ return ret;
+ }
+
ret = clk_prepare(i2c->clk);
if (ret < 0) {
- dev_err(&pdev->dev, "Could not prepare clock\n");
+ dev_err(&pdev->dev, "Can't prepare bus clk: %d\n", ret);
return ret;
}
+ ret = clk_prepare(i2c->pclk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Can't prepare periph clock: %d\n", ret);
+ goto err_clk;
+ }
i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb;
ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb);
if (ret != 0) {
dev_err(&pdev->dev, "Unable to register clock notifier\n");
- goto err_clk;
+ goto err_pclk;
}
clk_rate = clk_get_rate(i2c->clk);
@@ -973,6 +1314,8 @@
err_clk_notifier:
clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
+err_pclk:
+ clk_unprepare(i2c->pclk);
err_clk:
clk_unprepare(i2c->clk);
return ret;
@@ -985,6 +1328,7 @@
i2c_del_adapter(&i2c->adap);
clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
+ clk_unprepare(i2c->pclk);
clk_unprepare(i2c->clk);
return 0;
diff --git a/drivers/i2c/busses/i2c-robotfuzz-osif.c b/drivers/i2c/busses/i2c-robotfuzz-osif.c
index ced9c6a..89d8b41 100644
--- a/drivers/i2c/busses/i2c-robotfuzz-osif.c
+++ b/drivers/i2c/busses/i2c-robotfuzz-osif.c
@@ -125,7 +125,7 @@
#define USB_OSIF_VENDOR_ID 0x1964
#define USB_OSIF_PRODUCT_ID 0x0001
-static struct usb_device_id osif_table[] = {
+static const struct usb_device_id osif_table[] = {
{ USB_DEVICE(USB_OSIF_VENDOR_ID, USB_OSIF_PRODUCT_ID) },
{ }
};
diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c
index 240637f..c73d2d2 100644
--- a/drivers/i2c/busses/i2c-versatile.c
+++ b/drivers/i2c/busses/i2c-versatile.c
@@ -70,28 +70,14 @@
struct resource *r;
int ret;
+ i2c = devm_kzalloc(&dev->dev, sizeof(struct i2c_versatile), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
r = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (!r) {
- ret = -EINVAL;
- goto err_out;
- }
-
- if (!request_mem_region(r->start, resource_size(r), "versatile-i2c")) {
- ret = -EBUSY;
- goto err_out;
- }
-
- i2c = kzalloc(sizeof(struct i2c_versatile), GFP_KERNEL);
- if (!i2c) {
- ret = -ENOMEM;
- goto err_release;
- }
-
- i2c->base = ioremap(r->start, resource_size(r));
- if (!i2c->base) {
- ret = -ENOMEM;
- goto err_free;
- }
+ i2c->base = devm_ioremap_resource(&dev->dev, r);
+ if (IS_ERR(i2c->base))
+ return PTR_ERR(i2c->base);
writel(SCL | SDA, i2c->base + I2C_CONTROLS);
@@ -105,18 +91,12 @@
i2c->adap.nr = dev->id;
ret = i2c_bit_add_numbered_bus(&i2c->adap);
- if (ret >= 0) {
- platform_set_drvdata(dev, i2c);
- return 0;
- }
+ if (ret < 0)
+ return ret;
- iounmap(i2c->base);
- err_free:
- kfree(i2c);
- err_release:
- release_mem_region(r->start, resource_size(r));
- err_out:
- return ret;
+ platform_set_drvdata(dev, i2c);
+
+ return 0;
}
static int i2c_versatile_remove(struct platform_device *dev)
diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c
index c941418..55a7bef 100644
--- a/drivers/i2c/busses/i2c-xlp9xx.c
+++ b/drivers/i2c/busses/i2c-xlp9xx.c
@@ -6,6 +6,7 @@
* warranty of any kind, whether express or implied.
*/
+#include <linux/acpi.h>
#include <linux/completion.h>
#include <linux/i2c.h>
#include <linux/init.h>
@@ -341,11 +342,10 @@
static int xlp9xx_i2c_get_frequency(struct platform_device *pdev,
struct xlp9xx_i2c_dev *priv)
{
- struct device_node *np = pdev->dev.of_node;
u32 freq;
int err;
- err = of_property_read_u32(np, "clock-frequency", &freq);
+ err = device_property_read_u32(&pdev->dev, "clock-frequency", &freq);
if (err) {
freq = XLP9XX_I2C_DEFAULT_FREQ;
dev_dbg(&pdev->dev, "using default frequency %u\n", freq);
@@ -429,12 +429,21 @@
{ /* sentinel */ },
};
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id xlp9xx_i2c_acpi_ids[] = {
+ {"BRCM9007", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, xlp9xx_i2c_acpi_ids);
+#endif
+
static struct platform_driver xlp9xx_i2c_driver = {
.probe = xlp9xx_i2c_probe,
.remove = xlp9xx_i2c_remove,
.driver = {
.name = "xlp9xx-i2c",
.of_match_table = xlp9xx_i2c_of_match,
+ .acpi_match_table = ACPI_PTR(xlp9xx_i2c_acpi_ids),
},
};
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 74e5aeaf..da3a02e 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -27,6 +27,8 @@
I2C slave support (c) 2014 by Wolfram Sang <wsa@sang-engineering.com>
*/
+#define pr_fmt(fmt) "i2c-core: " fmt
+
#include <dt-bindings/i2c/i2c.h>
#include <asm/uaccess.h>
#include <linux/acpi.h>
@@ -493,7 +495,8 @@
break;
default:
- pr_info("protocol(0x%02x) is not supported.\n", accessor_type);
+ dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n",
+ accessor_type, client->addr);
ret = AE_BAD_PARAMETER;
goto err;
}
@@ -759,6 +762,47 @@
}
EXPORT_SYMBOL_GPL(i2c_recover_bus);
+static void i2c_init_recovery(struct i2c_adapter *adap)
+{
+ struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
+ char *err_str;
+
+ if (!bri)
+ return;
+
+ if (!bri->recover_bus) {
+ err_str = "no recover_bus() found";
+ goto err;
+ }
+
+ /* Generic GPIO recovery */
+ if (bri->recover_bus == i2c_generic_gpio_recovery) {
+ if (!gpio_is_valid(bri->scl_gpio)) {
+ err_str = "invalid SCL gpio";
+ goto err;
+ }
+
+ if (gpio_is_valid(bri->sda_gpio))
+ bri->get_sda = get_sda_gpio_value;
+ else
+ bri->get_sda = NULL;
+
+ bri->get_scl = get_scl_gpio_value;
+ bri->set_scl = set_scl_gpio_value;
+ } else if (bri->recover_bus == i2c_generic_scl_recovery) {
+ /* Generic SCL recovery */
+ if (!bri->set_scl || !bri->get_scl) {
+ err_str = "no {get|set}_scl() found";
+ goto err;
+ }
+ }
+
+ return;
+ err:
+ dev_err(&adap->dev, "Not using recovery: %s\n", err_str);
+ adap->bus_recovery_info = NULL;
+}
+
static int i2c_device_probe(struct device *dev)
{
struct i2c_client *client = i2c_verify_client(dev);
@@ -1240,6 +1284,47 @@
}
EXPORT_SYMBOL_GPL(i2c_new_dummy);
+/**
+ * i2c_new_secondary_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
+ * @default_addr: Used as a fallback if no secondary address was specified
+ * Context: can sleep
+ *
+ * I2C clients can be composed of multiple I2C slaves bound together in a single
+ * component. The I2C client driver then binds to the master I2C slave and needs
+ * to create I2C dummy clients to communicate with all the other slaves.
+ *
+ * This function creates and returns an I2C dummy client whose I2C address is
+ * retrieved from the platform firmware based on the given slave name. If no
+ * address is specified by the firmware default_addr is used.
+ *
+ * On DT-based platforms the address is retrieved from the "reg" property entry
+ * 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.
+ */
+struct i2c_client *i2c_new_secondary_device(struct i2c_client *client,
+ const char *name,
+ u16 default_addr)
+{
+ struct device_node *np = client->dev.of_node;
+ u32 addr = default_addr;
+ int i;
+
+ if (np) {
+ i = of_property_match_string(np, "reg-names", name);
+ if (i >= 0)
+ of_property_read_u32_index(np, "reg", i, &addr);
+ }
+
+ dev_dbg(&client->adapter->dev, "Address for %s : 0x%x\n", name, addr);
+ return i2c_new_dummy(client->adapter, addr);
+}
+EXPORT_SYMBOL_GPL(i2c_new_secondary_device);
+
/* ------------------------------------------------------------------------- */
/* I2C bus adapters -- one roots each I2C or SMBUS segment */
@@ -1608,7 +1693,7 @@
static int i2c_register_adapter(struct i2c_adapter *adap)
{
- int res = 0;
+ int res = -EINVAL;
/* Can't register until after driver model init */
if (WARN_ON(!is_registered)) {
@@ -1617,15 +1702,12 @@
}
/* Sanity checks */
- if (unlikely(adap->name[0] == '\0')) {
- pr_err("i2c-core: Attempt to register an adapter with "
- "no name!\n");
- return -EINVAL;
- }
- if (unlikely(!adap->algo)) {
- pr_err("i2c-core: Attempt to register adapter '%s' with "
- "no algo!\n", adap->name);
- return -EINVAL;
+ if (WARN(!adap->name[0], "i2c adapter has no name"))
+ goto out_list;
+
+ if (!adap->algo) {
+ pr_err("adapter '%s': no algo supplied!\n", adap->name);
+ goto out_list;
}
if (!adap->lock_bus) {
@@ -1647,8 +1729,10 @@
adap->dev.bus = &i2c_bus_type;
adap->dev.type = &i2c_adapter_type;
res = device_register(&adap->dev);
- if (res)
+ if (res) {
+ pr_err("adapter '%s': can't register device (%d)\n", adap->name, res);
goto out_list;
+ }
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
@@ -1664,41 +1748,8 @@
"Failed to create compatibility class link\n");
#endif
- /* bus recovery specific initialization */
- if (adap->bus_recovery_info) {
- struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
+ i2c_init_recovery(adap);
- if (!bri->recover_bus) {
- dev_err(&adap->dev, "No recover_bus() found, not using recovery\n");
- adap->bus_recovery_info = NULL;
- goto exit_recovery;
- }
-
- /* Generic GPIO recovery */
- if (bri->recover_bus == i2c_generic_gpio_recovery) {
- if (!gpio_is_valid(bri->scl_gpio)) {
- dev_err(&adap->dev, "Invalid SCL gpio, not using recovery\n");
- adap->bus_recovery_info = NULL;
- goto exit_recovery;
- }
-
- if (gpio_is_valid(bri->sda_gpio))
- bri->get_sda = get_sda_gpio_value;
- else
- bri->get_sda = NULL;
-
- bri->get_scl = get_scl_gpio_value;
- bri->set_scl = set_scl_gpio_value;
- } else if (bri->recover_bus == i2c_generic_scl_recovery) {
- /* Generic SCL recovery */
- if (!bri->set_scl || !bri->get_scl) {
- dev_err(&adap->dev, "No {get|set}_scl() found, not using recovery\n");
- adap->bus_recovery_info = NULL;
- }
- }
- }
-
-exit_recovery:
/* create pre-declared device nodes */
of_i2c_register_devices(adap);
acpi_i2c_register_devices(adap);
@@ -1730,13 +1781,12 @@
*/
static int __i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
- int id;
+ int id;
mutex_lock(&core_lock);
- id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1,
- GFP_KERNEL);
+ id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1, GFP_KERNEL);
mutex_unlock(&core_lock);
- if (id < 0)
+ if (WARN(id < 0, "couldn't get idr"))
return id == -ENOSPC ? -EBUSY : id;
return i2c_register_adapter(adap);
@@ -1773,7 +1823,7 @@
id = idr_alloc(&i2c_adapter_idr, adapter,
__i2c_first_dynamic_bus_num, 0, GFP_KERNEL);
mutex_unlock(&core_lock);
- if (id < 0)
+ if (WARN(id < 0, "couldn't get idr"))
return id;
adapter->nr = id;
@@ -1871,8 +1921,7 @@
found = idr_find(&i2c_adapter_idr, adap->nr);
mutex_unlock(&core_lock);
if (found != adap) {
- pr_debug("i2c-core: attempting to delete unregistered "
- "adapter [%s]\n", adap->name);
+ pr_debug("attempting to delete unregistered adapter [%s]\n", adap->name);
return;
}
@@ -2032,7 +2081,7 @@
if (res)
return res;
- pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
+ pr_debug("driver [%s] registered\n", driver->driver.name);
INIT_LIST_HEAD(&driver->clients);
/* Walk the adapters that are already present */
@@ -2059,7 +2108,7 @@
i2c_for_each_dev(driver, __process_removed_driver);
driver_unregister(&driver->driver);
- pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
+ pr_debug("driver [%s] unregistered\n", driver->driver.name);
}
EXPORT_SYMBOL(i2c_del_driver);
@@ -2150,8 +2199,8 @@
put_device(&adap->dev);
if (IS_ERR(client)) {
- pr_err("%s: failed to create for '%s'\n",
- __func__, rd->dn->full_name);
+ dev_err(&adap->dev, "failed to create client for '%s'\n",
+ rd->dn->full_name);
return notifier_from_errno(PTR_ERR(client));
}
break;
@@ -2772,7 +2821,7 @@
cpec = i2c_smbus_msg_pec(cpec, msg);
if (rpec != cpec) {
- pr_debug("i2c-core: Bad PEC 0x%02x vs. 0x%02x\n",
+ pr_debug("Bad PEC 0x%02x vs. 0x%02x\n",
rpec, cpec);
return -EBADMSG;
}
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 6ecfd76..66f323f 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -485,13 +485,8 @@
unsigned int minor = iminor(inode);
struct i2c_client *client;
struct i2c_adapter *adap;
- struct i2c_dev *i2c_dev;
- i2c_dev = i2c_dev_get_by_minor(minor);
- if (!i2c_dev)
- return -ENODEV;
-
- adap = i2c_get_adapter(i2c_dev->adap->nr);
+ adap = i2c_get_adapter(minor);
if (!adap)
return -ENODEV;
diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c
index abb55d3..b0d2679 100644
--- a/drivers/i2c/i2c-smbus.c
+++ b/drivers/i2c/i2c-smbus.c
@@ -33,7 +33,8 @@
struct alert_data {
unsigned short addr;
- u8 flag:1;
+ enum i2c_alert_protocol type;
+ unsigned int data;
};
/* If this is the alerting device, notify its driver */
@@ -56,7 +57,7 @@
if (client->dev.driver) {
driver = to_i2c_driver(client->dev.driver);
if (driver->alert)
- driver->alert(client, data->flag);
+ driver->alert(client, data->type, data->data);
else
dev_warn(&client->dev, "no driver alert()!\n");
} else
@@ -96,8 +97,9 @@
if (status < 0)
break;
- data.flag = status & 1;
+ data.data = status & 1;
data.addr = status >> 1;
+ data.type = I2C_PROTOCOL_SMBUS_ALERT;
if (data.addr == prev_addr) {
dev_warn(&ara->dev, "Duplicate SMBALERT# from dev "
@@ -105,7 +107,7 @@
break;
}
dev_dbg(&ara->dev, "SMBALERT# from dev 0x%02x, flag %d\n",
- data.addr, data.flag);
+ data.addr, data.data);
/* Notify driver for the device which issued the alert */
device_for_each_child(&ara->adapter->dev, &data,
@@ -239,6 +241,108 @@
}
EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert);
+static void smbus_host_notify_work(struct work_struct *work)
+{
+ struct alert_data alert;
+ struct i2c_adapter *adapter;
+ unsigned long flags;
+ u16 payload;
+ u8 addr;
+ struct smbus_host_notify *data;
+
+ data = container_of(work, struct smbus_host_notify, work);
+
+ spin_lock_irqsave(&data->lock, flags);
+ payload = data->payload;
+ addr = data->addr;
+ adapter = data->adapter;
+
+ /* clear the pending bit and release the spinlock */
+ data->pending = false;
+ spin_unlock_irqrestore(&data->lock, flags);
+
+ if (!adapter || !addr)
+ return;
+
+ alert.type = I2C_PROTOCOL_SMBUS_HOST_NOTIFY;
+ alert.addr = addr;
+ alert.data = payload;
+
+ device_for_each_child(&adapter->dev, &alert, smbus_do_alert);
+}
+
+/**
+ * i2c_setup_smbus_host_notify - Allocate a new smbus_host_notify for the given
+ * I2C adapter.
+ * @adapter: the adapter we want to associate a Host Notify function
+ *
+ * Returns a struct smbus_host_notify pointer on success, and NULL on failure.
+ * The resulting smbus_host_notify must not be freed afterwards, it is a
+ * managed resource already.
+ */
+struct smbus_host_notify *i2c_setup_smbus_host_notify(struct i2c_adapter *adap)
+{
+ struct smbus_host_notify *host_notify;
+
+ host_notify = devm_kzalloc(&adap->dev, sizeof(struct smbus_host_notify),
+ GFP_KERNEL);
+ if (!host_notify)
+ return NULL;
+
+ host_notify->adapter = adap;
+
+ spin_lock_init(&host_notify->lock);
+ INIT_WORK(&host_notify->work, smbus_host_notify_work);
+
+ return host_notify;
+}
+EXPORT_SYMBOL_GPL(i2c_setup_smbus_host_notify);
+
+/**
+ * i2c_handle_smbus_host_notify - Forward a Host Notify event to the correct
+ * I2C client.
+ * @host_notify: the struct host_notify attached to the relevant adapter
+ * @addr: the I2C address of the notifying device
+ * @data: the payload of the notification
+ * Context: can't sleep
+ *
+ * Helper function to be called from an I2C bus driver's interrupt
+ * handler. It will schedule the Host Notify work, in turn calling the
+ * corresponding I2C device driver's alert function.
+ *
+ * host_notify should be a valid pointer previously returned by
+ * i2c_setup_smbus_host_notify().
+ */
+int i2c_handle_smbus_host_notify(struct smbus_host_notify *host_notify,
+ unsigned short addr, unsigned int data)
+{
+ unsigned long flags;
+ struct i2c_adapter *adapter;
+
+ if (!host_notify || !host_notify->adapter)
+ return -EINVAL;
+
+ adapter = host_notify->adapter;
+
+ spin_lock_irqsave(&host_notify->lock, flags);
+
+ if (host_notify->pending) {
+ spin_unlock_irqrestore(&host_notify->lock, flags);
+ dev_warn(&adapter->dev, "Host Notify already scheduled.\n");
+ return -EBUSY;
+ }
+
+ host_notify->payload = data;
+ host_notify->addr = addr;
+
+ /* Mark that there is a pending notification and release the lock */
+ host_notify->pending = true;
+ spin_unlock_irqrestore(&host_notify->lock, flags);
+
+ return schedule_work(&host_notify->work);
+}
+EXPORT_SYMBOL_GPL(i2c_handle_smbus_host_notify);
+
module_i2c_driver(smbalert_driver);
MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 9ceb63b..3cdf8e1 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -58,6 +58,10 @@
int use_smbus;
int use_smbus_write;
+ ssize_t (*read_func)(struct at24_data *, char *, unsigned int, size_t);
+ ssize_t (*write_func)(struct at24_data *,
+ const char *, unsigned int, size_t);
+
/*
* Lock protects against activities from other Linux tasks,
* but not from changes by other I2C masters.
@@ -109,25 +113,63 @@
((1 << AT24_SIZE_FLAGS | (_flags)) \
<< AT24_SIZE_BYTELEN | ilog2(_len))
+/*
+ * Both reads and writes fail if the previous write didn't complete yet. This
+ * macro loops a few times waiting at least long enough for one entire page
+ * write to work while making sure that at least one iteration is run before
+ * checking the break condition.
+ *
+ * It takes two parameters: a variable in which the future timeout in jiffies
+ * will be stored and a temporary variable holding the time of the last
+ * iteration of processing the request. Both should be unsigned integers
+ * holding at least 32 bits.
+ */
+#define loop_until_timeout(tout, op_time) \
+ for (tout = jiffies + msecs_to_jiffies(write_timeout), op_time = 0; \
+ op_time ? time_before(op_time, tout) : true; \
+ usleep_range(1000, 1500), op_time = jiffies)
+
static const struct i2c_device_id at24_ids[] = {
/* needs 8 addresses as A0-A2 are ignored */
- { "24c00", AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) },
+ { "24c00", AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) },
/* old variants can't be handled with this generic entry! */
- { "24c01", AT24_DEVICE_MAGIC(1024 / 8, 0) },
- { "24c02", AT24_DEVICE_MAGIC(2048 / 8, 0) },
+ { "24c01", AT24_DEVICE_MAGIC(1024 / 8, 0) },
+ { "24cs01", AT24_DEVICE_MAGIC(16,
+ AT24_FLAG_SERIAL | AT24_FLAG_READONLY) },
+ { "24c02", AT24_DEVICE_MAGIC(2048 / 8, 0) },
+ { "24cs02", AT24_DEVICE_MAGIC(16,
+ AT24_FLAG_SERIAL | AT24_FLAG_READONLY) },
+ { "24mac402", AT24_DEVICE_MAGIC(48 / 8,
+ AT24_FLAG_MAC | AT24_FLAG_READONLY) },
+ { "24mac602", AT24_DEVICE_MAGIC(64 / 8,
+ AT24_FLAG_MAC | AT24_FLAG_READONLY) },
/* spd is a 24c02 in memory DIMMs */
- { "spd", AT24_DEVICE_MAGIC(2048 / 8,
- AT24_FLAG_READONLY | AT24_FLAG_IRUGO) },
- { "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) },
+ { "spd", AT24_DEVICE_MAGIC(2048 / 8,
+ AT24_FLAG_READONLY | AT24_FLAG_IRUGO) },
+ { "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) },
+ { "24cs04", AT24_DEVICE_MAGIC(16,
+ AT24_FLAG_SERIAL | AT24_FLAG_READONLY) },
/* 24rf08 quirk is handled at i2c-core */
- { "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) },
- { "24c16", AT24_DEVICE_MAGIC(16384 / 8, 0) },
- { "24c32", AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) },
- { "24c64", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) },
- { "24c128", AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) },
- { "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) },
- { "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) },
- { "24c1024", AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16) },
+ { "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) },
+ { "24cs08", AT24_DEVICE_MAGIC(16,
+ AT24_FLAG_SERIAL | AT24_FLAG_READONLY) },
+ { "24c16", AT24_DEVICE_MAGIC(16384 / 8, 0) },
+ { "24cs16", AT24_DEVICE_MAGIC(16,
+ AT24_FLAG_SERIAL | AT24_FLAG_READONLY) },
+ { "24c32", AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) },
+ { "24cs32", AT24_DEVICE_MAGIC(16,
+ AT24_FLAG_ADDR16 |
+ AT24_FLAG_SERIAL |
+ AT24_FLAG_READONLY) },
+ { "24c64", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) },
+ { "24cs64", AT24_DEVICE_MAGIC(16,
+ AT24_FLAG_ADDR16 |
+ AT24_FLAG_SERIAL |
+ AT24_FLAG_READONLY) },
+ { "24c128", AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) },
+ { "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) },
+ { "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) },
+ { "24c1024", AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16) },
{ "at24", 0 },
{ /* END OF LIST */ }
};
@@ -145,9 +187,22 @@
* This routine supports chips which consume multiple I2C addresses. It
* computes the addressing information to be used for a given r/w request.
* Assumes that sanity checks for offset happened at sysfs-layer.
+ *
+ * Slave address and byte offset derive from the offset. Always
+ * set the byte address; on a multi-master board, another master
+ * may have changed the chip's "current" address pointer.
+ *
+ * REVISIT some multi-address chips don't rollover page reads to
+ * the next slave address, so we may need to truncate the count.
+ * Those chips might need another quirk flag.
+ *
+ * If the real hardware used four adjacent 24c02 chips and that
+ * were misconfigured as one 24c08, that would be a similar effect:
+ * one "eeprom" file not four, but larger reads would fail when
+ * they crossed certain pages.
*/
static struct i2c_client *at24_translate_offset(struct at24_data *at24,
- unsigned *offset)
+ unsigned int *offset)
{
unsigned i;
@@ -162,89 +217,283 @@
return at24->client[i];
}
-static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
- unsigned offset, size_t count)
+static ssize_t at24_eeprom_read_smbus(struct at24_data *at24, char *buf,
+ unsigned int offset, size_t count)
{
- struct i2c_msg msg[2];
- u8 msgbuf[2];
- struct i2c_client *client;
unsigned long timeout, read_time;
- int status, i;
+ struct i2c_client *client;
+ int status;
- memset(msg, 0, sizeof(msg));
-
- /*
- * REVISIT some multi-address chips don't rollover page reads to
- * the next slave address, so we may need to truncate the count.
- * Those chips might need another quirk flag.
- *
- * If the real hardware used four adjacent 24c02 chips and that
- * were misconfigured as one 24c08, that would be a similar effect:
- * one "eeprom" file not four, but larger reads would fail when
- * they crossed certain pages.
- */
-
- /*
- * Slave address and byte offset derive from the offset. Always
- * set the byte address; on a multi-master board, another master
- * may have changed the chip's "current" address pointer.
- */
client = at24_translate_offset(at24, &offset);
if (count > io_limit)
count = io_limit;
- if (at24->use_smbus) {
- /* Smaller eeproms can work given some SMBus extension calls */
- if (count > I2C_SMBUS_BLOCK_MAX)
- count = I2C_SMBUS_BLOCK_MAX;
- } else {
- /*
- * When we have a better choice than SMBus calls, use a
- * combined I2C message. Write address; then read up to
- * io_limit data bytes. Note that read page rollover helps us
- * here (unlike writes). msgbuf is u8 and will cast to our
- * needs.
- */
- i = 0;
- if (at24->chip.flags & AT24_FLAG_ADDR16)
- msgbuf[i++] = offset >> 8;
- msgbuf[i++] = offset;
+ /* Smaller eeproms can work given some SMBus extension calls */
+ if (count > I2C_SMBUS_BLOCK_MAX)
+ count = I2C_SMBUS_BLOCK_MAX;
- msg[0].addr = client->addr;
- msg[0].buf = msgbuf;
- msg[0].len = i;
+ loop_until_timeout(timeout, read_time) {
+ status = i2c_smbus_read_i2c_block_data_or_emulated(client,
+ offset,
+ count, buf);
- msg[1].addr = client->addr;
- msg[1].flags = I2C_M_RD;
- msg[1].buf = buf;
- msg[1].len = count;
- }
-
- /*
- * Reads fail if the previous write didn't complete yet. We may
- * loop a few times until this one succeeds, waiting at least
- * long enough for one entire page write to work.
- */
- timeout = jiffies + msecs_to_jiffies(write_timeout);
- do {
- read_time = jiffies;
- if (at24->use_smbus) {
- status = i2c_smbus_read_i2c_block_data_or_emulated(client, offset,
- count, buf);
- } else {
- status = i2c_transfer(client->adapter, msg, 2);
- if (status == 2)
- status = count;
- }
dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n",
count, offset, status, jiffies);
if (status == count)
return count;
+ }
- usleep_range(1000, 1500);
- } while (time_before(read_time, timeout));
+ return -ETIMEDOUT;
+}
+
+static ssize_t at24_eeprom_read_i2c(struct at24_data *at24, char *buf,
+ unsigned int offset, size_t count)
+{
+ unsigned long timeout, read_time;
+ struct i2c_client *client;
+ struct i2c_msg msg[2];
+ int status, i;
+ u8 msgbuf[2];
+
+ memset(msg, 0, sizeof(msg));
+ client = at24_translate_offset(at24, &offset);
+
+ if (count > io_limit)
+ count = io_limit;
+
+ /*
+ * When we have a better choice than SMBus calls, use a combined I2C
+ * message. Write address; then read up to io_limit data bytes. Note
+ * that read page rollover helps us here (unlike writes). msgbuf is
+ * u8 and will cast to our needs.
+ */
+ i = 0;
+ if (at24->chip.flags & AT24_FLAG_ADDR16)
+ msgbuf[i++] = offset >> 8;
+ msgbuf[i++] = offset;
+
+ msg[0].addr = client->addr;
+ msg[0].buf = msgbuf;
+ msg[0].len = i;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = buf;
+ msg[1].len = count;
+
+ loop_until_timeout(timeout, read_time) {
+ status = i2c_transfer(client->adapter, msg, 2);
+ if (status == 2)
+ status = count;
+
+ dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n",
+ count, offset, status, jiffies);
+
+ if (status == count)
+ return count;
+ }
+
+ return -ETIMEDOUT;
+}
+
+static ssize_t at24_eeprom_read_serial(struct at24_data *at24, char *buf,
+ unsigned int offset, size_t count)
+{
+ unsigned long timeout, read_time;
+ struct i2c_client *client;
+ struct i2c_msg msg[2];
+ u8 addrbuf[2];
+ int status;
+
+ client = at24_translate_offset(at24, &offset);
+
+ memset(msg, 0, sizeof(msg));
+ msg[0].addr = client->addr;
+ msg[0].buf = addrbuf;
+
+ /*
+ * The address pointer of the device is shared between the regular
+ * EEPROM array and the serial number block. The dummy write (part of
+ * the sequential read protocol) ensures the address pointer is reset
+ * to the desired position.
+ */
+ if (at24->chip.flags & AT24_FLAG_ADDR16) {
+ /*
+ * For 16 bit address pointers, the word address must contain
+ * a '10' sequence in bits 11 and 10 regardless of the
+ * intended position of the address pointer.
+ */
+ addrbuf[0] = 0x08;
+ addrbuf[1] = offset;
+ msg[0].len = 2;
+ } else {
+ /*
+ * Otherwise the word address must begin with a '10' sequence,
+ * regardless of the intended address.
+ */
+ addrbuf[0] = 0x80 + offset;
+ msg[0].len = 1;
+ }
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = buf;
+ msg[1].len = count;
+
+ loop_until_timeout(timeout, read_time) {
+ status = i2c_transfer(client->adapter, msg, 2);
+ if (status == 2)
+ return count;
+ }
+
+ return -ETIMEDOUT;
+}
+
+static ssize_t at24_eeprom_read_mac(struct at24_data *at24, char *buf,
+ unsigned int offset, size_t count)
+{
+ unsigned long timeout, read_time;
+ struct i2c_client *client;
+ struct i2c_msg msg[2];
+ u8 addrbuf[2];
+ int status;
+
+ client = at24_translate_offset(at24, &offset);
+
+ memset(msg, 0, sizeof(msg));
+ msg[0].addr = client->addr;
+ msg[0].buf = addrbuf;
+ addrbuf[0] = 0x90 + offset;
+ msg[0].len = 1;
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = buf;
+ msg[1].len = count;
+
+ loop_until_timeout(timeout, read_time) {
+ status = i2c_transfer(client->adapter, msg, 2);
+ if (status == 2)
+ return count;
+ }
+
+ return -ETIMEDOUT;
+}
+
+/*
+ * Note that if the hardware write-protect pin is pulled high, the whole
+ * chip is normally write protected. But there are plenty of product
+ * variants here, including OTP fuses and partial chip protect.
+ *
+ * We only use page mode writes; the alternative is sloooow. These routines
+ * write at most one page.
+ */
+
+static size_t at24_adjust_write_count(struct at24_data *at24,
+ unsigned int offset, size_t count)
+{
+ unsigned next_page;
+
+ /* write_max is at most a page */
+ if (count > at24->write_max)
+ count = at24->write_max;
+
+ /* Never roll over backwards, to the start of this page */
+ next_page = roundup(offset + 1, at24->chip.page_size);
+ if (offset + count > next_page)
+ count = next_page - offset;
+
+ return count;
+}
+
+static ssize_t at24_eeprom_write_smbus_block(struct at24_data *at24,
+ const char *buf,
+ unsigned int offset, size_t count)
+{
+ unsigned long timeout, write_time;
+ struct i2c_client *client;
+ ssize_t status = 0;
+
+ client = at24_translate_offset(at24, &offset);
+ count = at24_adjust_write_count(at24, offset, count);
+
+ loop_until_timeout(timeout, write_time) {
+ status = i2c_smbus_write_i2c_block_data(client,
+ offset, count, buf);
+ if (status == 0)
+ status = count;
+
+ dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",
+ count, offset, status, jiffies);
+
+ if (status == count)
+ return count;
+ }
+
+ return -ETIMEDOUT;
+}
+
+static ssize_t at24_eeprom_write_smbus_byte(struct at24_data *at24,
+ const char *buf,
+ unsigned int offset, size_t count)
+{
+ unsigned long timeout, write_time;
+ struct i2c_client *client;
+ ssize_t status = 0;
+
+ client = at24_translate_offset(at24, &offset);
+
+ loop_until_timeout(timeout, write_time) {
+ status = i2c_smbus_write_byte_data(client, offset, buf[0]);
+ if (status == 0)
+ status = count;
+
+ dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",
+ count, offset, status, jiffies);
+
+ if (status == count)
+ return count;
+ }
+
+ return -ETIMEDOUT;
+}
+
+static ssize_t at24_eeprom_write_i2c(struct at24_data *at24, const char *buf,
+ unsigned int offset, size_t count)
+{
+ unsigned long timeout, write_time;
+ struct i2c_client *client;
+ struct i2c_msg msg;
+ ssize_t status = 0;
+ int i = 0;
+
+ client = at24_translate_offset(at24, &offset);
+ count = at24_adjust_write_count(at24, offset, count);
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+
+ /* msg.buf is u8 and casts will mask the values */
+ msg.buf = at24->writebuf;
+ if (at24->chip.flags & AT24_FLAG_ADDR16)
+ msg.buf[i++] = offset >> 8;
+
+ msg.buf[i++] = offset;
+ memcpy(&msg.buf[i], buf, count);
+ msg.len = i + count;
+
+ loop_until_timeout(timeout, write_time) {
+ status = i2c_transfer(client->adapter, &msg, 1);
+ if (status == 1)
+ status = count;
+
+ dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",
+ count, offset, status, jiffies);
+
+ if (status == count)
+ return count;
+ }
return -ETIMEDOUT;
}
@@ -266,7 +515,7 @@
while (count) {
int status;
- status = at24_eeprom_read(at24, buf, off, count);
+ status = at24->read_func(at24, buf, off, count);
if (status < 0) {
mutex_unlock(&at24->lock);
return status;
@@ -281,91 +530,6 @@
return 0;
}
-/*
- * Note that if the hardware write-protect pin is pulled high, the whole
- * chip is normally write protected. But there are plenty of product
- * variants here, including OTP fuses and partial chip protect.
- *
- * We only use page mode writes; the alternative is sloooow. This routine
- * writes at most one page.
- */
-static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
- unsigned offset, size_t count)
-{
- struct i2c_client *client;
- struct i2c_msg msg;
- ssize_t status = 0;
- unsigned long timeout, write_time;
- unsigned next_page;
-
- /* Get corresponding I2C address and adjust offset */
- client = at24_translate_offset(at24, &offset);
-
- /* write_max is at most a page */
- if (count > at24->write_max)
- count = at24->write_max;
-
- /* Never roll over backwards, to the start of this page */
- next_page = roundup(offset + 1, at24->chip.page_size);
- if (offset + count > next_page)
- count = next_page - offset;
-
- /* If we'll use I2C calls for I/O, set up the message */
- if (!at24->use_smbus) {
- int i = 0;
-
- msg.addr = client->addr;
- msg.flags = 0;
-
- /* msg.buf is u8 and casts will mask the values */
- msg.buf = at24->writebuf;
- if (at24->chip.flags & AT24_FLAG_ADDR16)
- msg.buf[i++] = offset >> 8;
-
- msg.buf[i++] = offset;
- memcpy(&msg.buf[i], buf, count);
- msg.len = i + count;
- }
-
- /*
- * Writes fail if the previous one didn't complete yet. We may
- * loop a few times until this one succeeds, waiting at least
- * long enough for one entire page write to work.
- */
- timeout = jiffies + msecs_to_jiffies(write_timeout);
- do {
- write_time = jiffies;
- if (at24->use_smbus_write) {
- switch (at24->use_smbus_write) {
- case I2C_SMBUS_I2C_BLOCK_DATA:
- status = i2c_smbus_write_i2c_block_data(client,
- offset, count, buf);
- break;
- case I2C_SMBUS_BYTE_DATA:
- status = i2c_smbus_write_byte_data(client,
- offset, buf[0]);
- break;
- }
-
- if (status == 0)
- status = count;
- } else {
- status = i2c_transfer(client->adapter, &msg, 1);
- if (status == 1)
- status = count;
- }
- dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",
- count, offset, status, jiffies);
-
- if (status == count)
- return count;
-
- usleep_range(1000, 1500);
- } while (time_before(write_time, timeout));
-
- return -ETIMEDOUT;
-}
-
static int at24_write(void *priv, unsigned int off, void *val, size_t count)
{
struct at24_data *at24 = priv;
@@ -383,7 +547,7 @@
while (count) {
int status;
- status = at24_eeprom_write(at24, buf, off, count);
+ status = at24->write_func(at24, buf, off, count);
if (status < 0) {
mutex_unlock(&at24->lock);
return status;
@@ -400,7 +564,7 @@
#ifdef CONFIG_OF
static void at24_get_ofdata(struct i2c_client *client,
- struct at24_platform_data *chip)
+ struct at24_platform_data *chip)
{
const __be32 *val;
struct device_node *node = client->dev.of_node;
@@ -415,7 +579,7 @@
}
#else
static void at24_get_ofdata(struct i2c_client *client,
- struct at24_platform_data *chip)
+ struct at24_platform_data *chip)
{ }
#endif /* CONFIG_OF */
@@ -518,6 +682,30 @@
at24->chip = chip;
at24->num_addresses = num_addresses;
+ if ((chip.flags & AT24_FLAG_SERIAL) && (chip.flags & AT24_FLAG_MAC)) {
+ dev_err(&client->dev,
+ "invalid device data - cannot have both AT24_FLAG_SERIAL & AT24_FLAG_MAC.");
+ return -EINVAL;
+ }
+
+ if (chip.flags & AT24_FLAG_SERIAL) {
+ at24->read_func = at24_eeprom_read_serial;
+ } else if (chip.flags & AT24_FLAG_MAC) {
+ at24->read_func = at24_eeprom_read_mac;
+ } else {
+ at24->read_func = at24->use_smbus ? at24_eeprom_read_smbus
+ : at24_eeprom_read_i2c;
+ }
+
+ if (at24->use_smbus) {
+ if (at24->use_smbus_write == I2C_SMBUS_I2C_BLOCK_DATA)
+ at24->write_func = at24_eeprom_write_smbus_block;
+ else
+ at24->write_func = at24_eeprom_write_smbus_byte;
+ } else {
+ at24->write_func = at24_eeprom_write_i2c;
+ }
+
writable = !(chip.flags & AT24_FLAG_READONLY);
if (writable) {
if (!use_smbus || use_smbus_write) {
diff --git a/include/linux/i2c-smbus.h b/include/linux/i2c-smbus.h
index 8f1b086..c2e3324 100644
--- a/include/linux/i2c-smbus.h
+++ b/include/linux/i2c-smbus.h
@@ -23,6 +23,8 @@
#define _LINUX_I2C_SMBUS_H
#include <linux/i2c.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
/**
@@ -48,4 +50,31 @@
struct i2c_smbus_alert_setup *setup);
int i2c_handle_smbus_alert(struct i2c_client *ara);
+/**
+ * smbus_host_notify - internal structure used by the Host Notify mechanism.
+ * @adapter: the I2C adapter associated with this struct
+ * @work: worker used to schedule the IRQ in the slave device
+ * @lock: spinlock to check if a notification is already pending
+ * @pending: flag set when a notification is pending (any new notification will
+ * be rejected if pending is true)
+ * @payload: the actual payload of the Host Notify event
+ * @addr: the address of the slave device which raised the notification
+ *
+ * This struct needs to be allocated by i2c_setup_smbus_host_notify() and does
+ * not need to be freed. Internally, i2c_setup_smbus_host_notify() uses a
+ * managed resource to clean this up when the adapter get released.
+ */
+struct smbus_host_notify {
+ struct i2c_adapter *adapter;
+ struct work_struct work;
+ spinlock_t lock;
+ bool pending;
+ u16 payload;
+ u8 addr;
+};
+
+struct smbus_host_notify *i2c_setup_smbus_host_notify(struct i2c_adapter *adap);
+int i2c_handle_smbus_host_notify(struct smbus_host_notify *host_notify,
+ unsigned short addr, unsigned int data);
+
#endif /* _LINUX_I2C_SMBUS_H */
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 96a25ae..fffdc27 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -126,6 +126,11 @@
u8 command, u8 length, u8 *values);
#endif /* I2C */
+enum i2c_alert_protocol {
+ I2C_PROTOCOL_SMBUS_ALERT,
+ I2C_PROTOCOL_SMBUS_HOST_NOTIFY,
+};
+
/**
* struct i2c_driver - represent an I2C device driver
* @class: What kind of i2c device we instantiate (for detect)
@@ -180,8 +185,11 @@
* The format and meaning of the data value depends on the protocol.
* For the SMBus alert protocol, there is a single bit of data passed
* as the alert response's low bit ("event flag").
+ * For the SMBus Host Notify protocol, the data corresponds to the
+ * 16-bit payload data reported by the slave device acting as master.
*/
- void (*alert)(struct i2c_client *, unsigned int data);
+ void (*alert)(struct i2c_client *, enum i2c_alert_protocol protocol,
+ unsigned int data);
/* a ioctl like command that can be used to perform specific functions
* with the device.
@@ -349,6 +357,11 @@
extern struct i2c_client *
i2c_new_dummy(struct i2c_adapter *adap, u16 address);
+extern struct i2c_client *
+i2c_new_secondary_device(struct i2c_client *client,
+ const char *name,
+ u16 default_addr);
+
extern void i2c_unregister_device(struct i2c_client *);
#endif /* I2C */
diff --git a/include/linux/platform_data/at24.h b/include/linux/platform_data/at24.h
index be830b1..271a4e2 100644
--- a/include/linux/platform_data/at24.h
+++ b/include/linux/platform_data/at24.h
@@ -10,6 +10,7 @@
#include <linux/types.h>
#include <linux/nvmem-consumer.h>
+#include <linux/bitops.h>
/**
* struct at24_platform_data - data to set up at24 (generic eeprom) driver
@@ -43,10 +44,12 @@
u32 byte_len; /* size (sum of all addr) */
u16 page_size; /* for writes */
u8 flags;
-#define AT24_FLAG_ADDR16 0x80 /* address pointer is 16 bit */
-#define AT24_FLAG_READONLY 0x40 /* sysfs-entry will be read-only */
-#define AT24_FLAG_IRUGO 0x20 /* sysfs-entry will be world-readable */
-#define AT24_FLAG_TAKE8ADDR 0x10 /* take always 8 addresses (24c00) */
+#define AT24_FLAG_ADDR16 BIT(7) /* address pointer is 16 bit */
+#define AT24_FLAG_READONLY BIT(6) /* sysfs-entry will be read-only */
+#define AT24_FLAG_IRUGO BIT(5) /* sysfs-entry will be world-readable */
+#define AT24_FLAG_TAKE8ADDR BIT(4) /* take always 8 addresses (24c00) */
+#define AT24_FLAG_SERIAL BIT(3) /* factory-programmed serial number */
+#define AT24_FLAG_MAC BIT(2) /* factory-programmed mac address */
void (*setup)(struct nvmem_device *nvmem, void *context);
void *context;
diff --git a/include/uapi/linux/i2c.h b/include/uapi/linux/i2c.h
index adcbef4..009e27bb 100644
--- a/include/uapi/linux/i2c.h
+++ b/include/uapi/linux/i2c.h
@@ -102,6 +102,7 @@
#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */
#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */
+#define I2C_FUNC_SMBUS_HOST_NOTIFY 0x10000000
#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \
I2C_FUNC_SMBUS_WRITE_BYTE)