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