Merge branch 'i2c/for-mergewindow' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull i2c updates from Wolfram Sang:
 "I2C has a smaller pull reuest this time:

   - new driver for I2C virtio

   - removal of PMC SMP driver because platform is already gone

   - IRQ probing and DMAENGINE API cleanups

   - add SI metric prefix definitions to units.h

   - beginning of i801 refactorization

   - a few driver improvements"

* 'i2c/for-mergewindow' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (28 commits)
  i2c: cadence: Implement save restore
  i2c: xlp9xx: fix main IRQ check
  i2c: mt65xx: fix IRQ check
  i2c: virtio: add a virtio i2c frontend driver
  i2c: hix5hd2: fix IRQ check
  i2c: s3c2410: fix IRQ check
  i2c: iop3xx: fix deferred probing
  i2c: synquacer: fix deferred probing
  i2c: sun6i-pw2i: Prefer strscpy over strlcpy
  i2c: remove dead PMC MSP TWI/SMBus/I2C driver
  i2c: dev: Use sysfs_emit() in "show" functions
  i2c: dev: Define pr_fmt() and drop duplication substrings
  i2c: designware: Fix indentation in the header
  i2c: designware: Use DIV_ROUND_CLOSEST() macro
  units: Add SI metric prefix definitions
  i2c: at91: mark PM ops as __maybe unused
  i2c: sh_mobile: : use proper DMAENGINE API for termination
  i2c: qup: : use proper DMAENGINE API for termination
  i2c: mxs: : use proper DMAENGINE API for termination
  i2c: imx: : use proper DMAENGINE API for termination
  ...
This commit is contained in:
Linus Torvalds 2021-08-31 14:34:01 -07:00
commit 871dda463c
29 changed files with 467 additions and 730 deletions

View File

@ -19736,6 +19736,15 @@ S: Maintained
F: include/uapi/linux/virtio_snd.h
F: sound/virtio/*
VIRTIO I2C DRIVER
M: Jie Deng <jie.deng@intel.com>
M: Viresh Kumar <viresh.kumar@linaro.org>
L: linux-i2c@vger.kernel.org
L: virtualization@lists.linux-foundation.org
S: Maintained
F: drivers/i2c/busses/i2c-virtio.c
F: include/uapi/linux/virtio_i2c.h
VIRTUAL BOX GUEST DEVICE DRIVER
M: Hans de Goede <hdegoede@redhat.com>
M: Arnd Bergmann <arnd@arndb.de>

View File

@ -866,15 +866,6 @@ config I2C_PCA_PLATFORM
This driver can also be built as a module. If so, the module
will be called i2c-pca-platform.
config I2C_PMCMSP
tristate "PMC MSP I2C TWI Controller"
depends on PMC_MSP || COMPILE_TEST
help
This driver supports the PMC TWI controller on MSP devices.
This driver can also be built as module. If so, the module
will be called i2c-pmcmsp.
config I2C_PNX
tristate "I2C bus support for Philips PNX and NXP LPC targets"
depends on ARCH_LPC32XX || COMPILE_TEST
@ -1402,4 +1393,15 @@ config I2C_FSI
This driver can also be built as a module. If so, the module will be
called as i2c-fsi.
config I2C_VIRTIO
tristate "Virtio I2C Adapter"
select VIRTIO
help
If you say yes to this option, support will be included for the virtio
I2C adapter driver. The hardware can be emulated by any device model
software according to the virtio protocol.
This driver can also be built as a module. If so, the module
will be called i2c-virtio.
endmenu

View File

@ -86,7 +86,6 @@ obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
obj-$(CONFIG_I2C_OWL) += i2c-owl.o
obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o
obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o
obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o
obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o
@ -146,5 +145,6 @@ obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
obj-$(CONFIG_I2C_FSI) += i2c-fsi.o
obj-$(CONFIG_I2C_VIRTIO) += i2c-virtio.o
ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG

View File

@ -286,9 +286,7 @@ static int at91_twi_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static int at91_twi_runtime_suspend(struct device *dev)
static int __maybe_unused at91_twi_runtime_suspend(struct device *dev)
{
struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
@ -299,7 +297,7 @@ static int at91_twi_runtime_suspend(struct device *dev)
return 0;
}
static int at91_twi_runtime_resume(struct device *dev)
static int __maybe_unused at91_twi_runtime_resume(struct device *dev)
{
struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
@ -308,7 +306,7 @@ static int at91_twi_runtime_resume(struct device *dev)
return clk_prepare_enable(twi_dev->clk);
}
static int at91_twi_suspend_noirq(struct device *dev)
static int __maybe_unused at91_twi_suspend_noirq(struct device *dev)
{
if (!pm_runtime_status_suspended(dev))
at91_twi_runtime_suspend(dev);
@ -316,7 +314,7 @@ static int at91_twi_suspend_noirq(struct device *dev)
return 0;
}
static int at91_twi_resume_noirq(struct device *dev)
static int __maybe_unused at91_twi_resume_noirq(struct device *dev)
{
struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
int ret;
@ -335,18 +333,13 @@ static int at91_twi_resume_noirq(struct device *dev)
return 0;
}
static const struct dev_pm_ops at91_twi_pm = {
static const struct dev_pm_ops __maybe_unused at91_twi_pm = {
.suspend_noirq = at91_twi_suspend_noirq,
.resume_noirq = at91_twi_resume_noirq,
.runtime_suspend = at91_twi_runtime_suspend,
.runtime_resume = at91_twi_runtime_resume,
};
#define at91_twi_pm_ops (&at91_twi_pm)
#else
#define at91_twi_pm_ops NULL
#endif
static struct platform_driver at91_twi_driver = {
.probe = at91_twi_probe,
.remove = at91_twi_remove,
@ -354,7 +347,7 @@ static struct platform_driver at91_twi_driver = {
.driver = {
.name = "at91_i2c",
.of_match_table = of_match_ptr(atmel_twi_dt_ids),
.pm = at91_twi_pm_ops,
.pm = pm_ptr(&at91_twi_pm),
},
};

View File

@ -138,9 +138,9 @@ static void at91_twi_dma_cleanup(struct at91_twi_dev *dev)
if (dma->xfer_in_progress) {
if (dma->direction == DMA_FROM_DEVICE)
dmaengine_terminate_all(dma->chan_rx);
dmaengine_terminate_sync(dma->chan_rx);
else
dmaengine_terminate_all(dma->chan_tx);
dmaengine_terminate_sync(dma->chan_tx);
dma->xfer_in_progress = false;
}
if (dma->buf_mapped) {

View File

@ -178,6 +178,7 @@ enum cdns_i2c_slave_state {
* @clk: Pointer to struct clk
* @clk_rate_change_nb: Notifier block for clock rate changes
* @quirks: flag for broken hold bit usage in r1p10
* @ctrl_reg: Cached value of the control register.
* @ctrl_reg_diva_divb: value of fields DIV_A and DIV_B from CR register
* @slave: Registered slave instance.
* @dev_mode: I2C operating role(master/slave).
@ -202,6 +203,7 @@ struct cdns_i2c {
struct clk *clk;
struct notifier_block clk_rate_change_nb;
u32 quirks;
u32 ctrl_reg;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
u16 ctrl_reg_diva_divb;
struct i2c_client *slave;
@ -1071,10 +1073,11 @@ static int cdns_i2c_setclk(unsigned long clk_in, struct cdns_i2c *id)
if (ret)
return ret;
ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
ctrl_reg = id->ctrl_reg;
ctrl_reg &= ~(CDNS_I2C_CR_DIVA_MASK | CDNS_I2C_CR_DIVB_MASK);
ctrl_reg |= ((div_a << CDNS_I2C_CR_DIVA_SHIFT) |
(div_b << CDNS_I2C_CR_DIVB_SHIFT));
id->ctrl_reg = ctrl_reg;
cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
#if IS_ENABLED(CONFIG_I2C_SLAVE)
id->ctrl_reg_diva_divb = ctrl_reg & (CDNS_I2C_CR_DIVA_MASK |
@ -1162,6 +1165,26 @@ static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
return 0;
}
/**
* cdns_i2c_init - Controller initialisation
* @id: Device private data structure
*
* Initialise the i2c controller.
*
*/
static void cdns_i2c_init(struct cdns_i2c *id)
{
cdns_i2c_writereg(id->ctrl_reg, CDNS_I2C_CR_OFFSET);
/*
* Cadence I2C controller has a bug wherein it generates
* invalid read transaction after HW timeout in master receiver mode.
* HW timeout is not used by this driver and the interrupt is disabled.
* But the feature itself cannot be disabled. Hence maximum value
* is written to this register to reduce the chances of error.
*/
cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET);
}
/**
* cdns_i2c_runtime_resume - Runtime resume
* @dev: Address of the platform_device structure
@ -1180,6 +1203,7 @@ static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev)
dev_err(dev, "Cannot enable clock.\n");
return ret;
}
cdns_i2c_init(xi2c);
return 0;
}
@ -1279,7 +1303,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
id->dev_mode = CDNS_I2C_MODE_MASTER;
id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE;
#endif
cdns_i2c_writereg(CDNS_I2C_CR_MASTER_EN_MASK, CDNS_I2C_CR_OFFSET);
id->ctrl_reg = CDNS_I2C_CR_ACK_EN | CDNS_I2C_CR_NEA | CDNS_I2C_CR_MS;
ret = cdns_i2c_setclk(id->input_clk, id);
if (ret) {
@ -1294,15 +1318,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
goto err_clk_dis;
}
/*
* Cadence I2C controller has a bug wherein it generates
* invalid read transaction after HW timeout in master receiver mode.
* HW timeout is not used by this driver and the interrupt is disabled.
* But the feature itself cannot be disabled. Hence maximum value
* is written to this register to reduce the chances of error.
*/
cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET);
cdns_i2c_init(id);
ret = i2c_add_adapter(&id->adap);
if (ret < 0)

View File

@ -24,6 +24,7 @@
#include <linux/regmap.h>
#include <linux/swab.h>
#include <linux/types.h>
#include <linux/units.h>
#include "i2c-designware-core.h"
@ -350,7 +351,7 @@ u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
*
* If your hardware is free from tHD;STA issue, try this one.
*/
return (ic_clk * tSYMBOL + 500000) / 1000000 - 8 + offset;
return DIV_ROUND_CLOSEST(ic_clk * tSYMBOL, MICRO) - 8 + offset;
else
/*
* Conditional expression:
@ -366,8 +367,7 @@ u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
* The reason why we need to take into account "tf" here,
* is the same as described in i2c_dw_scl_lcnt().
*/
return (ic_clk * (tSYMBOL + tf) + 500000) / 1000000
- 3 + offset;
return DIV_ROUND_CLOSEST(ic_clk * (tSYMBOL + tf), MICRO) - 3 + offset;
}
u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
@ -383,7 +383,7 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
* account the fall time of SCL signal (tf). Default tf value
* should be 0.3 us, for safety.
*/
return ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 1 + offset;
return DIV_ROUND_CLOSEST(ic_clk * (tLOW + tf), MICRO) - 1 + offset;
}
int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)

View File

@ -117,7 +117,7 @@
#define DW_IC_ERR_TX_ABRT 0x1
#define DW_IC_TAR_10BITADDR_MASTER BIT(12)
#define DW_IC_TAR_10BITADDR_MASTER BIT(12)
#define DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH (BIT(2) | BIT(3))
#define DW_IC_COMP_PARAM_1_SPEED_MODE_MASK GENMASK(3, 2)
@ -245,7 +245,7 @@ struct dw_i2c_dev {
struct clk *clk;
struct clk *pclk;
struct reset_control *rst;
struct i2c_client *slave;
struct i2c_client *slave;
u32 (*get_clk_rate_khz) (struct dw_i2c_dev *dev);
int cmd_err;
struct i2c_msg *msgs;

View File

@ -31,12 +31,13 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/suspend.h>
#include <linux/units.h>
#include "i2c-designware-core.h"
static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
{
return clk_get_rate(dev->clk)/1000;
return clk_get_rate(dev->clk) / KILO;
}
#ifdef CONFIG_ACPI
@ -270,7 +271,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
if (!dev->sda_hold_time && t->sda_hold_ns)
dev->sda_hold_time =
div_u64(clk_khz * t->sda_hold_ns + 500000, 1000000);
DIV_S64_ROUND_CLOSEST(clk_khz * t->sda_hold_ns, MICRO);
}
adap = &dev->adapter;

View File

@ -379,7 +379,7 @@ static int highlander_i2c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dev);
dev->irq = platform_get_irq(pdev, 0);
if (iic_force_poll)
if (dev->irq < 0 || iic_force_poll)
dev->irq = 0;
if (dev->irq) {

View File

@ -413,7 +413,7 @@ static int hix5hd2_i2c_probe(struct platform_device *pdev)
return PTR_ERR(priv->regs);
irq = platform_get_irq(pdev, 0);
if (irq <= 0)
if (irq < 0)
return irq;
priv->clk = devm_clk_get(&pdev->dev, NULL);

View File

@ -110,6 +110,7 @@
#include <linux/platform_device.h>
#include <linux/platform_data/itco_wdt.h>
#include <linux/pm_runtime.h>
#include <linux/mutex.h>
#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI
#include <linux/gpio/machine.h>
@ -503,19 +504,16 @@ static int i801_transaction(struct i801_priv *priv, int xact)
static int i801_block_transaction_by_block(struct i801_priv *priv,
union i2c_smbus_data *data,
char read_write, int command,
int hwpec)
char read_write, int command)
{
int i, len;
int status;
int xact = hwpec ? SMBHSTCNT_PEC_EN : 0;
int i, len, status, xact;
switch (command) {
case I2C_SMBUS_BLOCK_PROC_CALL:
xact |= I801_BLOCK_PROC_CALL;
xact = I801_BLOCK_PROC_CALL;
break;
case I2C_SMBUS_BLOCK_DATA:
xact |= I801_BLOCK_DATA;
xact = I801_BLOCK_DATA;
break;
default:
return -EOPNOTSUPP;
@ -561,10 +559,6 @@ static void i801_isr_byte_done(struct i801_priv *priv)
priv->len);
/* FIXME: Recover */
priv->len = I2C_SMBUS_BLOCK_MAX;
} else {
dev_dbg(&priv->pci_dev->dev,
"SMBus block read size is %d\n",
priv->len);
}
priv->data[-1] = priv->len;
}
@ -665,8 +659,7 @@ static irqreturn_t i801_isr(int irq, void *dev_id)
*/
static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
union i2c_smbus_data *data,
char read_write, int command,
int hwpec)
char read_write, int command)
{
int i, len;
int smbcmd;
@ -764,9 +757,8 @@ static int i801_set_block_buffer_mode(struct i801_priv *priv)
}
/* Block transaction function */
static int i801_block_transaction(struct i801_priv *priv,
union i2c_smbus_data *data, char read_write,
int command, int hwpec)
static int i801_block_transaction(struct i801_priv *priv, union i2c_smbus_data *data,
char read_write, int command)
{
int result = 0;
unsigned char hostc;
@ -802,11 +794,11 @@ static int i801_block_transaction(struct i801_priv *priv,
&& i801_set_block_buffer_mode(priv) == 0)
result = i801_block_transaction_by_block(priv, data,
read_write,
command, hwpec);
command);
else
result = i801_block_transaction_byte_by_byte(priv, data,
read_write,
command, hwpec);
command);
if (command == I2C_SMBUS_I2C_BLOCK_DATA
&& read_write == I2C_SMBUS_WRITE) {
@ -917,8 +909,7 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
SMBAUXCTL(priv));
if (block)
ret = i801_block_transaction(priv, data, read_write, size,
hwpec);
ret = i801_block_transaction(priv, data, read_write, size);
else
ret = i801_transaction(priv, xact);
@ -1498,12 +1489,11 @@ static const struct itco_wdt_platform_data spt_tco_platform_data = {
.version = 4,
};
static DEFINE_SPINLOCK(p2sb_spinlock);
static struct platform_device *
i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev,
struct resource *tco_res)
{
static DEFINE_MUTEX(p2sb_mutex);
struct resource *res;
unsigned int devfn;
u64 base64_addr;
@ -1516,7 +1506,7 @@ i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev,
* enumerated by the PCI subsystem, so we need to unhide/hide it
* to lookup the P2SB BAR.
*/
spin_lock(&p2sb_spinlock);
mutex_lock(&p2sb_mutex);
devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 1);
@ -1534,7 +1524,7 @@ i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev,
/* Hide the P2SB device, if it was hidden before */
if (hidden)
pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, hidden);
spin_unlock(&p2sb_spinlock);
mutex_unlock(&p2sb_mutex);
res = &tco_res[1];
if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS)
@ -1634,7 +1624,7 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
* BIOS is accessing the host controller so prevent it from
* suspending automatically from now on.
*/
pm_runtime_get_sync(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, -1);
}
if ((function & ACPI_IO_MASK) == ACPI_READ)
@ -1674,11 +1664,6 @@ static void i801_acpi_remove(struct i801_priv *priv)
acpi_remove_address_space_handler(adev->handle,
ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler);
mutex_lock(&priv->acpi_lock);
if (priv->acpi_reserved)
pm_runtime_put(&priv->pci_dev->dev);
mutex_unlock(&priv->acpi_lock);
}
#else
static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; }
@ -1690,6 +1675,7 @@ static void i801_setup_hstcfg(struct i801_priv *priv)
unsigned char hstcfg = priv->original_hstcfg;
hstcfg &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */
hstcfg &= ~SMBHSTCNT_PEC_EN; /* Disable software PEC */
hstcfg |= SMBHSTCFG_HST_EN;
pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hstcfg);
}

View File

@ -423,7 +423,7 @@ static int i2c_imx_dma_xfer(struct imx_i2c_struct *i2c_imx,
return 0;
err_submit:
dmaengine_terminate_all(dma->chan_using);
dmaengine_terminate_sync(dma->chan_using);
err_desc:
dma_unmap_single(chan_dev, dma->dma_buf,
dma->dma_len, dma->dma_data_dir);
@ -894,7 +894,7 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
&i2c_imx->dma->cmd_complete,
msecs_to_jiffies(DMA_TIMEOUT));
if (time_left == 0) {
dmaengine_terminate_all(dma->chan_using);
dmaengine_terminate_sync(dma->chan_using);
return -ETIMEDOUT;
}
@ -949,7 +949,7 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
&i2c_imx->dma->cmd_complete,
msecs_to_jiffies(DMA_TIMEOUT));
if (time_left == 0) {
dmaengine_terminate_all(dma->chan_using);
dmaengine_terminate_sync(dma->chan_using);
return -ETIMEDOUT;
}

View File

@ -469,16 +469,14 @@ iop3xx_i2c_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = -ENXIO;
ret = irq;
goto unmap;
}
ret = request_irq(irq, iop3xx_i2c_irq_handler, 0,
pdev->name, adapter_data);
if (ret) {
ret = -EIO;
if (ret)
goto unmap;
}
memcpy(new_adapter->name, pdev->name, strlen(pdev->name));
new_adapter->owner = THIS_MODULE;

View File

@ -1211,7 +1211,7 @@ static int mtk_i2c_probe(struct platform_device *pdev)
return PTR_ERR(i2c->pdmabase);
irq = platform_get_irq(pdev, 0);
if (irq <= 0)
if (irq < 0)
return irq;
init_completion(&i2c->msg_complete);

View File

@ -290,14 +290,14 @@ read_init_dma_fail:
select_init_dma_fail:
dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE);
select_init_pio_fail:
dmaengine_terminate_all(i2c->dmach);
dmaengine_terminate_sync(i2c->dmach);
return -EINVAL;
/* Write failpath. */
write_init_dma_fail:
dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
write_init_pio_fail:
dmaengine_terminate_all(i2c->dmach);
dmaengine_terminate_sync(i2c->dmach);
return -EINVAL;
}

View File

@ -267,6 +267,16 @@ static void i2c_parport_attach(struct parport *port)
int i;
struct pardev_cb i2c_parport_cb;
if (type < 0) {
pr_warn("adapter type unspecified\n");
return;
}
if (type >= ARRAY_SIZE(adapter_parm)) {
pr_warn("invalid type (%d)\n", type);
return;
}
for (i = 0; i < MAX_DEVICE; i++) {
if (parport[i] == -1)
continue;
@ -392,32 +402,8 @@ static struct parport_driver i2c_parport_driver = {
.detach = i2c_parport_detach,
.devmodel = true,
};
/* ----- Module loading, unloading and information ------------------------ */
static int __init i2c_parport_init(void)
{
if (type < 0) {
pr_warn("adapter type unspecified\n");
return -ENODEV;
}
if (type >= ARRAY_SIZE(adapter_parm)) {
pr_warn("invalid type (%d)\n", type);
return -ENODEV;
}
return parport_register_driver(&i2c_parport_driver);
}
static void __exit i2c_parport_exit(void)
{
parport_unregister_driver(&i2c_parport_driver);
}
module_parport_driver(i2c_parport_driver);
MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
MODULE_DESCRIPTION("I2C bus over parallel port");
MODULE_LICENSE("GPL");
module_init(i2c_parport_init);
module_exit(i2c_parport_exit);

View File

@ -1,600 +0,0 @@
/*
* Specific bus support for PMC-TWI compliant implementation on MSP71xx.
*
* Copyright 2005-2007 PMC-Sierra, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/io.h>
#define DRV_NAME "pmcmsptwi"
#define MSP_TWI_SF_CLK_REG_OFFSET 0x00
#define MSP_TWI_HS_CLK_REG_OFFSET 0x04
#define MSP_TWI_CFG_REG_OFFSET 0x08
#define MSP_TWI_CMD_REG_OFFSET 0x0c
#define MSP_TWI_ADD_REG_OFFSET 0x10
#define MSP_TWI_DAT_0_REG_OFFSET 0x14
#define MSP_TWI_DAT_1_REG_OFFSET 0x18
#define MSP_TWI_INT_STS_REG_OFFSET 0x1c
#define MSP_TWI_INT_MSK_REG_OFFSET 0x20
#define MSP_TWI_BUSY_REG_OFFSET 0x24
#define MSP_TWI_INT_STS_DONE (1 << 0)
#define MSP_TWI_INT_STS_LOST_ARBITRATION (1 << 1)
#define MSP_TWI_INT_STS_NO_RESPONSE (1 << 2)
#define MSP_TWI_INT_STS_DATA_COLLISION (1 << 3)
#define MSP_TWI_INT_STS_BUSY (1 << 4)
#define MSP_TWI_INT_STS_ALL 0x1f
#define MSP_MAX_BYTES_PER_RW 8
#define MSP_MAX_POLL 5
#define MSP_POLL_DELAY 10
#define MSP_IRQ_TIMEOUT (MSP_MAX_POLL * MSP_POLL_DELAY)
/* IO Operation macros */
#define pmcmsptwi_readl __raw_readl
#define pmcmsptwi_writel __raw_writel
/* TWI command type */
enum pmcmsptwi_cmd_type {
MSP_TWI_CMD_WRITE = 0, /* Write only */
MSP_TWI_CMD_READ = 1, /* Read only */
MSP_TWI_CMD_WRITE_READ = 2, /* Write then Read */
};
/* The possible results of the xferCmd */
enum pmcmsptwi_xfer_result {
MSP_TWI_XFER_OK = 0,
MSP_TWI_XFER_TIMEOUT,
MSP_TWI_XFER_BUSY,
MSP_TWI_XFER_DATA_COLLISION,
MSP_TWI_XFER_NO_RESPONSE,
MSP_TWI_XFER_LOST_ARBITRATION,
};
/* Corresponds to a PMCTWI clock configuration register */
struct pmcmsptwi_clock {
u8 filter; /* Bits 15:12, default = 0x03 */
u16 clock; /* Bits 9:0, default = 0x001f */
};
struct pmcmsptwi_clockcfg {
struct pmcmsptwi_clock standard; /* The standard/fast clock config */
struct pmcmsptwi_clock highspeed; /* The highspeed clock config */
};
/* Corresponds to the main TWI configuration register */
struct pmcmsptwi_cfg {
u8 arbf; /* Bits 15:12, default=0x03 */
u8 nak; /* Bits 11:8, default=0x03 */
u8 add10; /* Bit 7, default=0x00 */
u8 mst_code; /* Bits 6:4, default=0x00 */
u8 arb; /* Bit 1, default=0x01 */
u8 highspeed; /* Bit 0, default=0x00 */
};
/* A single pmctwi command to issue */
struct pmcmsptwi_cmd {
u16 addr; /* The slave address (7 or 10 bits) */
enum pmcmsptwi_cmd_type type; /* The command type */
u8 write_len; /* Number of bytes in the write buffer */
u8 read_len; /* Number of bytes in the read buffer */
u8 *write_data; /* Buffer of characters to send */
u8 *read_data; /* Buffer to fill with incoming data */
};
/* The private data */
struct pmcmsptwi_data {
void __iomem *iobase; /* iomapped base for IO */
int irq; /* IRQ to use (0 disables) */
struct completion wait; /* Completion for xfer */
struct mutex lock; /* Used for threadsafeness */
enum pmcmsptwi_xfer_result last_result; /* result of last xfer */
};
/* The default settings */
static const struct pmcmsptwi_clockcfg pmcmsptwi_defclockcfg = {
.standard = {
.filter = 0x3,
.clock = 0x1f,
},
.highspeed = {
.filter = 0x3,
.clock = 0x1f,
},
};
static const struct pmcmsptwi_cfg pmcmsptwi_defcfg = {
.arbf = 0x03,
.nak = 0x03,
.add10 = 0x00,
.mst_code = 0x00,
.arb = 0x01,
.highspeed = 0x00,
};
static struct pmcmsptwi_data pmcmsptwi_data;
static struct i2c_adapter pmcmsptwi_adapter;
/* inline helper functions */
static inline u32 pmcmsptwi_clock_to_reg(
const struct pmcmsptwi_clock *clock)
{
return ((clock->filter & 0xf) << 12) | (clock->clock & 0x03ff);
}
static inline u32 pmcmsptwi_cfg_to_reg(const struct pmcmsptwi_cfg *cfg)
{
return ((cfg->arbf & 0xf) << 12) |
((cfg->nak & 0xf) << 8) |
((cfg->add10 & 0x1) << 7) |
((cfg->mst_code & 0x7) << 4) |
((cfg->arb & 0x1) << 1) |
(cfg->highspeed & 0x1);
}
static inline void pmcmsptwi_reg_to_cfg(u32 reg, struct pmcmsptwi_cfg *cfg)
{
cfg->arbf = (reg >> 12) & 0xf;
cfg->nak = (reg >> 8) & 0xf;
cfg->add10 = (reg >> 7) & 0x1;
cfg->mst_code = (reg >> 4) & 0x7;
cfg->arb = (reg >> 1) & 0x1;
cfg->highspeed = reg & 0x1;
}
/*
* Sets the current clock configuration
*/
static void pmcmsptwi_set_clock_config(const struct pmcmsptwi_clockcfg *cfg,
struct pmcmsptwi_data *data)
{
mutex_lock(&data->lock);
pmcmsptwi_writel(pmcmsptwi_clock_to_reg(&cfg->standard),
data->iobase + MSP_TWI_SF_CLK_REG_OFFSET);
pmcmsptwi_writel(pmcmsptwi_clock_to_reg(&cfg->highspeed),
data->iobase + MSP_TWI_HS_CLK_REG_OFFSET);
mutex_unlock(&data->lock);
}
/*
* Gets the current TWI bus configuration
*/
static void pmcmsptwi_get_twi_config(struct pmcmsptwi_cfg *cfg,
struct pmcmsptwi_data *data)
{
mutex_lock(&data->lock);
pmcmsptwi_reg_to_cfg(pmcmsptwi_readl(
data->iobase + MSP_TWI_CFG_REG_OFFSET), cfg);
mutex_unlock(&data->lock);
}
/*
* Sets the current TWI bus configuration
*/
static void pmcmsptwi_set_twi_config(const struct pmcmsptwi_cfg *cfg,
struct pmcmsptwi_data *data)
{
mutex_lock(&data->lock);
pmcmsptwi_writel(pmcmsptwi_cfg_to_reg(cfg),
data->iobase + MSP_TWI_CFG_REG_OFFSET);
mutex_unlock(&data->lock);
}
/*
* Parses the 'int_sts' register and returns a well-defined error code
*/
static enum pmcmsptwi_xfer_result pmcmsptwi_get_result(u32 reg)
{
if (reg & MSP_TWI_INT_STS_LOST_ARBITRATION) {
dev_dbg(&pmcmsptwi_adapter.dev,
"Result: Lost arbitration\n");
return MSP_TWI_XFER_LOST_ARBITRATION;
} else if (reg & MSP_TWI_INT_STS_NO_RESPONSE) {
dev_dbg(&pmcmsptwi_adapter.dev,
"Result: No response\n");
return MSP_TWI_XFER_NO_RESPONSE;
} else if (reg & MSP_TWI_INT_STS_DATA_COLLISION) {
dev_dbg(&pmcmsptwi_adapter.dev,
"Result: Data collision\n");
return MSP_TWI_XFER_DATA_COLLISION;
} else if (reg & MSP_TWI_INT_STS_BUSY) {
dev_dbg(&pmcmsptwi_adapter.dev,
"Result: Bus busy\n");
return MSP_TWI_XFER_BUSY;
}
dev_dbg(&pmcmsptwi_adapter.dev, "Result: Operation succeeded\n");
return MSP_TWI_XFER_OK;
}
/*
* In interrupt mode, handle the interrupt.
* NOTE: Assumes data->lock is held.
*/
static irqreturn_t pmcmsptwi_interrupt(int irq, void *ptr)
{
struct pmcmsptwi_data *data = ptr;
u32 reason = pmcmsptwi_readl(data->iobase +
MSP_TWI_INT_STS_REG_OFFSET);
pmcmsptwi_writel(reason, data->iobase + MSP_TWI_INT_STS_REG_OFFSET);
dev_dbg(&pmcmsptwi_adapter.dev, "Got interrupt 0x%08x\n", reason);
if (!(reason & MSP_TWI_INT_STS_DONE))
return IRQ_NONE;
data->last_result = pmcmsptwi_get_result(reason);
complete(&data->wait);
return IRQ_HANDLED;
}
/*
* Probe for and register the device and return 0 if there is one.
*/
static int pmcmsptwi_probe(struct platform_device *pldev)
{
struct resource *res;
int rc = -ENODEV;
/* get the static platform resources */
res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pldev->dev, "IOMEM resource not found\n");
goto ret_err;
}
/* reserve the memory region */
if (!request_mem_region(res->start, resource_size(res),
pldev->name)) {
dev_err(&pldev->dev,
"Unable to get memory/io address region %pap\n",
&res->start);
rc = -EBUSY;
goto ret_err;
}
/* remap the memory */
pmcmsptwi_data.iobase = ioremap(res->start,
resource_size(res));
if (!pmcmsptwi_data.iobase) {
dev_err(&pldev->dev,
"Unable to ioremap address %pap\n", &res->start);
rc = -EIO;
goto ret_unreserve;
}
/* request the irq */
pmcmsptwi_data.irq = platform_get_irq(pldev, 0);
if (pmcmsptwi_data.irq) {
rc = request_irq(pmcmsptwi_data.irq, &pmcmsptwi_interrupt,
IRQF_SHARED, pldev->name, &pmcmsptwi_data);
if (rc == 0) {
/*
* Enable 'DONE' interrupt only.
*
* If you enable all interrupts, you will get one on
* error and another when the operation completes.
* This way you only have to handle one interrupt,
* but you can still check all result flags.
*/
pmcmsptwi_writel(MSP_TWI_INT_STS_DONE,
pmcmsptwi_data.iobase +
MSP_TWI_INT_MSK_REG_OFFSET);
} else {
dev_warn(&pldev->dev,
"Could not assign TWI IRQ handler "
"to irq %d (continuing with poll)\n",
pmcmsptwi_data.irq);
pmcmsptwi_data.irq = 0;
}
}
init_completion(&pmcmsptwi_data.wait);
mutex_init(&pmcmsptwi_data.lock);
pmcmsptwi_set_clock_config(&pmcmsptwi_defclockcfg, &pmcmsptwi_data);
pmcmsptwi_set_twi_config(&pmcmsptwi_defcfg, &pmcmsptwi_data);
printk(KERN_INFO DRV_NAME ": Registering MSP71xx I2C adapter\n");
pmcmsptwi_adapter.dev.parent = &pldev->dev;
platform_set_drvdata(pldev, &pmcmsptwi_adapter);
i2c_set_adapdata(&pmcmsptwi_adapter, &pmcmsptwi_data);
rc = i2c_add_adapter(&pmcmsptwi_adapter);
if (rc)
goto ret_unmap;
return 0;
ret_unmap:
if (pmcmsptwi_data.irq) {
pmcmsptwi_writel(0,
pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET);
free_irq(pmcmsptwi_data.irq, &pmcmsptwi_data);
}
iounmap(pmcmsptwi_data.iobase);
ret_unreserve:
release_mem_region(res->start, resource_size(res));
ret_err:
return rc;
}
/*
* Release the device and return 0 if there is one.
*/
static int pmcmsptwi_remove(struct platform_device *pldev)
{
struct resource *res;
i2c_del_adapter(&pmcmsptwi_adapter);
if (pmcmsptwi_data.irq) {
pmcmsptwi_writel(0,
pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET);
free_irq(pmcmsptwi_data.irq, &pmcmsptwi_data);
}
iounmap(pmcmsptwi_data.iobase);
res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
return 0;
}
/*
* Polls the 'busy' register until the command is complete.
* NOTE: Assumes data->lock is held.
*/
static void pmcmsptwi_poll_complete(struct pmcmsptwi_data *data)
{
int i;
for (i = 0; i < MSP_MAX_POLL; i++) {
u32 val = pmcmsptwi_readl(data->iobase +
MSP_TWI_BUSY_REG_OFFSET);
if (val == 0) {
u32 reason = pmcmsptwi_readl(data->iobase +
MSP_TWI_INT_STS_REG_OFFSET);
pmcmsptwi_writel(reason, data->iobase +
MSP_TWI_INT_STS_REG_OFFSET);
data->last_result = pmcmsptwi_get_result(reason);
return;
}
udelay(MSP_POLL_DELAY);
}
dev_dbg(&pmcmsptwi_adapter.dev, "Result: Poll timeout\n");
data->last_result = MSP_TWI_XFER_TIMEOUT;
}
/*
* Do the transfer (low level):
* May use interrupt-driven or polling, depending on if an IRQ is
* presently registered.
* NOTE: Assumes data->lock is held.
*/
static enum pmcmsptwi_xfer_result pmcmsptwi_do_xfer(
u32 reg, struct pmcmsptwi_data *data)
{
dev_dbg(&pmcmsptwi_adapter.dev, "Writing cmd reg 0x%08x\n", reg);
pmcmsptwi_writel(reg, data->iobase + MSP_TWI_CMD_REG_OFFSET);
if (data->irq) {
unsigned long timeleft = wait_for_completion_timeout(
&data->wait, MSP_IRQ_TIMEOUT);
if (timeleft == 0) {
dev_dbg(&pmcmsptwi_adapter.dev,
"Result: IRQ timeout\n");
complete(&data->wait);
data->last_result = MSP_TWI_XFER_TIMEOUT;
}
} else
pmcmsptwi_poll_complete(data);
return data->last_result;
}
/*
* Helper routine, converts 'pmctwi_cmd' struct to register format
*/
static inline u32 pmcmsptwi_cmd_to_reg(const struct pmcmsptwi_cmd *cmd)
{
return ((cmd->type & 0x3) << 8) |
(((cmd->write_len - 1) & 0x7) << 4) |
((cmd->read_len - 1) & 0x7);
}
/*
* Do the transfer (high level)
*/
static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd(
struct pmcmsptwi_cmd *cmd,
struct pmcmsptwi_data *data)
{
enum pmcmsptwi_xfer_result retval;
mutex_lock(&data->lock);
dev_dbg(&pmcmsptwi_adapter.dev,
"Setting address to 0x%04x\n", cmd->addr);
pmcmsptwi_writel(cmd->addr, data->iobase + MSP_TWI_ADD_REG_OFFSET);
if (cmd->type == MSP_TWI_CMD_WRITE ||
cmd->type == MSP_TWI_CMD_WRITE_READ) {
u64 tmp = be64_to_cpup((__be64 *)cmd->write_data);
tmp >>= (MSP_MAX_BYTES_PER_RW - cmd->write_len) * 8;
dev_dbg(&pmcmsptwi_adapter.dev, "Writing 0x%016llx\n", tmp);
pmcmsptwi_writel(tmp & 0x00000000ffffffffLL,
data->iobase + MSP_TWI_DAT_0_REG_OFFSET);
if (cmd->write_len > 4)
pmcmsptwi_writel(tmp >> 32,
data->iobase + MSP_TWI_DAT_1_REG_OFFSET);
}
retval = pmcmsptwi_do_xfer(pmcmsptwi_cmd_to_reg(cmd), data);
if (retval != MSP_TWI_XFER_OK)
goto xfer_err;
if (cmd->type == MSP_TWI_CMD_READ ||
cmd->type == MSP_TWI_CMD_WRITE_READ) {
int i;
u64 rmsk = ~(0xffffffffffffffffLL << (cmd->read_len * 8));
u64 tmp = (u64)pmcmsptwi_readl(data->iobase +
MSP_TWI_DAT_0_REG_OFFSET);
if (cmd->read_len > 4)
tmp |= (u64)pmcmsptwi_readl(data->iobase +
MSP_TWI_DAT_1_REG_OFFSET) << 32;
tmp &= rmsk;
dev_dbg(&pmcmsptwi_adapter.dev, "Read 0x%016llx\n", tmp);
for (i = 0; i < cmd->read_len; i++)
cmd->read_data[i] = tmp >> i;
}
xfer_err:
mutex_unlock(&data->lock);
return retval;
}
/* -- Algorithm functions -- */
/*
* Sends an i2c command out on the adapter
*/
static int pmcmsptwi_master_xfer(struct i2c_adapter *adap,
struct i2c_msg *msg, int num)
{
struct pmcmsptwi_data *data = i2c_get_adapdata(adap);
struct pmcmsptwi_cmd cmd;
struct pmcmsptwi_cfg oldcfg, newcfg;
int ret;
if (num == 2) {
struct i2c_msg *nextmsg = msg + 1;
cmd.type = MSP_TWI_CMD_WRITE_READ;
cmd.write_len = msg->len;
cmd.write_data = msg->buf;
cmd.read_len = nextmsg->len;
cmd.read_data = nextmsg->buf;
} else if (msg->flags & I2C_M_RD) {
cmd.type = MSP_TWI_CMD_READ;
cmd.read_len = msg->len;
cmd.read_data = msg->buf;
cmd.write_len = 0;
cmd.write_data = NULL;
} else {
cmd.type = MSP_TWI_CMD_WRITE;
cmd.read_len = 0;
cmd.read_data = NULL;
cmd.write_len = msg->len;
cmd.write_data = msg->buf;
}
cmd.addr = msg->addr;
if (msg->flags & I2C_M_TEN) {
pmcmsptwi_get_twi_config(&newcfg, data);
memcpy(&oldcfg, &newcfg, sizeof(oldcfg));
/* Set the special 10-bit address flag */
newcfg.add10 = 1;
pmcmsptwi_set_twi_config(&newcfg, data);
}
/* Execute the command */
ret = pmcmsptwi_xfer_cmd(&cmd, data);
if (msg->flags & I2C_M_TEN)
pmcmsptwi_set_twi_config(&oldcfg, data);
dev_dbg(&adap->dev, "I2C %s of %d bytes %s\n",
(msg->flags & I2C_M_RD) ? "read" : "write", msg->len,
(ret == MSP_TWI_XFER_OK) ? "succeeded" : "failed");
if (ret != MSP_TWI_XFER_OK) {
/*
* TODO: We could potentially loop and retry in the case
* of MSP_TWI_XFER_TIMEOUT.
*/
return -EIO;
}
return num;
}
static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR |
I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL;
}
static const struct i2c_adapter_quirks pmcmsptwi_i2c_quirks = {
.flags = I2C_AQ_COMB_WRITE_THEN_READ | I2C_AQ_NO_ZERO_LEN,
.max_write_len = MSP_MAX_BYTES_PER_RW,
.max_read_len = MSP_MAX_BYTES_PER_RW,
.max_comb_1st_msg_len = MSP_MAX_BYTES_PER_RW,
.max_comb_2nd_msg_len = MSP_MAX_BYTES_PER_RW,
};
/* -- Initialization -- */
static const struct i2c_algorithm pmcmsptwi_algo = {
.master_xfer = pmcmsptwi_master_xfer,
.functionality = pmcmsptwi_i2c_func,
};
static struct i2c_adapter pmcmsptwi_adapter = {
.owner = THIS_MODULE,
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
.algo = &pmcmsptwi_algo,
.quirks = &pmcmsptwi_i2c_quirks,
.name = DRV_NAME,
};
static struct platform_driver pmcmsptwi_driver = {
.probe = pmcmsptwi_probe,
.remove = pmcmsptwi_remove,
.driver = {
.name = DRV_NAME,
},
};
module_platform_driver(pmcmsptwi_driver);
MODULE_DESCRIPTION("PMC MSP TWI/SMBus/I2C driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRV_NAME);

View File

@ -778,7 +778,7 @@ static int qup_i2c_bam_schedule_desc(struct qup_i2c_dev *qup)
ret = -EINVAL;
/* abort TX descriptors */
dmaengine_terminate_all(qup->btx.dma);
dmaengine_terminate_sync(qup->btx.dma);
goto desc_err;
}

View File

@ -1137,7 +1137,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
*/
if (!(i2c->quirks & QUIRK_POLL)) {
i2c->irq = ret = platform_get_irq(pdev, 0);
if (ret <= 0) {
if (ret < 0) {
dev_err(&pdev->dev, "cannot find IRQ\n");
clk_unprepare(i2c->clk);
return ret;

View File

@ -458,9 +458,9 @@ static void sh_mobile_i2c_cleanup_dma(struct sh_mobile_i2c_data *pd)
if (pd->dma_direction == DMA_NONE)
return;
else if (pd->dma_direction == DMA_FROM_DEVICE)
dmaengine_terminate_all(pd->dma_rx);
dmaengine_terminate_sync(pd->dma_rx);
else if (pd->dma_direction == DMA_TO_DEVICE)
dmaengine_terminate_all(pd->dma_tx);
dmaengine_terminate_sync(pd->dma_tx);
sh_mobile_i2c_dma_unmap(pd);
}

View File

@ -234,7 +234,7 @@ static int p2wi_probe(struct platform_device *pdev)
if (IS_ERR(p2wi->regs))
return PTR_ERR(p2wi->regs);
strlcpy(p2wi->adapter.name, pdev->name, sizeof(p2wi->adapter.name));
strscpy(p2wi->adapter.name, pdev->name, sizeof(p2wi->adapter.name));
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;

View File

@ -578,7 +578,7 @@ static int synquacer_i2c_probe(struct platform_device *pdev)
i2c->irq = platform_get_irq(pdev, 0);
if (i2c->irq < 0)
return -ENODEV;
return i2c->irq;
ret = devm_request_irq(&pdev->dev, i2c->irq, synquacer_i2c_isr,
0, dev_name(&pdev->dev), i2c);

View File

@ -0,0 +1,290 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Virtio I2C Bus Driver
*
* The Virtio I2C Specification:
* https://raw.githubusercontent.com/oasis-tcs/virtio-spec/master/virtio-i2c.tex
*
* Copyright (c) 2021 Intel Corporation. All rights reserved.
*/
#include <linux/acpi.h>
#include <linux/completion.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/virtio.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
#include <linux/virtio_i2c.h>
/**
* struct virtio_i2c - virtio I2C data
* @vdev: virtio device for this controller
* @completion: completion of virtio I2C message
* @adap: I2C adapter for this controller
* @vq: the virtio virtqueue for communication
*/
struct virtio_i2c {
struct virtio_device *vdev;
struct completion completion;
struct i2c_adapter adap;
struct virtqueue *vq;
};
/**
* struct virtio_i2c_req - the virtio I2C request structure
* @out_hdr: the OUT header of the virtio I2C message
* @buf: the buffer into which data is read, or from which it's written
* @in_hdr: the IN header of the virtio I2C message
*/
struct virtio_i2c_req {
struct virtio_i2c_out_hdr out_hdr ____cacheline_aligned;
uint8_t *buf ____cacheline_aligned;
struct virtio_i2c_in_hdr in_hdr ____cacheline_aligned;
};
static void virtio_i2c_msg_done(struct virtqueue *vq)
{
struct virtio_i2c *vi = vq->vdev->priv;
complete(&vi->completion);
}
static int virtio_i2c_prepare_reqs(struct virtqueue *vq,
struct virtio_i2c_req *reqs,
struct i2c_msg *msgs, int num)
{
struct scatterlist *sgs[3], out_hdr, msg_buf, in_hdr;
int i;
for (i = 0; i < num; i++) {
int outcnt = 0, incnt = 0;
/*
* We don't support 0 length messages and so filter out
* 0 length transfers by using i2c_adapter_quirks.
*/
if (!msgs[i].len)
break;
/*
* Only 7-bit mode supported for this moment. For the address
* format, Please check the Virtio I2C Specification.
*/
reqs[i].out_hdr.addr = cpu_to_le16(msgs[i].addr << 1);
if (i != num - 1)
reqs[i].out_hdr.flags = cpu_to_le32(VIRTIO_I2C_FLAGS_FAIL_NEXT);
sg_init_one(&out_hdr, &reqs[i].out_hdr, sizeof(reqs[i].out_hdr));
sgs[outcnt++] = &out_hdr;
reqs[i].buf = i2c_get_dma_safe_msg_buf(&msgs[i], 1);
if (!reqs[i].buf)
break;
sg_init_one(&msg_buf, reqs[i].buf, msgs[i].len);
if (msgs[i].flags & I2C_M_RD)
sgs[outcnt + incnt++] = &msg_buf;
else
sgs[outcnt++] = &msg_buf;
sg_init_one(&in_hdr, &reqs[i].in_hdr, sizeof(reqs[i].in_hdr));
sgs[outcnt + incnt++] = &in_hdr;
if (virtqueue_add_sgs(vq, sgs, outcnt, incnt, &reqs[i], GFP_KERNEL)) {
i2c_put_dma_safe_msg_buf(reqs[i].buf, &msgs[i], false);
break;
}
}
return i;
}
static int virtio_i2c_complete_reqs(struct virtqueue *vq,
struct virtio_i2c_req *reqs,
struct i2c_msg *msgs, int num,
bool timedout)
{
struct virtio_i2c_req *req;
bool failed = timedout;
unsigned int len;
int i, j = 0;
for (i = 0; i < num; i++) {
/* Detach the ith request from the vq */
req = virtqueue_get_buf(vq, &len);
/*
* Condition req == &reqs[i] should always meet since we have
* total num requests in the vq. reqs[i] can never be NULL here.
*/
if (!failed && (WARN_ON(req != &reqs[i]) ||
req->in_hdr.status != VIRTIO_I2C_MSG_OK))
failed = true;
i2c_put_dma_safe_msg_buf(reqs[i].buf, &msgs[i], !failed);
if (!failed)
j++;
}
return timedout ? -ETIMEDOUT : j;
}
static int virtio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num)
{
struct virtio_i2c *vi = i2c_get_adapdata(adap);
struct virtqueue *vq = vi->vq;
struct virtio_i2c_req *reqs;
unsigned long time_left;
int count;
reqs = kcalloc(num, sizeof(*reqs), GFP_KERNEL);
if (!reqs)
return -ENOMEM;
count = virtio_i2c_prepare_reqs(vq, reqs, msgs, num);
if (!count)
goto err_free;
/*
* For the case where count < num, i.e. we weren't able to queue all the
* msgs, ideally we should abort right away and return early, but some
* of the messages are already sent to the remote I2C controller and the
* virtqueue will be left in undefined state in that case. We kick the
* remote here to clear the virtqueue, so we can try another set of
* messages later on.
*/
reinit_completion(&vi->completion);
virtqueue_kick(vq);
time_left = wait_for_completion_timeout(&vi->completion, adap->timeout);
if (!time_left)
dev_err(&adap->dev, "virtio i2c backend timeout.\n");
count = virtio_i2c_complete_reqs(vq, reqs, msgs, count, !time_left);
err_free:
kfree(reqs);
return count;
}
static void virtio_i2c_del_vqs(struct virtio_device *vdev)
{
vdev->config->reset(vdev);
vdev->config->del_vqs(vdev);
}
static int virtio_i2c_setup_vqs(struct virtio_i2c *vi)
{
struct virtio_device *vdev = vi->vdev;
vi->vq = virtio_find_single_vq(vdev, virtio_i2c_msg_done, "msg");
return PTR_ERR_OR_ZERO(vi->vq);
}
static u32 virtio_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
}
static struct i2c_algorithm virtio_algorithm = {
.master_xfer = virtio_i2c_xfer,
.functionality = virtio_i2c_func,
};
static const struct i2c_adapter_quirks virtio_i2c_quirks = {
.flags = I2C_AQ_NO_ZERO_LEN,
};
static int virtio_i2c_probe(struct virtio_device *vdev)
{
struct virtio_i2c *vi;
int ret;
vi = devm_kzalloc(&vdev->dev, sizeof(*vi), GFP_KERNEL);
if (!vi)
return -ENOMEM;
vdev->priv = vi;
vi->vdev = vdev;
init_completion(&vi->completion);
ret = virtio_i2c_setup_vqs(vi);
if (ret)
return ret;
vi->adap.owner = THIS_MODULE;
snprintf(vi->adap.name, sizeof(vi->adap.name),
"i2c_virtio at virtio bus %d", vdev->index);
vi->adap.algo = &virtio_algorithm;
vi->adap.quirks = &virtio_i2c_quirks;
vi->adap.dev.parent = &vdev->dev;
vi->adap.dev.of_node = vdev->dev.of_node;
i2c_set_adapdata(&vi->adap, vi);
/*
* Setup ACPI node for controlled devices which will be probed through
* ACPI.
*/
ACPI_COMPANION_SET(&vi->adap.dev, ACPI_COMPANION(vdev->dev.parent));
ret = i2c_add_adapter(&vi->adap);
if (ret)
virtio_i2c_del_vqs(vdev);
return ret;
}
static void virtio_i2c_remove(struct virtio_device *vdev)
{
struct virtio_i2c *vi = vdev->priv;
i2c_del_adapter(&vi->adap);
virtio_i2c_del_vqs(vdev);
}
static struct virtio_device_id id_table[] = {
{ VIRTIO_ID_I2C_ADAPTER, VIRTIO_DEV_ANY_ID },
{}
};
MODULE_DEVICE_TABLE(virtio, id_table);
#ifdef CONFIG_PM_SLEEP
static int virtio_i2c_freeze(struct virtio_device *vdev)
{
virtio_i2c_del_vqs(vdev);
return 0;
}
static int virtio_i2c_restore(struct virtio_device *vdev)
{
return virtio_i2c_setup_vqs(vdev->priv);
}
#endif
static struct virtio_driver virtio_i2c_driver = {
.id_table = id_table,
.probe = virtio_i2c_probe,
.remove = virtio_i2c_remove,
.driver = {
.name = "i2c_virtio",
},
#ifdef CONFIG_PM_SLEEP
.freeze = virtio_i2c_freeze,
.restore = virtio_i2c_restore,
#endif
};
module_virtio_driver(virtio_i2c_driver);
MODULE_AUTHOR("Jie Deng <jie.deng@intel.com>");
MODULE_AUTHOR("Conghui Chen <conghui.chen@intel.com>");
MODULE_DESCRIPTION("Virtio i2c bus driver");
MODULE_LICENSE("GPL");

View File

@ -517,7 +517,7 @@ static int xlp9xx_i2c_probe(struct platform_device *pdev)
return PTR_ERR(priv->base);
priv->irq = platform_get_irq(pdev, 0);
if (priv->irq <= 0)
if (priv->irq < 0)
return priv->irq;
/* SMBAlert irq */
priv->alert_data.irq = platform_get_irq(pdev, 1);

View File

@ -14,6 +14,8 @@
/* The I2C_RDWR ioctl code is written by Kolja Waschk <waschk@telos.de> */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/cdev.h>
#include <linux/compat.h>
#include <linux/device.h>
@ -68,8 +70,7 @@ static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap)
struct i2c_dev *i2c_dev;
if (adap->nr >= I2C_MINORS) {
printk(KERN_ERR "i2c-dev: Out of device minors (%d)\n",
adap->nr);
pr_err("Out of device minors (%d)\n", adap->nr);
return ERR_PTR(-ENODEV);
}
@ -101,7 +102,7 @@ static ssize_t name_show(struct device *dev,
if (!i2c_dev)
return -ENODEV;
return sprintf(buf, "%s\n", i2c_dev->adap->name);
return sysfs_emit(buf, "%s\n", i2c_dev->adap->name);
}
static DEVICE_ATTR_RO(name);
@ -145,8 +146,7 @@ static ssize_t i2cdev_read(struct file *file, char __user *buf, size_t count,
if (tmp == NULL)
return -ENOMEM;
pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n",
iminor(file_inode(file)), count);
pr_debug("i2c-%d reading %zu bytes.\n", iminor(file_inode(file)), count);
ret = i2c_master_recv(client, tmp, count);
if (ret >= 0)
@ -170,8 +170,7 @@ static ssize_t i2cdev_write(struct file *file, const char __user *buf,
if (IS_ERR(tmp))
return PTR_ERR(tmp);
pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n",
iminor(file_inode(file)), count);
pr_debug("i2c-%d writing %zu bytes.\n", iminor(file_inode(file)), count);
ret = i2c_master_send(client, tmp, count);
kfree(tmp);
@ -674,8 +673,7 @@ static int i2cdev_attach_adapter(struct device *dev, void *dummy)
return res;
}
pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
adap->name, adap->nr);
pr_debug("adapter [%s] registered as minor %d\n", adap->name, adap->nr);
return 0;
}
@ -694,7 +692,7 @@ static int i2cdev_detach_adapter(struct device *dev, void *dummy)
put_i2c_dev(i2c_dev, true);
pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
pr_debug("adapter [%s] unregistered\n", adap->name);
return 0;
}
@ -727,7 +725,7 @@ static int __init i2c_dev_init(void)
{
int res;
printk(KERN_INFO "i2c /dev entries driver\n");
pr_info("i2c /dev entries driver\n");
res = register_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS, "i2c");
if (res)
@ -755,7 +753,7 @@ out_unreg_class:
out_unreg_chrdev:
unregister_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS);
out:
printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
pr_err("Driver Initialisation failed\n");
return res;
}

