Commit 66304207 authored by Linus Torvalds's avatar Linus Torvalds

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()
  ...
parents 7ae0ae4a 175c7080
...@@ -6,10 +6,20 @@ RK3xxx SoCs. ...@@ -6,10 +6,20 @@ RK3xxx SoCs.
Required properties : Required properties :
- reg : Offset and length of the register set for the device - reg : Offset and length of the register set for the device
- compatible : should be "rockchip,rk3066-i2c", "rockchip,rk3188-i2c", - compatible: should be one of the following:
"rockchip,rk3228-i2c" or "rockchip,rk3288-i2c". - "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 - 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 : Required on RK3066, RK3188 :
......
...@@ -62,6 +62,13 @@ wants to support one of the below features, it should adapt the bindings below. ...@@ -62,6 +62,13 @@ wants to support one of the below features, it should adapt the bindings below.
- wakeup-source - wakeup-source
device can be used as a 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 Binding may contain optional "interrupts" property, describing interrupts
used by the device. I2C core will assign "irq" interrupt (or the very first 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. interrupt if not using interrupt names) as primary interrupt for the slave.
......
...@@ -139,9 +139,9 @@ If you want to add slave support to the bus driver: ...@@ -139,9 +139,9 @@ If you want to add slave support to the bus driver:
* implement calls to register/unregister the slave and add those to the * implement calls to register/unregister the slave and add those to the
struct i2c_algorithm. When registering, you probably need to set the i2c 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 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 should use pm_runtime_get_sync() because your device usually needs to be
on always to be able to detect its slave address. When unregistering, do the powered on always to be able to detect its slave address. When unregistering,
inverse of the above. do the inverse of the above.
* Catch the slave interrupts and send appropriate i2c_slave_events to the backend. * Catch the slave interrupts and send appropriate i2c_slave_events to the backend.
...@@ -173,13 +173,14 @@ During development of this API, the question of using buffers instead of just ...@@ -173,13 +173,14 @@ During development of this API, the question of using buffers instead of just
bytes came up. Such an extension might be possible, usefulness is unclear at 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: 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 * Buffers should be opt-in and backend drivers will always have to support
byte-based transactions as the ultimate fallback because this is how the byte-based transactions as the ultimate fallback anyhow because this is how
majority of HW works. the majority of HW works.
* For backends simulating hardware registers, buffers are not helpful because * For backends simulating hardware registers, buffers are largely not helpful
on writes an action should be immediately triggered. For reads, the data in because after each byte written an action should be immediately triggered.
the buffer might get stale. 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 * 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 means additional code to handle this exception. Such code tends to be
......
...@@ -199,6 +199,12 @@ alerting device's address. ...@@ -199,6 +199,12 @@ alerting device's address.
[S] [HostAddr] [Wr] A [DevAddr] A [DataLow] A [DataHigh] A [P] [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) Packet Error Checking (PEC)
=========================== ===========================
......
...@@ -568,12 +568,16 @@ static void retry_timeout(unsigned long data) ...@@ -568,12 +568,16 @@ static void retry_timeout(unsigned long data)
} }
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); struct ssif_info *ssif_info = i2c_get_clientdata(client);
unsigned long oflags, *flags; unsigned long oflags, *flags;
bool do_get = false; bool do_get = false;
if (type != I2C_PROTOCOL_SMBUS_ALERT)
return;
ssif_inc_stat(ssif_info, alerts); ssif_inc_stat(ssif_info, alerts);
flags = ipmi_ssif_lock_cond(ssif_info, &oflags); flags = ipmi_ssif_lock_cond(ssif_info, &oflags);
......
...@@ -1719,10 +1719,14 @@ static int lm90_probe(struct i2c_client *client, ...@@ -1719,10 +1719,14 @@ static int lm90_probe(struct i2c_client *client,
return 0; 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; u16 alarms;
if (type != I2C_PROTOCOL_SMBUS_ALERT)
return;
if (lm90_is_tripped(client, &alarms)) { if (lm90_is_tripped(client, &alarms)) {
/* /*
* Disable ALERT# output, because these chips don't implement * Disable ALERT# output, because these chips don't implement
......
...@@ -88,8 +88,8 @@ config I2C_SMBUS ...@@ -88,8 +88,8 @@ config I2C_SMBUS
tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO
help help
Say Y here if you want support for SMBus extensions to the I2C Say Y here if you want support for SMBus extensions to the I2C
specification. At the moment, the only supported extension is specification. At the moment, two extensions are supported:
the SMBus alert protocol. the SMBus Alert protocol and the SMBus Host Notify protocol.
This support is also available as a module. If so, the module This support is also available as a module. If so, the module
will be called i2c-smbus. will be called i2c-smbus.
......
...@@ -91,6 +91,7 @@ config I2C_I801 ...@@ -91,6 +91,7 @@ config I2C_I801
tristate "Intel 82801 (ICH/PCH)" tristate "Intel 82801 (ICH/PCH)"
depends on PCI depends on PCI
select CHECK_SIGNATURE if X86 && DMI select CHECK_SIGNATURE if X86 && DMI
select I2C_SMBUS
help help
If you say yes to this option, support will be included for the Intel If you say yes to this option, support will be included for the Intel
801 family of mainboard I2C interfaces. Specifically, the following 801 family of mainboard I2C interfaces. Specifically, the following
...@@ -397,7 +398,7 @@ config I2C_BCM_KONA ...@@ -397,7 +398,7 @@ config I2C_BCM_KONA
config I2C_BRCMSTB config I2C_BRCMSTB
tristate "BRCM Settop I2C controller" tristate "BRCM Settop I2C controller"
depends on ARCH_BRCMSTB || COMPILE_TEST depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
default y default y
help help
If you say yes to this option, support will be included for the If you say yes to this option, support will be included for the
...@@ -490,7 +491,9 @@ config I2C_DESIGNWARE_PCI ...@@ -490,7 +491,9 @@ config I2C_DESIGNWARE_PCI
config I2C_DESIGNWARE_BAYTRAIL config I2C_DESIGNWARE_BAYTRAIL
bool "Intel Baytrail I2C semaphore support" 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 help
This driver enables managed host access to the PMIC I2C bus on select This driver enables managed host access to the PMIC I2C bus on select
Intel BayTrail platforms using the X-Powers AXP288 PMIC. It allows Intel BayTrail platforms using the X-Powers AXP288 PMIC. It allows
...@@ -635,7 +638,7 @@ config I2C_LPC2K ...@@ -635,7 +638,7 @@ config I2C_LPC2K
config I2C_MESON config I2C_MESON
tristate "Amlogic Meson I2C controller" tristate "Amlogic Meson I2C controller"
depends on ARCH_MESON depends on ARCH_MESON || COMPILE_TEST
help help
If you say yes to this option, support will be included for the If you say yes to this option, support will be included for the
I2C interface on the Amlogic Meson family of SoCs. I2C interface on the Amlogic Meson family of SoCs.
...@@ -924,7 +927,7 @@ config I2C_UNIPHIER_F ...@@ -924,7 +927,7 @@ config I2C_UNIPHIER_F
config I2C_VERSATILE config I2C_VERSATILE
tristate "ARM Versatile/Realview I2C bus support" 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 select I2C_ALGOBIT
help help
Say yes if you want to support the I2C serial bus on ARMs Versatile Say yes if you want to support the I2C serial bus on ARMs Versatile
......
...@@ -253,6 +253,7 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) ...@@ -253,6 +253,7 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
i2c_dev->clk = devm_clk_get(&pdev->dev, NULL); i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(i2c_dev->clk)) { if (IS_ERR(i2c_dev->clk)) {
if (PTR_ERR(i2c_dev->clk) != -EPROBE_DEFER)
dev_err(&pdev->dev, "Could not get clock\n"); dev_err(&pdev->dev, "Could not get clock\n");
return PTR_ERR(i2c_dev->clk); return PTR_ERR(i2c_dev->clk);
} }
......
...@@ -343,10 +343,9 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev, ...@@ -343,10 +343,9 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev,
struct bsc_regs *pi2creg = dev->bsc_regmap; struct bsc_regs *pi2creg = dev->bsc_regmap;
int no_ack = pmsg->flags & I2C_M_IGNORE_NAK; int no_ack = pmsg->flags & I2C_M_IGNORE_NAK;
int data_regsz = brcmstb_i2c_get_data_regsz(dev); 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 */ /* 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 = (pmsg->flags & I2C_M_RD) ? CMD_RD_NOACK
: CMD_WR_NOACK; : CMD_WR_NOACK;
pi2creg->ctlhi_reg |= BSC_CTLHI_REG_IGNORE_ACK_MASK; pi2creg->ctlhi_reg |= BSC_CTLHI_REG_IGNORE_ACK_MASK;
......
...@@ -663,7 +663,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ...@@ -663,7 +663,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
i2c_dw_xfer_init(dev); i2c_dw_xfer_init(dev);
/* wait for tx to complete */ /* 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"); dev_err(dev->dev, "controller timed out\n");
/* i2c_dw_init implicitly disables the adapter */ /* i2c_dw_init implicitly disables the adapter */
i2c_dw_init(dev); i2c_dw_init(dev);
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#define DW_IC_CON_MASTER 0x1 #define DW_IC_CON_MASTER 0x1
#define DW_IC_CON_SPEED_STD 0x2 #define DW_IC_CON_SPEED_STD 0x2
#define DW_IC_CON_SPEED_FAST 0x4 #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_10BITADDR_MASTER 0x10
#define DW_IC_CON_RESTART_EN 0x20 #define DW_IC_CON_RESTART_EN 0x20
#define DW_IC_CON_SLAVE_DISABLE 0x40 #define DW_IC_CON_SLAVE_DISABLE 0x40
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Copyright (C) 2006 Texas Instruments. * Copyright (C) 2006 Texas Instruments.
* Copyright (C) 2007 MontaVista Software Inc. * Copyright (C) 2007 MontaVista Software Inc.
* Copyright (C) 2009 Provigent Ltd. * Copyright (C) 2009 Provigent Ltd.
* Copyright (C) 2011, 2015 Intel Corporation. * Copyright (C) 2011, 2015, 2016 Intel Corporation.
* *
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
...@@ -23,31 +23,27 @@ ...@@ -23,31 +23,27 @@
* *
*/ */
#include <linux/kernel.h> #include <linux/acpi.h>
#include <linux/module.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/errno.h>
#include <linux/i2c.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/slab.h> #include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/acpi.h> #include <linux/sched.h>
#include <linux/slab.h>
#include "i2c-designware-core.h" #include "i2c-designware-core.h"
#define DRIVER_NAME "i2c-designware-pci" #define DRIVER_NAME "i2c-designware-pci"
enum dw_pci_ctl_id_t { enum dw_pci_ctl_id_t {
medfield_0, medfield,
medfield_1, merrifield,
medfield_2,
medfield_3,
medfield_4,
medfield_5,
baytrail, baytrail,
haswell, haswell,
}; };
...@@ -68,6 +64,7 @@ struct dw_pci_controller { ...@@ -68,6 +64,7 @@ struct dw_pci_controller {
u32 clk_khz; u32 clk_khz;
u32 functionality; u32 functionality;
struct dw_scl_sda_cfg *scl_sda_cfg; 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 | \ #define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \
...@@ -80,6 +77,14 @@ struct dw_pci_controller { ...@@ -80,6 +77,14 @@ struct dw_pci_controller {
I2C_FUNC_SMBUS_WORD_DATA | \ I2C_FUNC_SMBUS_WORD_DATA | \
I2C_FUNC_SMBUS_I2C_BLOCK) 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 */ /* BayTrail HCNT/LCNT/SDA hold time */
static struct dw_scl_sda_cfg byt_config = { static struct dw_scl_sda_cfg byt_config = {
.ss_hcnt = 0x200, .ss_hcnt = 0x200,
...@@ -98,48 +103,60 @@ static struct dw_scl_sda_cfg hsw_config = { ...@@ -98,48 +103,60 @@ static struct dw_scl_sda_cfg hsw_config = {
.sda_hold = 0x9, .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[] = { static struct dw_pci_controller dw_pci_controllers[] = {
[medfield_0] = { [medfield] = {
.bus_num = 0, .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_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, .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32, .tx_fifo_depth = 32,
.rx_fifo_depth = 32, .rx_fifo_depth = 32,
.clk_khz = 25000, .clk_khz = 25000,
.setup = mfld_setup,
}, },
[medfield_5] = { [merrifield] = {
.bus_num = 5, .bus_num = -1,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32, .tx_fifo_depth = 64,
.rx_fifo_depth = 32, .rx_fifo_depth = 64,
.clk_khz = 25000, .scl_sda_cfg = &mrfld_config,
.setup = mrfld_setup,
}, },
[baytrail] = { [baytrail] = {
.bus_num = -1, .bus_num = -1,
...@@ -224,6 +241,13 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, ...@@ -224,6 +241,13 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
dev->base = pcim_iomap_table(pdev)[0]; dev->base = pcim_iomap_table(pdev)[0];
dev->dev = &pdev->dev; dev->dev = &pdev->dev;
dev->irq = pdev->irq; dev->irq = pdev->irq;
if (controller->setup) {
r = controller->setup(pdev, controller);
if (r)
return r;
}
dev->functionality = controller->functionality | dev->functionality = controller->functionality |
DW_DEFAULT_FUNCTIONALITY; DW_DEFAULT_FUNCTIONALITY;
...@@ -276,12 +300,15 @@ MODULE_ALIAS("i2c_designware-pci"); ...@@ -276,12 +300,15 @@ MODULE_ALIAS("i2c_designware-pci");
static const struct pci_device_id i2_designware_pci_ids[] = { static const struct pci_device_id i2_designware_pci_ids[] = {
/* Medfield */ /* Medfield */
{ PCI_VDEVICE(INTEL, 0x0817), medfield_3 }, { PCI_VDEVICE(INTEL, 0x0817), medfield },
{ PCI_VDEVICE(INTEL, 0x0818), medfield_4 }, { PCI_VDEVICE(INTEL, 0x0818), medfield },
{ PCI_VDEVICE(INTEL, 0x0819), medfield_5 }, { PCI_VDEVICE(INTEL, 0x0819), medfield },
{ PCI_VDEVICE(INTEL, 0x082C), medfield_0 }, { PCI_VDEVICE(INTEL, 0x082C), medfield },
{ PCI_VDEVICE(INTEL, 0x082D), medfield_1 }, { PCI_VDEVICE(INTEL, 0x082D), medfield },
{ PCI_VDEVICE(INTEL, 0x082E), medfield_2 }, { PCI_VDEVICE(INTEL, 0x082E), medfield },
/* Merrifield */
{ PCI_VDEVICE(INTEL, 0x1195), merrifield },
{ PCI_VDEVICE(INTEL, 0x1196), merrifield },
/* Baytrail */ /* Baytrail */
{ PCI_VDEVICE(INTEL, 0x0F41), baytrail }, { PCI_VDEVICE(INTEL, 0x0F41), baytrail },
{ PCI_VDEVICE(INTEL, 0x0F42), baytrail }, { PCI_VDEVICE(INTEL, 0x0F42), baytrail },
......
...@@ -433,7 +433,7 @@ static int efm32_i2c_probe(struct platform_device *pdev) ...@@ -433,7 +433,7 @@ static int efm32_i2c_probe(struct platform_device *pdev)
ret = request_irq(ddata->irq, efm32_i2c_irq, 0, DRIVER_NAME, ddata); ret = request_irq(ddata->irq, efm32_i2c_irq, 0, DRIVER_NAME, ddata);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "failed to request irq (%d)\n", ret); dev_err(&pdev->dev, "failed to request irq (%d)\n", ret);
return ret; goto err_disable_clk;
} }
ret = i2c_add_adapter(&ddata->adapter); ret = i2c_add_adapter(&ddata->adapter);
......
...@@ -319,16 +319,6 @@ static struct isa_driver i2c_elektor_driver = { ...@@ -319,16 +319,6 @@ static struct isa_driver i2c_elektor_driver = {
}, },
}; };
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_AUTHOR("Hans Berglund <hb@spacetec.no>");
MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter"); MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -338,6 +328,4 @@ module_param(irq, int, 0); ...@@ -338,6 +328,4 @@ module_param(irq, int, 0);
module_param(clock, int, 0); module_param(clock, int, 0);
module_param(own, int, 0); module_param(own, int, 0);
module_param(mmapped, int, 0); module_param(mmapped, int, 0);
module_isa_driver(i2c_elektor_driver, 1);
module_init(i2c_pcfisa_init);
module_exit(i2c_pcfisa_exit);
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
* Block process call transaction no * Block process call transaction no
* I2C block read transaction yes (doesn't use the block buffer) * I2C block read transaction yes (doesn't use the block buffer)
* Slave mode no * Slave mode no
* SMBus Host Notify yes
* Interrupt processing yes * Interrupt processing yes
* *
* See the file Documentation/i2c/busses/i2c-i801 for details. * See the file Documentation/i2c/busses/i2c-i801 for details.
...@@ -86,6 +87,7 @@ ...@@ -86,6 +87,7 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-smbus.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/dmi.h> #include <linux/dmi.h>
...@@ -96,8 +98,7 @@ ...@@ -96,8 +98,7 @@
#include <linux/platform_data/itco_wdt.h> #include <linux/platform_data/itco_wdt.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \ #if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
defined CONFIG_DMI
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/i2c-mux-gpio.h> #include <linux/i2c-mux-gpio.h>
#endif #endif
...@@ -113,6 +114,10 @@ ...@@ -113,6 +114,10 @@
#define SMBPEC(p) (8 + (p)->smba) /* ICH3 and later */ #define SMBPEC(p) (8 + (p)->smba) /* ICH3 and later */
#define SMBAUXSTS(p) (12 + (p)->smba) /* ICH4 and later */ #define SMBAUXSTS(p) (12 + (p)->smba) /* ICH4 and later */
#define SMBAUXCTL(p) (13 + (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 */ /* PCI Address Constants */
#define SMBBAR 4 #define SMBBAR 4
...@@ -144,6 +149,10 @@ ...@@ -144,6 +149,10 @@
/* TCO configuration bits for TCOCTL */ /* TCO configuration bits for TCOCTL */
#define TCOCTL_EN 0x0100 #define TCOCTL_EN 0x0100
/* Auxiliary status register bits, ICH4+ only */
#define SMBAUXSTS_CRCE 1
#define SMBAUXSTS_STCO 2
/* Auxiliary control register bits, ICH4+ only */ /* Auxiliary control register bits, ICH4+ only */
#define SMBAUXCTL_CRC 1 #define SMBAUXCTL_CRC 1
#define SMBAUXCTL_E32B 2 #define SMBAUXCTL_E32B 2
...@@ -177,6 +186,12 @@ ...@@ -177,6 +186,12 @@
#define SMBHSTSTS_INTR 0x02 #define SMBHSTSTS_INTR 0x02
#define SMBHSTSTS_HOST_BUSY 0x01 #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 | \ #define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | \
SMBHSTSTS_DEV_ERR) SMBHSTSTS_DEV_ERR)
...@@ -239,8 +254,7 @@ struct i801_priv { ...@@ -239,8 +254,7 @@ struct i801_priv {
int len; int len;
u8 *data; u8 *data;
#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \ #if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
defined CONFIG_DMI
const struct i801_mux_config *mux_drvdata; const struct i801_mux_config *mux_drvdata;
struct platform_device *mux_pdev; struct platform_device *mux_pdev;
#endif #endif
...@@ -252,13 +266,17 @@ struct i801_priv { ...@@ -252,13 +266,17 @@ struct i801_priv {
*/ */
bool acpi_reserved; bool acpi_reserved;
struct mutex acpi_lock; struct mutex acpi_lock;
struct smbus_host_notify *host_notify;
}; };
#define SMBHSTNTFY_SIZE 8
#define FEATURE_SMBUS_PEC (1 << 0) #define FEATURE_SMBUS_PEC (1 << 0)
#define FEATURE_BLOCK_BUFFER (1 << 1) #define FEATURE_BLOCK_BUFFER (1 << 1)
#define FEATURE_BLOCK_PROC (1 << 2) #define FEATURE_BLOCK_PROC (1 << 2)
#define FEATURE_I2C_BLOCK_READ (1 << 3) #define FEATURE_I2C_BLOCK_READ (1 << 3)
#define FEATURE_IRQ (1 << 4) #define FEATURE_IRQ (1 << 4)
#define FEATURE_HOST_NOTIFY (1 << 5)
/* Not really a feature, but it's convenient to handle it as such */ /* Not really a feature, but it's convenient to handle it as such */
#define FEATURE_IDF (1 << 15) #define FEATURE_IDF (1 << 15)
#define FEATURE_TCO (1 << 16) #define FEATURE_TCO (1 << 16)
...@@ -269,6 +287,7 @@ static const char *i801_feature_names[] = { ...@@ -269,6 +287,7 @@ static const char *i801_feature_names[] = {
"Block process call", "Block process call",
"I2C block read", "I2C block read",
"Interrupt", "Interrupt",
"SMBus Host Notify",
}; };
static unsigned int disable_features; static unsigned int disable_features;
...@@ -277,7 +296,8 @@ MODULE_PARM_DESC(disable_features, "Disable selected driver features:\n" ...@@ -277,7 +296,8 @@ MODULE_PARM_DESC(disable_features, "Disable selected driver features:\n"
"\t\t 0x01 disable SMBus PEC\n" "\t\t 0x01 disable SMBus PEC\n"
"\t\t 0x02 disable the block buffer\n" "\t\t 0x02 disable the block buffer\n"
"\t\t 0x08 disable the I2C block read functionality\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. /* Make sure the SMBus host is ready to start transmitting.
Return 0 if it is, -EBUSY if it is not. */ Return 0 if it is, -EBUSY if it is not. */
...@@ -305,6 +325,29 @@ static int i801_check_pre(struct i801_priv *priv) ...@@ -305,6 +325,29 @@ static int i801_check_pre(struct i801_priv *priv)
} }
} }
/*
* 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; return 0;
} }
...@@ -348,9 +391,31 @@ static int i801_check_post(struct i801_priv *priv, int status) ...@@ -348,9 +391,31 @@ static int i801_check_post(struct i801_priv *priv, int status)
dev_err(&priv->pci_dev->dev, "Transaction failed\n"); dev_err(&priv->pci_dev->dev, "Transaction failed\n");
} }
if (status & SMBHSTSTS_DEV_ERR) { if (status & SMBHSTSTS_DEV_ERR) {
/*
* 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; result = -ENXIO;
dev_dbg(&priv->pci_dev->dev, "No response\n"); dev_dbg(&priv->pci_dev->dev, "No response\n");
} }
}
if (status & SMBHSTSTS_BUS_ERR) { if (status & SMBHSTSTS_BUS_ERR) {
result = -EAGAIN; result = -EAGAIN;
dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n"); dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n");
...@@ -511,8 +576,23 @@ static void i801_isr_byte_done(struct i801_priv *priv) ...@@ -511,8 +576,23 @@ static void i801_isr_byte_done(struct i801_priv *priv)
outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); 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: * 1) i801 signals transaction completion with one of these interrupts:
* INTR - Success * INTR - Success
...@@ -524,6 +604,8 @@ static void i801_isr_byte_done(struct i801_priv *priv) ...@@ -524,6 +604,8 @@ static void i801_isr_byte_done(struct i801_priv *priv)
* *
* 2) For byte-by-byte (I2C read/write) transactions, one BYTE_DONE interrupt * 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. * 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) static irqreturn_t i801_isr(int irq, void *dev_id)
{ {
...@@ -536,6 +618,12 @@ static irqreturn_t i801_isr(int irq, void *dev_id) ...@@ -536,6 +618,12 @@ static irqreturn_t i801_isr(int irq, void *dev_id)
if (!(pcists & SMBPCISTS_INTS)) if (!(pcists & SMBPCISTS_INTS))
return IRQ_NONE; 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)); status = inb_p(SMBHSTSTS(priv));
if (status & SMBHSTSTS_BYTE_DONE) if (status & SMBHSTSTS_BYTE_DONE)
i801_isr_byte_done(priv); i801_isr_byte_done(priv);
...@@ -547,7 +635,7 @@ static irqreturn_t i801_isr(int irq, void *dev_id) ...@@ -547,7 +635,7 @@ static irqreturn_t i801_isr(int irq, void *dev_id)
status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS; status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS;
if (status) { if (status) {
outb_p(status, SMBHSTSTS(priv)); outb_p(status, SMBHSTSTS(priv));
priv->status |= status; priv->status = status;
wake_up(&priv->waitq); wake_up(&priv->waitq);
} }
...@@ -847,7 +935,28 @@ static u32 i801_func(struct i2c_adapter *adapter) ...@@ -847,7 +935,28 @@ static u32 i801_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
((priv->features & FEATURE_I2C_BLOCK_READ) ? ((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 = { static const struct i2c_algorithm smbus_algorithm = {
...@@ -1022,8 +1131,7 @@ static void __init input_apanel_init(void) {} ...@@ -1022,8 +1131,7 @@ static void __init input_apanel_init(void) {}
static void i801_probe_optional_slaves(struct i801_priv *priv) {} static void i801_probe_optional_slaves(struct i801_priv *priv) {}
#endif /* CONFIG_X86 && CONFIG_DMI */ #endif /* CONFIG_X86 && CONFIG_DMI */
#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \ #if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
defined CONFIG_DMI
static struct i801_mux_config i801_mux_config_asus_z8_d12 = { static struct i801_mux_config i801_mux_config_asus_z8_d12 = {
.gpio_chip = "gpio_ich", .gpio_chip = "gpio_ich",
.values = { 0x02, 0x03 }, .values = { 0x02, 0x03 },
...@@ -1379,6 +1487,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -1379,6 +1487,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
priv->features |= FEATURE_SMBUS_PEC; priv->features |= FEATURE_SMBUS_PEC;
priv->features |= FEATURE_BLOCK_BUFFER; priv->features |= FEATURE_BLOCK_BUFFER;
priv->features |= FEATURE_TCO; priv->features |= FEATURE_TCO;
priv->features |= FEATURE_HOST_NOTIFY;
break; break;
case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0: case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0:
...@@ -1398,6 +1507,8 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -1398,6 +1507,8 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
priv->features |= FEATURE_BLOCK_BUFFER; priv->features |= FEATURE_BLOCK_BUFFER;
/* fall through */ /* fall through */
case PCI_DEVICE_ID_INTEL_82801CA_3: 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_82801BA_2:
case PCI_DEVICE_ID_INTEL_82801AB_3: case PCI_DEVICE_ID_INTEL_82801AB_3:
case PCI_DEVICE_ID_INTEL_82801AA_3: case PCI_DEVICE_ID_INTEL_82801AA_3:
...@@ -1507,6 +1618,15 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -1507,6 +1618,15 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
return err; 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); i801_probe_optional_slaves(priv);
/* We ignore errors - multiplexing is optional */ /* We ignore errors - multiplexing is optional */
i801_add_mux(priv); i801_add_mux(priv);
...@@ -1553,6 +1673,14 @@ static int i801_suspend(struct device *dev) ...@@ -1553,6 +1673,14 @@ static int i801_suspend(struct device *dev)
static int i801_resume(struct device *dev) static int i801_resume(struct device *dev)
{ {
struct pci_dev *pci_dev = to_pci_dev(dev);
struct i801_priv *priv = pci_get_drvdata(pci_dev);
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; return 0;
} }
#endif #endif
......
...@@ -791,10 +791,6 @@ static int jz4780_i2c_probe(struct platform_device *pdev) ...@@ -791,10 +791,6 @@ static int jz4780_i2c_probe(struct platform_device *pdev)
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0x0); 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); i2c->irq = platform_get_irq(pdev, 0);
ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0, ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0,
dev_name(&pdev->dev), i2c); dev_name(&pdev->dev), i2c);
......
...@@ -193,23 +193,12 @@ static struct isa_driver pca_isa_driver = { ...@@ -193,23 +193,12 @@ static struct isa_driver pca_isa_driver = {
} }
}; };
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_AUTHOR("Ian Campbell <icampbell@arcom.com>");
MODULE_DESCRIPTION("ISA base PCA9564/PCA9665 driver"); MODULE_DESCRIPTION("ISA base PCA9564/PCA9665 driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
module_param(base, ulong, 0); module_param(base, ulong, 0);
MODULE_PARM_DESC(base, "I/O base address"); MODULE_PARM_DESC(base, "I/O base address");
module_param(irq, int, 0); module_param(irq, int, 0);
MODULE_PARM_DESC(irq, "IRQ"); MODULE_PARM_DESC(irq, "IRQ");
module_param(clock, int, 0); module_param(clock, int, 0);
...@@ -220,6 +209,4 @@ MODULE_PARM_DESC(clock, "Clock rate in hertz.\n\t\t" ...@@ -220,6 +209,4 @@ MODULE_PARM_DESC(clock, "Clock rate in hertz.\n\t\t"
"\t\t\t\tFast: 100100 - 400099\n" "\t\t\t\tFast: 100100 - 400099\n"
"\t\t\t\tFast+: 400100 - 10000099\n" "\t\t\t\tFast+: 400100 - 10000099\n"
"\t\t\t\tTurbo: Up to 1265800"); "\t\t\t\tTurbo: Up to 1265800");
module_isa_driver(pca_isa_driver, 1);
module_init(pca_isa_init);
module_exit(pca_isa_exit);
...@@ -213,14 +213,16 @@ static irqreturn_t qup_i2c_interrupt(int irq, void *dev) ...@@ -213,14 +213,16 @@ static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
bus_err &= I2C_STATUS_ERROR_MASK; bus_err &= I2C_STATUS_ERROR_MASK;
qup_err &= QUP_STATUS_ERROR_FLAGS; qup_err &= QUP_STATUS_ERROR_FLAGS;
if (qup_err) { /* Clear the error bits in QUP_ERROR_FLAGS */
/* Clear Error interrupt */ if (qup_err)
writel(qup_err, qup->base + QUP_ERROR_FLAGS); writel(qup_err, qup->base + QUP_ERROR_FLAGS);
goto done;
}
if (bus_err) { /* Clear the error bits in QUP_I2C_STATUS */
/* Clear Error interrupt */ 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); writel(QUP_RESET_STATE, qup->base + QUP_STATE);
goto done; goto done;
} }
...@@ -310,6 +312,7 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, ...@@ -310,6 +312,7 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val,
u32 opflags; u32 opflags;
u32 status; u32 status;
u32 shift = __ffs(op); u32 shift = __ffs(op);
int ret = 0;
len *= qup->one_byte_t; len *= qup->one_byte_t;
/* timeout after a wait of twice the max time */ /* timeout after a wait of twice the max time */
...@@ -321,18 +324,28 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val, ...@@ -321,18 +324,28 @@ static int qup_i2c_wait_ready(struct qup_i2c_dev *qup, int op, bool val,
if (((opflags & op) >> shift) == val) { if (((opflags & op) >> shift) == val) {
if ((op == QUP_OUT_NOT_EMPTY) && qup->is_last) { if ((op == QUP_OUT_NOT_EMPTY) && qup->is_last) {
if (!(status & I2C_STATUS_BUS_ACTIVE)) if (!(status & I2C_STATUS_BUS_ACTIVE)) {
return 0; ret = 0;
goto done;
}
} else { } else {
return 0; ret = 0;
goto done;
} }
} }
if (time_after(jiffies, timeout)) if (time_after(jiffies, timeout)) {
return -ETIMEDOUT; ret = -ETIMEDOUT;
goto done;
}
usleep_range(len, len * 2); 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, static void qup_i2c_set_write_mode_v2(struct qup_i2c_dev *qup,
...@@ -585,8 +598,8 @@ static void qup_i2c_bam_cb(void *data) ...@@ -585,8 +598,8 @@ static void qup_i2c_bam_cb(void *data)
} }
static int qup_sg_set_buf(struct scatterlist *sg, void *buf, static int qup_sg_set_buf(struct scatterlist *sg, void *buf,
struct qup_i2c_tag *tg, unsigned int buflen, unsigned int buflen, struct qup_i2c_dev *qup,
struct qup_i2c_dev *qup, int map, int dir) int dir)
{ {
int ret; int ret;
...@@ -595,9 +608,6 @@ static int qup_sg_set_buf(struct scatterlist *sg, void *buf, ...@@ -595,9 +608,6 @@ static int qup_sg_set_buf(struct scatterlist *sg, void *buf,
if (!ret) if (!ret)
return -EINVAL; return -EINVAL;
if (!map)
sg_dma_address(sg) = tg->addr + ((u8 *)buf - tg->start);
return 0; return 0;
} }
...@@ -649,37 +659,37 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, ...@@ -649,37 +659,37 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
u8 *tags; u8 *tags;
while (idx < num) { while (idx < num) {
blocks = (msg->len + limit) / limit;
rem = msg->len % limit;
tx_len = 0, len = 0, i = 0; tx_len = 0, len = 0, i = 0;
qup->is_last = (idx == (num - 1)); qup->is_last = (idx == (num - 1));
qup_i2c_set_blk_data(qup, msg); qup_i2c_set_blk_data(qup, msg);
blocks = qup->blk.count;
rem = msg->len - (blocks - 1) * limit;
if (msg->flags & I2C_M_RD) { if (msg->flags & I2C_M_RD) {
rx_nents += (blocks * 2) + 1; rx_nents += (blocks * 2) + 1;
tx_nents += 1; tx_nents += 1;
while (qup->blk.pos < blocks) { while (qup->blk.pos < blocks) {
/* length set to '0' implies 256 bytes */ tlen = (i == (blocks - 1)) ? rem : limit;
tlen = (i == (blocks - 1)) ? rem : 0;
tags = &qup->start_tag.start[off + len]; tags = &qup->start_tag.start[off + len];
len += qup_i2c_set_tags(tags, qup, msg, 1); len += qup_i2c_set_tags(tags, qup, msg, 1);
qup->blk.data_len -= tlen;
/* scratch buf to read the start and len tags */ /* scratch buf to read the start and len tags */
ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++], ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
&qup->brx.tag.start[0], &qup->brx.tag.start[0],
&qup->brx.tag, 2, qup, DMA_FROM_DEVICE);
2, qup, 0, 0);
if (ret) if (ret)
return ret; return ret;
ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++], ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
&msg->buf[limit * i], &msg->buf[limit * i],
NULL, tlen, qup, tlen, qup,
1, DMA_FROM_DEVICE); DMA_FROM_DEVICE);
if (ret) if (ret)
return ret; return ret;
...@@ -688,7 +698,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, ...@@ -688,7 +698,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
} }
ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
&qup->start_tag.start[off], &qup->start_tag.start[off],
&qup->start_tag, len, qup, 0, 0); len, qup, DMA_TO_DEVICE);
if (ret) if (ret)
return ret; return ret;
...@@ -696,30 +706,28 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, ...@@ -696,30 +706,28 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
/* scratch buf to read the BAM EOT and FLUSH tags */ /* scratch buf to read the BAM EOT and FLUSH tags */
ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++], ret = qup_sg_set_buf(&qup->brx.sg[rx_buf++],
&qup->brx.tag.start[0], &qup->brx.tag.start[0],
&qup->brx.tag, 2, 2, qup, DMA_FROM_DEVICE);
qup, 0, 0);
if (ret) if (ret)
return ret; return ret;
} else { } else {
tx_nents += (blocks * 2); tx_nents += (blocks * 2);
while (qup->blk.pos < blocks) { 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]; tags = &qup->start_tag.start[off + tx_len];
len = qup_i2c_set_tags(tags, qup, msg, 1); len = qup_i2c_set_tags(tags, qup, msg, 1);
qup->blk.data_len -= tlen;
ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
tags, tags, len,
&qup->start_tag, len, qup, DMA_TO_DEVICE);
qup, 0, 0);
if (ret) if (ret)
return ret; return ret;
tx_len += len; tx_len += len;
ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
&msg->buf[limit * i], &msg->buf[limit * i],
NULL, tlen, qup, 1, tlen, qup, DMA_TO_DEVICE);
DMA_TO_DEVICE);
if (ret) if (ret)
return ret; return ret;
i++; i++;
...@@ -738,8 +746,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, ...@@ -738,8 +746,7 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
QUP_BAM_FLUSH_STOP; QUP_BAM_FLUSH_STOP;
ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++], ret = qup_sg_set_buf(&qup->btx.sg[tx_buf++],
&qup->btx.tag.start[0], &qup->btx.tag.start[0],
&qup->btx.tag, len, len, qup, DMA_TO_DEVICE);
qup, 0, 0);
if (ret) if (ret)
return ret; return ret;
tx_nents += 1; tx_nents += 1;
...@@ -801,22 +808,16 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, ...@@ -801,22 +808,16 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
} }
if (ret || qup->bus_err || qup->qup_err) { 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)) { if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
dev_err(qup->dev, "change to run state timed out"); dev_err(qup->dev, "change to run state timed out");
return ret; goto desc_err;
} }
if (rx_nents) if (rx_nents)
writel(QUP_BAM_INPUT_EOT, writel(QUP_BAM_INPUT_EOT,
qup->base + QUP_OUT_FIFO_BASE); qup->base + QUP_OUT_FIFO_BASE);
writel(QUP_BAM_FLUSH_STOP, writel(QUP_BAM_FLUSH_STOP, qup->base + QUP_OUT_FIFO_BASE);
qup->base + QUP_OUT_FIFO_BASE);
qup_i2c_flush(qup); qup_i2c_flush(qup);
...@@ -825,15 +826,17 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, ...@@ -825,15 +826,17 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg,
dev_err(qup->dev, "flush timed out\n"); dev_err(qup->dev, "flush timed out\n");
qup_i2c_rel_dma(qup); 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); dma_unmap_sg(qup->dev, qup->btx.sg, tx_nents, DMA_TO_DEVICE);
if (rx_nents) if (rx_nents)
dma_unmap_sg(qup->dev, qup->brx.sg, rx_nents, dma_unmap_sg(qup->dev, qup->brx.sg, rx_nents,
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
desc_err:
return ret; return ret;
} }
...@@ -849,9 +852,6 @@ static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, ...@@ -849,9 +852,6 @@ static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
if (ret) if (ret)
goto out; goto out;
qup->bus_err = 0;
qup->qup_err = 0;
writel(0, qup->base + QUP_MX_INPUT_CNT); writel(0, qup->base + QUP_MX_INPUT_CNT);
writel(0, qup->base + QUP_MX_OUTPUT_CNT); writel(0, qup->base + QUP_MX_OUTPUT_CNT);
...@@ -889,12 +889,8 @@ static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup, ...@@ -889,12 +889,8 @@ static int qup_i2c_wait_for_complete(struct qup_i2c_dev *qup,
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
} }
if (qup->bus_err || qup->qup_err) { if (qup->bus_err || qup->qup_err)
if (qup->bus_err & QUP_I2C_NACK_FLAG) { ret = (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO;
dev_err(qup->dev, "NACK from %x\n", msg->addr);
ret = -EIO;
}
}
return ret; return ret;
} }
...@@ -1020,7 +1016,7 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg) ...@@ -1020,7 +1016,7 @@ static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
{ {
u32 addr, len, val; 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) */ /* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len; len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
...@@ -1186,6 +1182,9 @@ static int qup_i2c_xfer(struct i2c_adapter *adap, ...@@ -1186,6 +1182,9 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
if (ret < 0) if (ret < 0)
goto out; goto out;
qup->bus_err = 0;
qup->qup_err = 0;
writel(1, qup->base + QUP_SW_RESET); writel(1, qup->base + QUP_SW_RESET);
ret = qup_i2c_poll_state(qup, QUP_RESET_STATE); ret = qup_i2c_poll_state(qup, QUP_RESET_STATE);
if (ret) if (ret)
...@@ -1235,6 +1234,9 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap, ...@@ -1235,6 +1234,9 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap,
struct qup_i2c_dev *qup = i2c_get_adapdata(adap); struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
int ret, len, idx = 0, use_dma = 0; int ret, len, idx = 0, use_dma = 0;
qup->bus_err = 0;
qup->qup_err = 0;
ret = pm_runtime_get_sync(qup->dev); ret = pm_runtime_get_sync(qup->dev);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -1409,27 +1411,21 @@ static int qup_i2c_probe(struct platform_device *pdev) ...@@ -1409,27 +1411,21 @@ static int qup_i2c_probe(struct platform_device *pdev)
/* 2 tag bytes for each block + 5 for start, stop tags */ /* 2 tag bytes for each block + 5 for start, stop tags */
size = blocks * 2 + 5; 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.start = devm_kzalloc(&pdev->dev,
&qup->start_tag.addr); size, GFP_KERNEL);
if (!qup->start_tag.start) { if (!qup->start_tag.start) {
ret = -ENOMEM; ret = -ENOMEM;
goto fail_dma; goto fail_dma;
} }
qup->brx.tag.start = dma_pool_alloc(qup->dpool, qup->brx.tag.start = devm_kzalloc(&pdev->dev, 2, GFP_KERNEL);
GFP_KERNEL,
&qup->brx.tag.addr);
if (!qup->brx.tag.start) { if (!qup->brx.tag.start) {
ret = -ENOMEM; ret = -ENOMEM;
goto fail_dma; goto fail_dma;
} }
qup->btx.tag.start = dma_pool_alloc(qup->dpool, qup->btx.tag.start = devm_kzalloc(&pdev->dev, 2, GFP_KERNEL);
GFP_KERNEL,
&qup->btx.tag.addr);
if (!qup->btx.tag.start) { if (!qup->btx.tag.start) {
ret = -ENOMEM; ret = -ENOMEM;
goto fail_dma; goto fail_dma;
...@@ -1568,13 +1564,6 @@ static int qup_i2c_remove(struct platform_device *pdev) ...@@ -1568,13 +1564,6 @@ static int qup_i2c_remove(struct platform_device *pdev)
struct qup_i2c_dev *qup = platform_get_drvdata(pdev); struct qup_i2c_dev *qup = platform_get_drvdata(pdev);
if (qup->is_dma) { 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->btx.dma);
dma_release_channel(qup->brx.dma); dma_release_channel(qup->brx.dma);
} }
......
...@@ -58,6 +58,12 @@ enum { ...@@ -58,6 +58,12 @@ enum {
#define REG_CON_LASTACK BIT(5) /* 1: send NACK after last received byte */ #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_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 */ /* REG_MRXADDR bits */
#define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */ #define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */
...@@ -75,6 +81,77 @@ enum { ...@@ -75,6 +81,77 @@ enum {
#define WAIT_TIMEOUT 1000 /* ms */ #define WAIT_TIMEOUT 1000 /* ms */
#define DEFAULT_SCL_RATE (100 * 1000) /* Hz */ #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 { enum rk3x_i2c_state {
STATE_IDLE, STATE_IDLE,
STATE_START, STATE_START,
...@@ -85,11 +162,35 @@ enum rk3x_i2c_state { ...@@ -85,11 +162,35 @@ enum rk3x_i2c_state {
/** /**
* @grf_offset: offset inside the grf regmap for setting the i2c type * @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 { struct rk3x_i2c_soc_data {
int grf_offset; 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 rk3x_i2c {
struct i2c_adapter adap; struct i2c_adapter adap;
struct device *dev; struct device *dev;
...@@ -98,6 +199,7 @@ struct rk3x_i2c { ...@@ -98,6 +199,7 @@ struct rk3x_i2c {
/* Hardware resources */ /* Hardware resources */
void __iomem *regs; void __iomem *regs;
struct clk *clk; struct clk *clk;
struct clk *pclk;
struct notifier_block clk_rate_nb; struct notifier_block clk_rate_nb;
/* Settings */ /* Settings */
...@@ -116,7 +218,7 @@ struct rk3x_i2c { ...@@ -116,7 +218,7 @@ struct rk3x_i2c {
/* I2C state machine */ /* I2C state machine */
enum rk3x_i2c_state state; enum rk3x_i2c_state state;
unsigned int processed; /* sent/received bytes */ unsigned int processed;
int error; int error;
}; };
...@@ -142,13 +244,12 @@ static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c) ...@@ -142,13 +244,12 @@ static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c)
*/ */
static void rk3x_i2c_start(struct rk3x_i2c *i2c) 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); i2c_writel(i2c, REG_INT_START, REG_IEN);
/* enable adapter with correct mode, send START condition */ /* 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 we want to react to NACK, set ACTACK bit */
if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
...@@ -189,7 +290,8 @@ static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error) ...@@ -189,7 +290,8 @@ static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error)
* get the intended effect by resetting its internal state * get the intended effect by resetting its internal state
* and issuing an ordinary START. * 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 */ /* signal that we are finished with the current msg */
wake_up(&i2c->wait); wake_up(&i2c->wait);
...@@ -430,27 +532,38 @@ static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id) ...@@ -430,27 +532,38 @@ static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
/**
* 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 * Calculate divider values for desired SCL frequency
* *
* @clk_rate: I2C input clock rate * @clk_rate: I2C input clock rate
* @t: Known I2C timing information. * @t: Known I2C timing information
* @div_low: Divider output for low * @t_calc: Caculated rk3x private timings that would be written into regs
* @div_high: Divider output for high
* *
* Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case * 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 * a best-effort divider value is returned in divs. If the target rate is
* too high, we silently use the highest possible rate. * too high, we silently use the highest possible rate.
*/ */
static int rk3x_i2c_calc_divs(unsigned long clk_rate, static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate,
struct i2c_timings *t, struct i2c_timings *t,
unsigned long *div_low, struct rk3x_i2c_calced_timings *t_calc)
unsigned long *div_high)
{ {
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 min_low_ns, min_high_ns;
unsigned long max_low_ns, min_total_ns; unsigned long max_low_ns, min_total_ns;
...@@ -462,6 +575,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, ...@@ -462,6 +575,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
unsigned long min_div_for_hold, min_total_div; unsigned long min_div_for_hold, min_total_div;
unsigned long extra_div, extra_low_div, ideal_low_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; int ret = 0;
/* Only support standard-mode and fast-mode */ /* Only support standard-mode and fast-mode */
...@@ -484,22 +599,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, ...@@ -484,22 +599,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
* This is because the i2c host on Rockchip holds the data line * This is because the i2c host on Rockchip holds the data line
* for half the low time. * for half the low time.
*/ */
if (t->bus_freq_hz <= 100000) { spec = rk3x_i2c_get_spec(t->bus_freq_hz);
/* Standard-mode */ min_high_ns = t->scl_rise_ns + spec->min_high_ns;
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;
/* /*
* Timings for repeated start: * Timings for repeated start:
...@@ -509,14 +610,14 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, ...@@ -509,14 +610,14 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
* We need to account for those rules in picking our "high" time so * We need to account for those rules in picking our "high" time so
* we meet tSU;STA and tHD;STA times. * we meet tSU;STA and tHD;STA times.
*/ */
min_high_ns = max(min_high_ns, min_high_ns = max(min_high_ns, DIV_ROUND_UP(
DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start) * 1000, 875)); (t->scl_rise_ns + spec->min_setup_start_ns) * 1000, 875));
min_high_ns = max(min_high_ns, min_high_ns = max(min_high_ns, DIV_ROUND_UP(
DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start + (t->scl_rise_ns + spec->min_setup_start_ns + t->sda_fall_ns +
t->sda_fall_ns + spec_min_high_ns), 2)); spec->min_high_ns), 2));
min_low_ns = t->scl_fall_ns + spec_min_low_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; max_low_ns = spec->max_data_hold_ns * 2 - data_hold_buffer_ns;
min_total_ns = min_low_ns + min_high_ns; min_total_ns = min_low_ns + min_high_ns;
/* Adjust to avoid overflow */ /* Adjust to avoid overflow */
...@@ -552,8 +653,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, ...@@ -552,8 +653,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
* Time needed to meet hold requirements is important. * Time needed to meet hold requirements is important.
* Just use that. * Just use that.
*/ */
*div_low = min_low_div; t_calc->div_low = min_low_div;
*div_high = min_high_div; t_calc->div_high = min_high_div;
} else { } else {
/* /*
* We've got to distribute some time among the low and high * We've got to distribute some time among the low and high
...@@ -582,25 +683,186 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, ...@@ -582,25 +683,186 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
/* Give low the "ideal" and give high whatever extra is left */ /* Give low the "ideal" and give high whatever extra is left */
extra_low_div = ideal_low_div - min_low_div; extra_low_div = ideal_low_div - min_low_div;
*div_low = ideal_low_div; t_calc->div_low = ideal_low_div;
*div_high = min_high_div + (extra_div - extra_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". * Adjust to the fact that the hardware has an implicit "+1".
* NOTE: Above calculations always produce div_low > 0 and div_high > 0. * NOTE: Above calculations always produce div_low > 0 and div_high > 0.
*/ */
*div_low = *div_low - 1; t_calc->div_low--;
*div_high = *div_high - 1; 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;
}
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 */ /* Maximum divider supported by hw is 0xffff */
if (*div_low > 0xffff) { if (t_calc->div_low > 0xffff) {
*div_low = 0xffff; t_calc->div_low = 0xffff;
ret = -EINVAL; ret = -EINVAL;
} }
if (*div_high > 0xffff) { if (t_calc->div_high > 0xffff) {
*div_high = 0xffff; t_calc->div_high = 0xffff;
ret = -EINVAL; ret = -EINVAL;
} }
...@@ -610,19 +872,31 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, ...@@ -610,19 +872,31 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate) static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
{ {
struct i2c_timings *t = &i2c->t; 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; u64 t_low_ns, t_high_ns;
unsigned long flags;
u32 val;
int ret; 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); WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
clk_enable(i2c->clk); clk_enable(i2c->pclk);
i2c_writel(i2c, (div_high << 16) | (div_low & 0xffff), REG_CLKDIV);
clk_disable(i2c->clk); 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)div_low + 1) * 8 * 1000000000, clk_rate); t_low_ns = div_u64(((u64)calc.div_low + 1) * 8 * 1000000000, clk_rate);
t_high_ns = div_u64(((u64)div_high + 1) * 8 * 1000000000, clk_rate); t_high_ns = div_u64(((u64)calc.div_high + 1) * 8 * 1000000000,
clk_rate);
dev_dbg(i2c->dev, dev_dbg(i2c->dev,
"CLK %lukhz, Req %uns, Act low %lluns high %lluns\n", "CLK %lukhz, Req %uns, Act low %lluns high %lluns\n",
clk_rate / 1000, clk_rate / 1000,
...@@ -652,12 +926,17 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long ...@@ -652,12 +926,17 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
{ {
struct clk_notifier_data *ndata = data; struct clk_notifier_data *ndata = data;
struct rk3x_i2c *i2c = container_of(nb, struct rk3x_i2c, clk_rate_nb); 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) { switch (event) {
case PRE_RATE_CHANGE: 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; return NOTIFY_STOP;
/* scale up */ /* scale up */
...@@ -767,12 +1046,14 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap, ...@@ -767,12 +1046,14 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
{ {
struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data; struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data;
unsigned long timeout, flags; unsigned long timeout, flags;
u32 val;
int ret = 0; int ret = 0;
int i; int i;
spin_lock_irqsave(&i2c->lock, flags); spin_lock_irqsave(&i2c->lock, flags);
clk_enable(i2c->clk); clk_enable(i2c->clk);
clk_enable(i2c->pclk);
i2c->is_last_msg = false; i2c->is_last_msg = false;
...@@ -806,7 +1087,9 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap, ...@@ -806,7 +1087,9 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
/* Force a STOP condition without interrupt */ /* Force a STOP condition without interrupt */
i2c_writel(i2c, 0, REG_IEN); 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; i2c->state = STATE_IDLE;
...@@ -820,7 +1103,9 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap, ...@@ -820,7 +1103,9 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
} }
} }
clk_disable(i2c->pclk);
clk_disable(i2c->clk); clk_disable(i2c->clk);
spin_unlock_irqrestore(&i2c->lock, flags); spin_unlock_irqrestore(&i2c->lock, flags);
return ret < 0 ? ret : num; return ret < 0 ? ret : num;
...@@ -836,17 +1121,52 @@ static const struct i2c_algorithm rk3x_i2c_algorithm = { ...@@ -836,17 +1121,52 @@ static const struct i2c_algorithm rk3x_i2c_algorithm = {
.functionality = rk3x_i2c_func, .functionality = rk3x_i2c_func,
}; };
static struct rk3x_i2c_soc_data soc_data[3] = { static const struct rk3x_i2c_soc_data rk3066_soc_data = {
{ .grf_offset = 0x154 }, /* rk3066 */ .grf_offset = 0x154,
{ .grf_offset = 0x0a4 }, /* rk3188 */ .calc_timings = rk3x_i2c_v0_calc_timings,
{ .grf_offset = -1 }, /* no I2C switching needed */ };
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[] = { 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,rk3066-i2c",
{ .compatible = "rockchip,rk3228-i2c", .data = (void *)&soc_data[2] }, .data = (void *)&rk3066_soc_data
{ .compatible = "rockchip,rk3288-i2c", .data = (void *)&soc_data[2] }, },
{
.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); MODULE_DEVICE_TABLE(of, rk3x_i2c_match);
...@@ -886,12 +1206,6 @@ static int rk3x_i2c_probe(struct platform_device *pdev) ...@@ -886,12 +1206,6 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
spin_lock_init(&i2c->lock); spin_lock_init(&i2c->lock);
init_waitqueue_head(&i2c->wait); 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); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i2c->regs = devm_ioremap_resource(&pdev->dev, mem); i2c->regs = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(i2c->regs)) if (IS_ERR(i2c->regs))
...@@ -945,17 +1259,44 @@ static int rk3x_i2c_probe(struct platform_device *pdev) ...@@ -945,17 +1259,44 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, i2c); 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); ret = clk_prepare(i2c->clk);
if (ret < 0) { 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; 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; i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb;
ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb); ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb);
if (ret != 0) { if (ret != 0) {
dev_err(&pdev->dev, "Unable to register clock notifier\n"); dev_err(&pdev->dev, "Unable to register clock notifier\n");
goto err_clk; goto err_pclk;
} }
clk_rate = clk_get_rate(i2c->clk); clk_rate = clk_get_rate(i2c->clk);
...@@ -973,6 +1314,8 @@ static int rk3x_i2c_probe(struct platform_device *pdev) ...@@ -973,6 +1314,8 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
err_clk_notifier: err_clk_notifier:
clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb); clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
err_pclk:
clk_unprepare(i2c->pclk);
err_clk: err_clk:
clk_unprepare(i2c->clk); clk_unprepare(i2c->clk);
return ret; return ret;
...@@ -985,6 +1328,7 @@ static int rk3x_i2c_remove(struct platform_device *pdev) ...@@ -985,6 +1328,7 @@ static int rk3x_i2c_remove(struct platform_device *pdev)
i2c_del_adapter(&i2c->adap); i2c_del_adapter(&i2c->adap);
clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb); clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
clk_unprepare(i2c->pclk);
clk_unprepare(i2c->clk); clk_unprepare(i2c->clk);
return 0; return 0;
......
...@@ -125,7 +125,7 @@ static struct i2c_algorithm osif_algorithm = { ...@@ -125,7 +125,7 @@ static struct i2c_algorithm osif_algorithm = {
#define USB_OSIF_VENDOR_ID 0x1964 #define USB_OSIF_VENDOR_ID 0x1964
#define USB_OSIF_PRODUCT_ID 0x0001 #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) }, { USB_DEVICE(USB_OSIF_VENDOR_ID, USB_OSIF_PRODUCT_ID) },
{ } { }
}; };
......
...@@ -70,28 +70,14 @@ static int i2c_versatile_probe(struct platform_device *dev) ...@@ -70,28 +70,14 @@ static int i2c_versatile_probe(struct platform_device *dev)
struct resource *r; struct resource *r;
int ret; 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); r = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!r) { i2c->base = devm_ioremap_resource(&dev->dev, r);
ret = -EINVAL; if (IS_ERR(i2c->base))
goto err_out; return PTR_ERR(i2c->base);
}
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;
}
writel(SCL | SDA, i2c->base + I2C_CONTROLS); writel(SCL | SDA, i2c->base + I2C_CONTROLS);
...@@ -105,18 +91,12 @@ static int i2c_versatile_probe(struct platform_device *dev) ...@@ -105,18 +91,12 @@ static int i2c_versatile_probe(struct platform_device *dev)
i2c->adap.nr = dev->id; i2c->adap.nr = dev->id;
ret = i2c_bit_add_numbered_bus(&i2c->adap); ret = i2c_bit_add_numbered_bus(&i2c->adap);
if (ret >= 0) { if (ret < 0)
return ret;
platform_set_drvdata(dev, i2c); platform_set_drvdata(dev, i2c);
return 0; return 0;
}
iounmap(i2c->base);
err_free:
kfree(i2c);
err_release:
release_mem_region(r->start, resource_size(r));
err_out:
return ret;
} }
static int i2c_versatile_remove(struct platform_device *dev) static int i2c_versatile_remove(struct platform_device *dev)
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
* warranty of any kind, whether express or implied. * warranty of any kind, whether express or implied.
*/ */
#include <linux/acpi.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -341,11 +342,10 @@ static struct i2c_algorithm xlp9xx_i2c_algo = { ...@@ -341,11 +342,10 @@ static struct i2c_algorithm xlp9xx_i2c_algo = {
static int xlp9xx_i2c_get_frequency(struct platform_device *pdev, static int xlp9xx_i2c_get_frequency(struct platform_device *pdev,
struct xlp9xx_i2c_dev *priv) struct xlp9xx_i2c_dev *priv)
{ {
struct device_node *np = pdev->dev.of_node;
u32 freq; u32 freq;
int err; int err;
err = of_property_read_u32(np, "clock-frequency", &freq); err = device_property_read_u32(&pdev->dev, "clock-frequency", &freq);
if (err) { if (err) {
freq = XLP9XX_I2C_DEFAULT_FREQ; freq = XLP9XX_I2C_DEFAULT_FREQ;
dev_dbg(&pdev->dev, "using default frequency %u\n", freq); dev_dbg(&pdev->dev, "using default frequency %u\n", freq);
...@@ -429,12 +429,21 @@ static const struct of_device_id xlp9xx_i2c_of_match[] = { ...@@ -429,12 +429,21 @@ static const struct of_device_id xlp9xx_i2c_of_match[] = {
{ /* sentinel */ }, { /* 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 = { static struct platform_driver xlp9xx_i2c_driver = {
.probe = xlp9xx_i2c_probe, .probe = xlp9xx_i2c_probe,
.remove = xlp9xx_i2c_remove, .remove = xlp9xx_i2c_remove,
.driver = { .driver = {
.name = "xlp9xx-i2c", .name = "xlp9xx-i2c",
.of_match_table = xlp9xx_i2c_of_match, .of_match_table = xlp9xx_i2c_of_match,
.acpi_match_table = ACPI_PTR(xlp9xx_i2c_acpi_ids),
}, },
}; };
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
I2C slave support (c) 2014 by Wolfram Sang <wsa@sang-engineering.com> 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 <dt-bindings/i2c/i2c.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/acpi.h> #include <linux/acpi.h>
...@@ -493,7 +495,8 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command, ...@@ -493,7 +495,8 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command,
break; break;
default: 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; ret = AE_BAD_PARAMETER;
goto err; goto err;
} }
...@@ -759,6 +762,47 @@ int i2c_recover_bus(struct i2c_adapter *adap) ...@@ -759,6 +762,47 @@ int i2c_recover_bus(struct i2c_adapter *adap)
} }
EXPORT_SYMBOL_GPL(i2c_recover_bus); EXPORT_SYMBOL_GPL(i2c_recover_bus);
static void i2c_init_recovery(struct i2c_adapter *adap)
{
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) static int i2c_device_probe(struct device *dev)
{ {
struct i2c_client *client = i2c_verify_client(dev); struct i2c_client *client = i2c_verify_client(dev);
...@@ -1240,6 +1284,47 @@ struct i2c_client *i2c_new_dummy(struct i2c_adapter *adapter, u16 address) ...@@ -1240,6 +1284,47 @@ struct i2c_client *i2c_new_dummy(struct i2c_adapter *adapter, u16 address)
} }
EXPORT_SYMBOL_GPL(i2c_new_dummy); 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 */ /* I2C bus adapters -- one roots each I2C or SMBUS segment */
...@@ -1608,7 +1693,7 @@ static int __process_new_adapter(struct device_driver *d, void *data) ...@@ -1608,7 +1693,7 @@ static int __process_new_adapter(struct device_driver *d, void *data)
static int i2c_register_adapter(struct i2c_adapter *adap) static int i2c_register_adapter(struct i2c_adapter *adap)
{ {
int res = 0; int res = -EINVAL;
/* Can't register until after driver model init */ /* Can't register until after driver model init */
if (WARN_ON(!is_registered)) { if (WARN_ON(!is_registered)) {
...@@ -1617,15 +1702,12 @@ static int i2c_register_adapter(struct i2c_adapter *adap) ...@@ -1617,15 +1702,12 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
} }
/* Sanity checks */ /* Sanity checks */
if (unlikely(adap->name[0] == '\0')) { if (WARN(!adap->name[0], "i2c adapter has no name"))
pr_err("i2c-core: Attempt to register an adapter with " goto out_list;
"no name!\n");
return -EINVAL; if (!adap->algo) {
} pr_err("adapter '%s': no algo supplied!\n", adap->name);
if (unlikely(!adap->algo)) { goto out_list;
pr_err("i2c-core: Attempt to register adapter '%s' with "
"no algo!\n", adap->name);
return -EINVAL;
} }
if (!adap->lock_bus) { if (!adap->lock_bus) {
...@@ -1647,8 +1729,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap) ...@@ -1647,8 +1729,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
adap->dev.bus = &i2c_bus_type; adap->dev.bus = &i2c_bus_type;
adap->dev.type = &i2c_adapter_type; adap->dev.type = &i2c_adapter_type;
res = device_register(&adap->dev); 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; goto out_list;
}
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
...@@ -1664,41 +1748,8 @@ static int i2c_register_adapter(struct i2c_adapter *adap) ...@@ -1664,41 +1748,8 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
"Failed to create compatibility class link\n"); "Failed to create compatibility class link\n");
#endif #endif
/* bus recovery specific initialization */ i2c_init_recovery(adap);
if (adap->bus_recovery_info) {
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
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 */ /* create pre-declared device nodes */
of_i2c_register_devices(adap); of_i2c_register_devices(adap);
acpi_i2c_register_devices(adap); acpi_i2c_register_devices(adap);
...@@ -1733,10 +1784,9 @@ static int __i2c_add_numbered_adapter(struct i2c_adapter *adap) ...@@ -1733,10 +1784,9 @@ static int __i2c_add_numbered_adapter(struct i2c_adapter *adap)
int id; int id;
mutex_lock(&core_lock); mutex_lock(&core_lock);
id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1, id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1, GFP_KERNEL);
GFP_KERNEL);
mutex_unlock(&core_lock); mutex_unlock(&core_lock);
if (id < 0) if (WARN(id < 0, "couldn't get idr"))
return id == -ENOSPC ? -EBUSY : id; return id == -ENOSPC ? -EBUSY : id;
return i2c_register_adapter(adap); return i2c_register_adapter(adap);
...@@ -1773,7 +1823,7 @@ int i2c_add_adapter(struct i2c_adapter *adapter) ...@@ -1773,7 +1823,7 @@ int i2c_add_adapter(struct i2c_adapter *adapter)
id = idr_alloc(&i2c_adapter_idr, adapter, id = idr_alloc(&i2c_adapter_idr, adapter,
__i2c_first_dynamic_bus_num, 0, GFP_KERNEL); __i2c_first_dynamic_bus_num, 0, GFP_KERNEL);
mutex_unlock(&core_lock); mutex_unlock(&core_lock);
if (id < 0) if (WARN(id < 0, "couldn't get idr"))
return id; return id;
adapter->nr = id; adapter->nr = id;
...@@ -1871,8 +1921,7 @@ void i2c_del_adapter(struct i2c_adapter *adap) ...@@ -1871,8 +1921,7 @@ void i2c_del_adapter(struct i2c_adapter *adap)
found = idr_find(&i2c_adapter_idr, adap->nr); found = idr_find(&i2c_adapter_idr, adap->nr);
mutex_unlock(&core_lock); mutex_unlock(&core_lock);
if (found != adap) { if (found != adap) {
pr_debug("i2c-core: attempting to delete unregistered " pr_debug("attempting to delete unregistered adapter [%s]\n", adap->name);
"adapter [%s]\n", adap->name);
return; return;
} }
...@@ -2032,7 +2081,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) ...@@ -2032,7 +2081,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
if (res) if (res)
return 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); INIT_LIST_HEAD(&driver->clients);
/* Walk the adapters that are already present */ /* Walk the adapters that are already present */
...@@ -2059,7 +2108,7 @@ void i2c_del_driver(struct i2c_driver *driver) ...@@ -2059,7 +2108,7 @@ void i2c_del_driver(struct i2c_driver *driver)
i2c_for_each_dev(driver, __process_removed_driver); i2c_for_each_dev(driver, __process_removed_driver);
driver_unregister(&driver->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); EXPORT_SYMBOL(i2c_del_driver);
...@@ -2150,8 +2199,8 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action, ...@@ -2150,8 +2199,8 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action,
put_device(&adap->dev); put_device(&adap->dev);
if (IS_ERR(client)) { if (IS_ERR(client)) {
pr_err("%s: failed to create for '%s'\n", dev_err(&adap->dev, "failed to create client for '%s'\n",
__func__, rd->dn->full_name); rd->dn->full_name);
return notifier_from_errno(PTR_ERR(client)); return notifier_from_errno(PTR_ERR(client));
} }
break; break;
...@@ -2772,7 +2821,7 @@ static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg) ...@@ -2772,7 +2821,7 @@ static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg)
cpec = i2c_smbus_msg_pec(cpec, msg); cpec = i2c_smbus_msg_pec(cpec, msg);
if (rpec != cpec) { 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); rpec, cpec);
return -EBADMSG; return -EBADMSG;
} }
......
...@@ -485,13 +485,8 @@ static int i2cdev_open(struct inode *inode, struct file *file) ...@@ -485,13 +485,8 @@ static int i2cdev_open(struct inode *inode, struct file *file)
unsigned int minor = iminor(inode); unsigned int minor = iminor(inode);
struct i2c_client *client; struct i2c_client *client;
struct i2c_adapter *adap; 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) if (!adap)
return -ENODEV; return -ENODEV;
......
...@@ -33,7 +33,8 @@ struct i2c_smbus_alert { ...@@ -33,7 +33,8 @@ struct i2c_smbus_alert {
struct alert_data { struct alert_data {
unsigned short addr; unsigned short addr;
u8 flag:1; enum i2c_alert_protocol type;
unsigned int data;
}; };
/* If this is the alerting device, notify its driver */ /* If this is the alerting device, notify its driver */
...@@ -56,7 +57,7 @@ static int smbus_do_alert(struct device *dev, void *addrp) ...@@ -56,7 +57,7 @@ static int smbus_do_alert(struct device *dev, void *addrp)
if (client->dev.driver) { if (client->dev.driver) {
driver = to_i2c_driver(client->dev.driver); driver = to_i2c_driver(client->dev.driver);
if (driver->alert) if (driver->alert)
driver->alert(client, data->flag); driver->alert(client, data->type, data->data);
else else
dev_warn(&client->dev, "no driver alert()!\n"); dev_warn(&client->dev, "no driver alert()!\n");
} else } else
...@@ -96,8 +97,9 @@ static void smbus_alert(struct work_struct *work) ...@@ -96,8 +97,9 @@ static void smbus_alert(struct work_struct *work)
if (status < 0) if (status < 0)
break; break;
data.flag = status & 1; data.data = status & 1;
data.addr = status >> 1; data.addr = status >> 1;
data.type = I2C_PROTOCOL_SMBUS_ALERT;
if (data.addr == prev_addr) { if (data.addr == prev_addr) {
dev_warn(&ara->dev, "Duplicate SMBALERT# from dev " dev_warn(&ara->dev, "Duplicate SMBALERT# from dev "
...@@ -105,7 +107,7 @@ static void smbus_alert(struct work_struct *work) ...@@ -105,7 +107,7 @@ static void smbus_alert(struct work_struct *work)
break; break;
} }
dev_dbg(&ara->dev, "SMBALERT# from dev 0x%02x, flag %d\n", 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 */ /* Notify driver for the device which issued the alert */
device_for_each_child(&ara->adapter->dev, &data, device_for_each_child(&ara->adapter->dev, &data,
...@@ -239,6 +241,108 @@ int i2c_handle_smbus_alert(struct i2c_client *ara) ...@@ -239,6 +241,108 @@ int i2c_handle_smbus_alert(struct i2c_client *ara)
} }
EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert); 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_i2c_driver(smbalert_driver);
MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>"); MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
......
...@@ -58,6 +58,10 @@ struct at24_data { ...@@ -58,6 +58,10 @@ struct at24_data {
int use_smbus; int use_smbus;
int use_smbus_write; 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, * Lock protects against activities from other Linux tasks,
* but not from changes by other I2C masters. * but not from changes by other I2C masters.
...@@ -109,21 +113,59 @@ MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)"); ...@@ -109,21 +113,59 @@ MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)");
((1 << AT24_SIZE_FLAGS | (_flags)) \ ((1 << AT24_SIZE_FLAGS | (_flags)) \
<< AT24_SIZE_BYTELEN | ilog2(_len)) << 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[] = { static const struct i2c_device_id at24_ids[] = {
/* needs 8 addresses as A0-A2 are ignored */ /* 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! */ /* old variants can't be handled with this generic entry! */
{ "24c01", AT24_DEVICE_MAGIC(1024 / 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) }, { "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 is a 24c02 in memory DIMMs */
{ "spd", AT24_DEVICE_MAGIC(2048 / 8, { "spd", AT24_DEVICE_MAGIC(2048 / 8,
AT24_FLAG_READONLY | AT24_FLAG_IRUGO) }, AT24_FLAG_READONLY | AT24_FLAG_IRUGO) },
{ "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) }, { "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 */ /* 24rf08 quirk is handled at i2c-core */
{ "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) }, { "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) }, { "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) }, { "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) }, { "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) }, { "24c128", AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) },
{ "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) }, { "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) },
{ "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) }, { "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) },
...@@ -145,9 +187,22 @@ MODULE_DEVICE_TABLE(acpi, at24_acpi_ids); ...@@ -145,9 +187,22 @@ MODULE_DEVICE_TABLE(acpi, at24_acpi_ids);
* This routine supports chips which consume multiple I2C addresses. It * This routine supports chips which consume multiple I2C addresses. It
* computes the addressing information to be used for a given r/w request. * computes the addressing information to be used for a given r/w request.
* Assumes that sanity checks for offset happened at sysfs-layer. * 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, static struct i2c_client *at24_translate_offset(struct at24_data *at24,
unsigned *offset) unsigned int *offset)
{ {
unsigned i; unsigned i;
...@@ -162,49 +217,57 @@ static struct i2c_client *at24_translate_offset(struct at24_data *at24, ...@@ -162,49 +217,57 @@ static struct i2c_client *at24_translate_offset(struct at24_data *at24,
return at24->client[i]; return at24->client[i];
} }
static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, static ssize_t at24_eeprom_read_smbus(struct at24_data *at24, char *buf,
unsigned offset, size_t count) unsigned int offset, size_t count)
{ {
struct i2c_msg msg[2];
u8 msgbuf[2];
struct i2c_client *client;
unsigned long timeout, read_time; 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); client = at24_translate_offset(at24, &offset);
if (count > io_limit) if (count > io_limit)
count = io_limit; count = io_limit;
if (at24->use_smbus) {
/* Smaller eeproms can work given some SMBus extension calls */ /* Smaller eeproms can work given some SMBus extension calls */
if (count > I2C_SMBUS_BLOCK_MAX) if (count > I2C_SMBUS_BLOCK_MAX)
count = I2C_SMBUS_BLOCK_MAX; count = I2C_SMBUS_BLOCK_MAX;
} else {
loop_until_timeout(timeout, read_time) {
status = i2c_smbus_read_i2c_block_data_or_emulated(client,
offset,
count, buf);
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_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 * When we have a better choice than SMBus calls, use a combined I2C
* combined I2C message. Write address; then read up to * message. Write address; then read up to io_limit data bytes. Note
* io_limit data bytes. Note that read page rollover helps us * that read page rollover helps us here (unlike writes). msgbuf is
* here (unlike writes). msgbuf is u8 and will cast to our * u8 and will cast to our needs.
* needs.
*/ */
i = 0; i = 0;
if (at24->chip.flags & AT24_FLAG_ADDR16) if (at24->chip.flags & AT24_FLAG_ADDR16)
...@@ -219,66 +282,103 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, ...@@ -219,66 +282,103 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
msg[1].flags = I2C_M_RD; msg[1].flags = I2C_M_RD;
msg[1].buf = buf; msg[1].buf = buf;
msg[1].len = count; msg[1].len = count;
}
/* loop_until_timeout(timeout, read_time) {
* 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); status = i2c_transfer(client->adapter, msg, 2);
if (status == 2) if (status == 2)
status = count; status = count;
}
dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n", dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n",
count, offset, status, jiffies); count, offset, status, jiffies);
if (status == count) if (status == count)
return count; return count;
}
usleep_range(1000, 1500);
} while (time_before(read_time, timeout));
return -ETIMEDOUT; return -ETIMEDOUT;
} }
static int at24_read(void *priv, unsigned int off, void *val, size_t count) static ssize_t at24_eeprom_read_serial(struct at24_data *at24, char *buf,
unsigned int offset, size_t count)
{ {
struct at24_data *at24 = priv; unsigned long timeout, read_time;
char *buf = val; struct i2c_client *client;
struct i2c_msg msg[2];
u8 addrbuf[2];
int status;
if (unlikely(!count)) client = at24_translate_offset(at24, &offset);
return count;
memset(msg, 0, sizeof(msg));
msg[0].addr = client->addr;
msg[0].buf = addrbuf;
/* /*
* Read data from chip, protecting against concurrent updates * The address pointer of the device is shared between the regular
* from this host, but not from other I2C masters. * 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.
*/ */
mutex_lock(&at24->lock); 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;
}
while (count) { msg[1].addr = client->addr;
int status; msg[1].flags = I2C_M_RD;
msg[1].buf = buf;
msg[1].len = count;
status = at24_eeprom_read(at24, buf, off, count); loop_until_timeout(timeout, read_time) {
if (status < 0) { status = i2c_transfer(client->adapter, msg, 2);
mutex_unlock(&at24->lock); if (status == 2)
return status; return count;
}
buf += status;
off += status;
count -= status;
} }
mutex_unlock(&at24->lock); return -ETIMEDOUT;
}
return 0; 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;
} }
/* /*
...@@ -286,21 +386,15 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count) ...@@ -286,21 +386,15 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count)
* chip is normally write protected. But there are plenty of product * chip is normally write protected. But there are plenty of product
* variants here, including OTP fuses and partial chip protect. * variants here, including OTP fuses and partial chip protect.
* *
* We only use page mode writes; the alternative is sloooow. This routine * We only use page mode writes; the alternative is sloooow. These routines
* writes at most one page. * write at most one page.
*/ */
static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
unsigned offset, size_t count) static size_t at24_adjust_write_count(struct at24_data *at24,
unsigned int offset, size_t count)
{ {
struct i2c_client *client;
struct i2c_msg msg;
ssize_t status = 0;
unsigned long timeout, write_time;
unsigned next_page; unsigned next_page;
/* Get corresponding I2C address and adjust offset */
client = at24_translate_offset(at24, &offset);
/* write_max is at most a page */ /* write_max is at most a page */
if (count > at24->write_max) if (count > at24->write_max)
count = at24->write_max; count = at24->write_max;
...@@ -310,10 +404,73 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf, ...@@ -310,10 +404,73 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
if (offset + count > next_page) if (offset + count > next_page)
count = next_page - offset; count = next_page - offset;
/* If we'll use I2C calls for I/O, set up the message */ return count;
if (!at24->use_smbus) { }
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; int i = 0;
client = at24_translate_offset(at24, &offset);
count = at24_adjust_write_count(at24, offset, count);
msg.addr = client->addr; msg.addr = client->addr;
msg.flags = 0; msg.flags = 0;
...@@ -325,47 +482,54 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf, ...@@ -325,47 +482,54 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
msg.buf[i++] = offset; msg.buf[i++] = offset;
memcpy(&msg.buf[i], buf, count); memcpy(&msg.buf[i], buf, count);
msg.len = i + 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) loop_until_timeout(timeout, write_time) {
status = count;
} else {
status = i2c_transfer(client->adapter, &msg, 1); status = i2c_transfer(client->adapter, &msg, 1);
if (status == 1) if (status == 1)
status = count; status = count;
}
dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n", dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",
count, offset, status, jiffies); count, offset, status, jiffies);
if (status == count) if (status == count)
return count; return count;
}
usleep_range(1000, 1500);
} while (time_before(write_time, timeout));
return -ETIMEDOUT; return -ETIMEDOUT;
} }
static int at24_read(void *priv, unsigned int off, void *val, size_t count)
{
struct at24_data *at24 = priv;
char *buf = val;
if (unlikely(!count))
return count;
/*
* Read data from chip, protecting against concurrent updates
* from this host, but not from other I2C masters.
*/
mutex_lock(&at24->lock);
while (count) {
int status;
status = at24->read_func(at24, buf, off, count);
if (status < 0) {
mutex_unlock(&at24->lock);
return status;
}
buf += status;
off += status;
count -= status;
}
mutex_unlock(&at24->lock);
return 0;
}
static int at24_write(void *priv, unsigned int off, void *val, size_t count) static int at24_write(void *priv, unsigned int off, void *val, size_t count)
{ {
struct at24_data *at24 = priv; struct at24_data *at24 = priv;
...@@ -383,7 +547,7 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count) ...@@ -383,7 +547,7 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
while (count) { while (count) {
int status; int status;
status = at24_eeprom_write(at24, buf, off, count); status = at24->write_func(at24, buf, off, count);
if (status < 0) { if (status < 0) {
mutex_unlock(&at24->lock); mutex_unlock(&at24->lock);
return status; return status;
...@@ -518,6 +682,30 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -518,6 +682,30 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
at24->chip = chip; at24->chip = chip;
at24->num_addresses = num_addresses; 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); writable = !(chip.flags & AT24_FLAG_READONLY);
if (writable) { if (writable) {
if (!use_smbus || use_smbus_write) { if (!use_smbus || use_smbus_write) {
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#define _LINUX_I2C_SMBUS_H #define _LINUX_I2C_SMBUS_H
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
/** /**
...@@ -48,4 +50,31 @@ struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter, ...@@ -48,4 +50,31 @@ struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter,
struct i2c_smbus_alert_setup *setup); struct i2c_smbus_alert_setup *setup);
int i2c_handle_smbus_alert(struct i2c_client *ara); 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 */ #endif /* _LINUX_I2C_SMBUS_H */
...@@ -126,6 +126,11 @@ i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client, ...@@ -126,6 +126,11 @@ i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client,
u8 command, u8 length, u8 *values); u8 command, u8 length, u8 *values);
#endif /* I2C */ #endif /* I2C */
enum i2c_alert_protocol {
I2C_PROTOCOL_SMBUS_ALERT,
I2C_PROTOCOL_SMBUS_HOST_NOTIFY,
};
/** /**
* struct i2c_driver - represent an I2C device driver * struct i2c_driver - represent an I2C device driver
* @class: What kind of i2c device we instantiate (for detect) * @class: What kind of i2c device we instantiate (for detect)
...@@ -180,8 +185,11 @@ struct i2c_driver { ...@@ -180,8 +185,11 @@ struct i2c_driver {
* The format and meaning of the data value depends on the protocol. * 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 * For the SMBus alert protocol, there is a single bit of data passed
* as the alert response's low bit ("event flag"). * 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 /* a ioctl like command that can be used to perform specific functions
* with the device. * with the device.
...@@ -349,6 +357,11 @@ extern int i2c_probe_func_quick_read(struct i2c_adapter *, unsigned short addr); ...@@ -349,6 +357,11 @@ extern int i2c_probe_func_quick_read(struct i2c_adapter *, unsigned short addr);
extern struct i2c_client * extern struct i2c_client *
i2c_new_dummy(struct i2c_adapter *adap, u16 address); 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 *); extern void i2c_unregister_device(struct i2c_client *);
#endif /* I2C */ #endif /* I2C */
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/nvmem-consumer.h> #include <linux/nvmem-consumer.h>
#include <linux/bitops.h>
/** /**
* struct at24_platform_data - data to set up at24 (generic eeprom) driver * struct at24_platform_data - data to set up at24 (generic eeprom) driver
...@@ -43,10 +44,12 @@ struct at24_platform_data { ...@@ -43,10 +44,12 @@ struct at24_platform_data {
u32 byte_len; /* size (sum of all addr) */ u32 byte_len; /* size (sum of all addr) */
u16 page_size; /* for writes */ u16 page_size; /* for writes */
u8 flags; u8 flags;
#define AT24_FLAG_ADDR16 0x80 /* address pointer is 16 bit */ #define AT24_FLAG_ADDR16 BIT(7) /* address pointer is 16 bit */
#define AT24_FLAG_READONLY 0x40 /* sysfs-entry will be read-only */ #define AT24_FLAG_READONLY BIT(6) /* sysfs-entry will be read-only */
#define AT24_FLAG_IRUGO 0x20 /* sysfs-entry will be world-readable */ #define AT24_FLAG_IRUGO BIT(5) /* sysfs-entry will be world-readable */
#define AT24_FLAG_TAKE8ADDR 0x10 /* take always 8 addresses (24c00) */ #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 (*setup)(struct nvmem_device *nvmem, void *context);
void *context; void *context;
......
...@@ -102,6 +102,7 @@ struct i2c_msg { ...@@ -102,6 +102,7 @@ struct i2c_msg {
#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 #define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */ #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_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 | \ #define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \
I2C_FUNC_SMBUS_WRITE_BYTE) I2C_FUNC_SMBUS_WRITE_BYTE)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment