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,7 +253,8 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) ...@@ -253,7 +253,8 @@ 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)) {
dev_err(&pdev->dev, "Could not get clock\n"); if (PTR_ERR(i2c_dev->clk) != -EPROBE_DEFER)
dev_err(&pdev->dev, "Could not get clock\n");
return PTR_ERR(i2c_dev->clk); 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,
...@@ -190,7 +207,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, ...@@ -190,7 +207,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
struct dw_i2c_dev *dev; struct dw_i2c_dev *dev;
struct i2c_adapter *adap; struct i2c_adapter *adap;
int r; int r;
struct dw_pci_controller *controller; struct dw_pci_controller *controller;
struct dw_scl_sda_cfg *cfg; struct dw_scl_sda_cfg *cfg;
if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) { if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) {
...@@ -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,8 +391,30 @@ static int i801_check_post(struct i801_priv *priv, int status) ...@@ -348,8 +391,30 @@ 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) {
result = -ENXIO; /*
dev_dbg(&priv->pci_dev->dev, "No response\n"); * This may be a PEC error, check and clear it.
*
* AUXSTS is handled differently from HSTSTS.
* For HSTSTS, i801_isr() or i801_wait_intr()
* has already cleared the error bits in hardware,
* and we are passed a copy of the original value
* in "status".
* For AUXSTS, the hardware register is left
* for us to handle here.
* This is asymmetric, slightly iffy, but safe,
* since all this code is serialized and the CRCE
* bit is harmless as long as it's cleared before
* the next operation.
*/
if ((priv->features & FEATURE_SMBUS_PEC) &&
(inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE)) {
outb_p(SMBAUXSTS_CRCE, SMBAUXSTS(priv));
result = -EBADMSG;
dev_dbg(&priv->pci_dev->dev, "PEC error\n");
} else {
result = -ENXIO;
dev_dbg(&priv->pci_dev->dev, "No response\n");
}
} }
if (status & SMBHSTSTS_BUS_ERR) { if (status & SMBHSTSTS_BUS_ERR) {
result = -EAGAIN; result = -EAGAIN;
...@@ -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,39 +808,35 @@ static int qup_i2c_bam_do_xfer(struct qup_i2c_dev *qup, struct i2c_msg *msg, ...@@ -801,39 +808,35 @@ 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) { if (qup_i2c_change_state(qup, QUP_RUN_STATE)) {
msg--; dev_err(qup->dev, "change to run state timed out");
dev_err(qup->dev, "NACK from %x\n", msg->addr); goto desc_err;
ret = -EIO; }
if (qup_i2c_change_state(qup, QUP_RUN_STATE)) { if (rx_nents)
dev_err(qup->dev, "change to run state timed out"); writel(QUP_BAM_INPUT_EOT,
return ret; qup->base + QUP_OUT_FIFO_BASE);
}
if (rx_nents) writel(QUP_BAM_FLUSH_STOP, qup->base + QUP_OUT_FIFO_BASE);
writel(QUP_BAM_INPUT_EOT,
qup->base + QUP_OUT_FIFO_BASE);
writel(QUP_BAM_FLUSH_STOP, qup_i2c_flush(qup);
qup->base + QUP_OUT_FIFO_BASE);
qup_i2c_flush(qup); /* wait for remaining interrupts to occur */
if (!wait_for_completion_timeout(&qup->xfer, HZ))
dev_err(qup->dev, "flush timed out\n");
/* wait for remaining interrupts to occur */ qup_i2c_rel_dma(qup);
if (!wait_for_completion_timeout(&qup->xfer, HZ))
dev_err(qup->dev, "flush timed out\n");
qup_i2c_rel_dma(qup); ret = (qup->bus_err & QUP_I2C_NACK_FLAG) ? -ENXIO : -EIO;
}
} }
desc_err:
dma_unmap_sg(qup->dev, qup->btx.sg, tx_nents, DMA_TO_DEVICE); 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);
} }
......
This diff is collapsed.
...@@ -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)
platform_set_drvdata(dev, i2c); return ret;
return 0;
} platform_set_drvdata(dev, i2c);
iounmap(i2c->base); return 0;
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);
...@@ -1730,13 +1781,12 @@ static int i2c_register_adapter(struct i2c_adapter *adap) ...@@ -1730,13 +1781,12 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
*/ */
static int __i2c_add_numbered_adapter(struct i2c_adapter *adap) 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>");
......
This diff is collapsed.
...@@ -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