View File

@ -4,6 +4,22 @@
#include <linux/math.h>
/* Metric prefixes in accordance with Système international (d'unités) */
#define PETA 1000000000000000ULL
#define TERA 1000000000000ULL
#define GIGA 1000000000UL
#define MEGA 1000000UL
#define KILO 1000UL
#define HECTO 100UL
#define DECA 10UL
#define DECI 10UL
#define CENTI 100UL
#define MILLI 1000UL
#define MICRO 1000000UL
#define NANO 1000000000UL
#define PICO 1000000000000ULL
#define FEMTO 1000000000000000ULL
#define MILLIWATT_PER_WATT 1000L
#define MICROWATT_PER_MILLIWATT 1000L
#define MICROWATT_PER_WATT 1000000L

View File

@ -0,0 +1,41 @@
/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */
/*
* Definitions for virtio I2C Adpter
*
* Copyright (c) 2021 Intel Corporation. All rights reserved.
*/
#ifndef _UAPI_LINUX_VIRTIO_I2C_H
#define _UAPI_LINUX_VIRTIO_I2C_H
#include <linux/const.h>
#include <linux/types.h>
/* The bit 0 of the @virtio_i2c_out_hdr.@flags, used to group the requests */
#define VIRTIO_I2C_FLAGS_FAIL_NEXT _BITUL(0)
/**
* struct virtio_i2c_out_hdr - the virtio I2C message OUT header
* @addr: the controlled device address
* @padding: used to pad to full dword
* @flags: used for feature extensibility
*/
struct virtio_i2c_out_hdr {
__le16 addr;
__le16 padding;
__le32 flags;
};
/**
* struct virtio_i2c_in_hdr - the virtio I2C message IN header
* @status: the processing result from the backend
*/
struct virtio_i2c_in_hdr {
__u8 status;
};
/* The final status written by the device */
#define VIRTIO_I2C_MSG_OK 0
#define VIRTIO_I2C_MSG_ERR 1
#endif /* _UAPI_LINUX_VIRTIO_I2C_H */

View File

@ -55,6 +55,7 @@
#define VIRTIO_ID_FS 26 /* virtio filesystem */
#define VIRTIO_ID_PMEM 27 /* virtio pmem */
#define VIRTIO_ID_MAC80211_HWSIM 29 /* virtio mac80211-hwsim */
#define VIRTIO_ID_I2C_ADAPTER 34 /* virtio i2c adapter */
#define VIRTIO_ID_BT 40 /* virtio bluetooth */
/*