Merge branch 'i2c/for-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang:
- Peter Rosin did some major rework on the locking of i2c muxes by
seperating parent-locked muxes and mux-locked muxes.
This avoids deadlocks/workarounds when the mux itself needs i2c
commands for muxing. And as a side-effect, other workarounds in the
media layer could be eliminated. Also, Peter stepped up as the i2c
mux maintainer and will keep an eye on these changes.
- major updates to the octeon driver
- add a helper to the core to generate the address+rw_bit octal and
make drivers use it
- quite a bunch of driver updates
* 'i2c/for-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (84 commits)
i2c: rcar: add DMA support
i2c: st: Implement bus clear
i2c: only check scl functions when using generic recovery
i2c: algo-bit: declare i2c_bit_quirk_no_clk_stretch as static
i2c: tegra: disable clock before returning error
[media] rtl2832: regmap is aware of lockdep, drop local locking hack
[media] rtl2832_sdr: get rid of empty regmap wrappers
[media] rtl2832: change the i2c gate to be mux-locked
[media] si2168: change the i2c gate to be mux-locked
iio: imu: inv_mpu6050: change the i2c gate to be mux-locked
i2c: mux: document i2c muxes and elaborate on parent-/mux-locked muxes
i2c: mux: relax locking of the top i2c adapter during mux-locked muxing
i2c: muxes always lock the parent adapter
i2c: allow adapter drivers to override the adapter locking
i2c: uniphier: add "\n" at the end of error log
i2c: mv64xxx: remove CONFIG_HAVE_CLK conditionals
i2c: mv64xxx: use clk_{prepare_enable,disable_unprepare}
i2c: mv64xxx: handle probe deferral for the clock
i2c: mv64xxx: enable the driver on ARCH_MVEBU
i2c: octeon: Add workaround for broken irqs on CN3860
...
This commit is contained in:
@@ -617,7 +617,7 @@ const struct i2c_algorithm i2c_bit_algo = {
|
||||
};
|
||||
EXPORT_SYMBOL(i2c_bit_algo);
|
||||
|
||||
const struct i2c_adapter_quirks i2c_bit_quirk_no_clk_stretch = {
|
||||
static const struct i2c_adapter_quirks i2c_bit_quirk_no_clk_stretch = {
|
||||
.flags = I2C_AQ_NO_CLK_STRETCH,
|
||||
};
|
||||
|
||||
|
||||
@@ -663,7 +663,7 @@ config I2C_MT65XX
|
||||
|
||||
config I2C_MV64XXX
|
||||
tristate "Marvell mv64xxx I2C Controller"
|
||||
depends on MV64X60 || PLAT_ORION || ARCH_SUNXI
|
||||
depends on MV64X60 || PLAT_ORION || ARCH_SUNXI || ARCH_MVEBU
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
built-in I2C interface on the Marvell 64xxx line of host bridges.
|
||||
|
||||
@@ -267,7 +267,7 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
|
||||
iproc_i2c->msg = msg;
|
||||
|
||||
/* format and load slave address into the TX FIFO */
|
||||
addr = msg->addr << 1 | (msg->flags & I2C_M_RD ? 1 : 0);
|
||||
addr = i2c_8bit_addr_from_msg(msg);
|
||||
writel(addr, iproc_i2c->base + M_TX_OFFSET);
|
||||
|
||||
/*
|
||||
|
||||
@@ -501,10 +501,7 @@ static int bcm_kona_i2c_do_addr(struct bcm_kona_i2c_dev *dev,
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
} else {
|
||||
addr = msg->addr << 1;
|
||||
|
||||
if (msg->flags & I2C_M_RD)
|
||||
addr |= 1;
|
||||
addr = i2c_8bit_addr_from_msg(msg);
|
||||
|
||||
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
|
||||
return -EREMOTEIO;
|
||||
|
||||
@@ -446,9 +446,7 @@ static int brcmstb_i2c_do_addr(struct brcmstb_i2c_dev *dev,
|
||||
|
||||
}
|
||||
} else {
|
||||
addr = msg->addr << 1;
|
||||
if (msg->flags & I2C_M_RD)
|
||||
addr |= 1;
|
||||
addr = i2c_8bit_addr_from_msg(msg);
|
||||
|
||||
bsc_writel(dev, addr, chip_address);
|
||||
}
|
||||
|
||||
@@ -197,9 +197,7 @@ static void cpm_i2c_parse_message(struct i2c_adapter *adap,
|
||||
tbdf = cpm->tbase + tx;
|
||||
rbdf = cpm->rbase + rx;
|
||||
|
||||
addr = pmsg->addr << 1;
|
||||
if (pmsg->flags & I2C_M_RD)
|
||||
addr |= 1;
|
||||
addr = i2c_8bit_addr_from_msg(pmsg);
|
||||
|
||||
tb = cpm->txbuf[tx];
|
||||
rb = cpm->rxbuf[rx];
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/dln2.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#define DLN2_I2C_MODULE_ID 0x03
|
||||
#define DLN2_I2C_CMD(cmd) DLN2_CMD(cmd, DLN2_I2C_MODULE_ID)
|
||||
@@ -210,6 +211,7 @@ static int dln2_i2c_probe(struct platform_device *pdev)
|
||||
dln2->adapter.algo = &dln2_i2c_usb_algorithm;
|
||||
dln2->adapter.quirks = &dln2_i2c_quirks;
|
||||
dln2->adapter.dev.parent = dev;
|
||||
ACPI_COMPANION_SET(&dln2->adapter.dev, ACPI_COMPANION(&pdev->dev));
|
||||
dln2->adapter.dev.of_node = dev->of_node;
|
||||
i2c_set_adapdata(&dln2->adapter, dln2);
|
||||
snprintf(dln2->adapter.name, sizeof(dln2->adapter.name), "%s-%s-%d",
|
||||
|
||||
@@ -861,14 +861,8 @@ static int exynos5_i2c_resume_noirq(struct device *dev)
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops exynos5_i2c_dev_pm_ops = {
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.suspend_noirq = exynos5_i2c_suspend_noirq,
|
||||
.resume_noirq = exynos5_i2c_resume_noirq,
|
||||
.freeze_noirq = exynos5_i2c_suspend_noirq,
|
||||
.thaw_noirq = exynos5_i2c_resume_noirq,
|
||||
.poweroff_noirq = exynos5_i2c_suspend_noirq,
|
||||
.restore_noirq = exynos5_i2c_resume_noirq,
|
||||
#endif
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos5_i2c_suspend_noirq,
|
||||
exynos5_i2c_resume_noirq)
|
||||
};
|
||||
|
||||
static struct platform_driver exynos5_i2c_driver = {
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#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
|
||||
@@ -714,9 +715,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
|
||||
{
|
||||
int hwpec;
|
||||
int block = 0;
|
||||
int ret, xact = 0;
|
||||
int ret = 0, xact = 0;
|
||||
struct i801_priv *priv = i2c_get_adapdata(adap);
|
||||
|
||||
pm_runtime_get_sync(&priv->pci_dev->dev);
|
||||
|
||||
hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
|
||||
&& size != I2C_SMBUS_QUICK
|
||||
&& size != I2C_SMBUS_I2C_BLOCK_DATA;
|
||||
@@ -773,7 +776,8 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
|
||||
default:
|
||||
dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n",
|
||||
size);
|
||||
return -EOPNOTSUPP;
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (hwpec) /* enable/disable hardware PEC */
|
||||
@@ -796,11 +800,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
|
||||
~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
|
||||
|
||||
if (block)
|
||||
return ret;
|
||||
goto out;
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
|
||||
return 0;
|
||||
goto out;
|
||||
|
||||
switch (xact & 0x7f) {
|
||||
case I801_BYTE: /* Result put in SMBHSTDAT0 */
|
||||
@@ -812,7 +816,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
|
||||
(inb_p(SMBHSTDAT1(priv)) << 8);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
|
||||
out:
|
||||
pm_runtime_mark_last_busy(&priv->pci_dev->dev);
|
||||
pm_runtime_put_autosuspend(&priv->pci_dev->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1413,6 +1421,11 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
|
||||
pci_set_drvdata(dev, priv);
|
||||
|
||||
pm_runtime_set_autosuspend_delay(&dev->dev, 1000);
|
||||
pm_runtime_use_autosuspend(&dev->dev);
|
||||
pm_runtime_put_autosuspend(&dev->dev);
|
||||
pm_runtime_allow(&dev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1420,6 +1433,9 @@ static void i801_remove(struct pci_dev *dev)
|
||||
{
|
||||
struct i801_priv *priv = pci_get_drvdata(dev);
|
||||
|
||||
pm_runtime_forbid(&dev->dev);
|
||||
pm_runtime_get_noresume(&dev->dev);
|
||||
|
||||
i801_del_mux(priv);
|
||||
i2c_del_adapter(&priv->adapter);
|
||||
pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
|
||||
@@ -1433,34 +1449,32 @@ static void i801_remove(struct pci_dev *dev)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int i801_suspend(struct pci_dev *dev, pm_message_t mesg)
|
||||
static int i801_suspend(struct device *dev)
|
||||
{
|
||||
struct i801_priv *priv = pci_get_drvdata(dev);
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
struct i801_priv *priv = pci_get_drvdata(pci_dev);
|
||||
|
||||
pci_save_state(dev);
|
||||
pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
|
||||
pci_set_power_state(dev, pci_choose_state(dev, mesg));
|
||||
pci_write_config_byte(pci_dev, SMBHSTCFG, priv->original_hstcfg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i801_resume(struct pci_dev *dev)
|
||||
static int i801_resume(struct device *dev)
|
||||
{
|
||||
pci_set_power_state(dev, PCI_D0);
|
||||
pci_restore_state(dev);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define i801_suspend NULL
|
||||
#define i801_resume NULL
|
||||
#endif
|
||||
|
||||
static UNIVERSAL_DEV_PM_OPS(i801_pm_ops, i801_suspend,
|
||||
i801_resume, NULL);
|
||||
|
||||
static struct pci_driver i801_driver = {
|
||||
.name = "i801_smbus",
|
||||
.id_table = i801_ids,
|
||||
.probe = i801_probe,
|
||||
.remove = i801_remove,
|
||||
.suspend = i801_suspend,
|
||||
.resume = i801_resume,
|
||||
.driver = {
|
||||
.pm = &i801_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init i2c_i801_init(void)
|
||||
|
||||
@@ -269,7 +269,7 @@ static int iic_smbus_quick(struct ibm_iic_private* dev, const struct i2c_msg* p)
|
||||
ndelay(t->hd_sta);
|
||||
|
||||
/* Send address */
|
||||
v = (u8)((p->addr << 1) | ((p->flags & I2C_M_RD) ? 1 : 0));
|
||||
v = i2c_8bit_addr_from_msg(p);
|
||||
for (i = 0, mask = 0x80; i < 8; ++i, mask >>= 1){
|
||||
out_8(&iic->directcntl, sda);
|
||||
ndelay(t->low / 2);
|
||||
|
||||
@@ -751,9 +751,7 @@ static unsigned int img_i2c_atomic(struct img_i2c *i2c,
|
||||
switch (i2c->at_cur_cmd) {
|
||||
case CMD_GEN_START:
|
||||
next_cmd = CMD_GEN_DATA;
|
||||
next_data = (i2c->msg.addr << 1);
|
||||
if (i2c->msg.flags & I2C_M_RD)
|
||||
next_data |= 0x1;
|
||||
next_data = i2c_8bit_addr_from_msg(&i2c->msg);
|
||||
break;
|
||||
case CMD_GEN_DATA:
|
||||
if (i2c->line_status & LINESTAT_INPUT_HELD_V)
|
||||
|
||||
@@ -525,7 +525,7 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
|
||||
imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx, IMX_I2C_I2CR);
|
||||
|
||||
/* Wait controller to be stable */
|
||||
udelay(50);
|
||||
usleep_range(50, 150);
|
||||
|
||||
/* Start I2C transaction */
|
||||
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
|
||||
|
||||
@@ -50,10 +50,7 @@ iic_cook_addr(struct i2c_msg *msg)
|
||||
{
|
||||
unsigned char addr;
|
||||
|
||||
addr = (msg->addr << 1);
|
||||
|
||||
if (msg->flags & I2C_M_RD)
|
||||
addr |= 1;
|
||||
addr = i2c_8bit_addr_from_msg(msg);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
@@ -133,9 +133,7 @@ static void i2c_lpc2k_pump_msg(struct lpc2k_i2c *i2c)
|
||||
case M_START:
|
||||
case M_REPSTART:
|
||||
/* Start bit was just sent out, send out addr and dir */
|
||||
data = i2c->msg->addr << 1;
|
||||
if (i2c->msg->flags & I2C_M_RD)
|
||||
data |= 1;
|
||||
data = i2c_8bit_addr_from_msg(i2c->msg);
|
||||
|
||||
writel(data, i2c->base + LPC24XX_I2DAT);
|
||||
writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONCLR);
|
||||
|
||||
@@ -413,10 +413,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
|
||||
else
|
||||
writew(I2C_FS_START_CON, i2c->base + OFFSET_EXT_CONF);
|
||||
|
||||
addr_reg = msgs->addr << 1;
|
||||
if (i2c->op == I2C_MASTER_RD)
|
||||
addr_reg |= 0x1;
|
||||
|
||||
addr_reg = i2c_8bit_addr_from_msg(msgs);
|
||||
writew(addr_reg, i2c->base + OFFSET_SLAVE_ADDR);
|
||||
|
||||
/* Clear interrupt status */
|
||||
|
||||
@@ -134,9 +134,7 @@ struct mv64xxx_i2c_data {
|
||||
int rc;
|
||||
u32 freq_m;
|
||||
u32 freq_n;
|
||||
#if defined(CONFIG_HAVE_CLK)
|
||||
struct clk *clk;
|
||||
#endif
|
||||
wait_queue_head_t waitq;
|
||||
spinlock_t lock;
|
||||
struct i2c_msg *msg;
|
||||
@@ -757,7 +755,6 @@ static const struct of_device_id mv64xxx_i2c_of_match_table[] = {
|
||||
MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
#ifdef CONFIG_HAVE_CLK
|
||||
static int
|
||||
mv64xxx_calc_freq(struct mv64xxx_i2c_data *drv_data,
|
||||
const int tclk, const int n, const int m)
|
||||
@@ -791,25 +788,20 @@ mv64xxx_find_baud_factors(struct mv64xxx_i2c_data *drv_data,
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_HAVE_CLK */
|
||||
|
||||
static int
|
||||
mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
|
||||
struct device *dev)
|
||||
{
|
||||
/* CLK is mandatory when using DT to describe the i2c bus. We
|
||||
* need to know tclk in order to calculate bus clock
|
||||
* factors.
|
||||
*/
|
||||
#if !defined(CONFIG_HAVE_CLK)
|
||||
/* Have OF but no CLK */
|
||||
return -ENODEV;
|
||||
#else
|
||||
const struct of_device_id *device;
|
||||
struct device_node *np = dev->of_node;
|
||||
u32 bus_freq, tclk;
|
||||
int rc = 0;
|
||||
|
||||
/* CLK is mandatory when using DT to describe the i2c bus. We
|
||||
* need to know tclk in order to calculate bus clock
|
||||
* factors.
|
||||
*/
|
||||
if (IS_ERR(drv_data->clk)) {
|
||||
rc = -ENODEV;
|
||||
goto out;
|
||||
@@ -869,7 +861,6 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
|
||||
|
||||
out:
|
||||
return rc;
|
||||
#endif
|
||||
}
|
||||
#else /* CONFIG_OF */
|
||||
static int
|
||||
@@ -907,14 +898,13 @@ mv64xxx_i2c_probe(struct platform_device *pd)
|
||||
init_waitqueue_head(&drv_data->waitq);
|
||||
spin_lock_init(&drv_data->lock);
|
||||
|
||||
#if defined(CONFIG_HAVE_CLK)
|
||||
/* Not all platforms have a clk */
|
||||
drv_data->clk = devm_clk_get(&pd->dev, NULL);
|
||||
if (!IS_ERR(drv_data->clk)) {
|
||||
clk_prepare(drv_data->clk);
|
||||
clk_enable(drv_data->clk);
|
||||
}
|
||||
#endif
|
||||
if (IS_ERR(drv_data->clk) && PTR_ERR(drv_data->clk) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
if (!IS_ERR(drv_data->clk))
|
||||
clk_prepare_enable(drv_data->clk);
|
||||
|
||||
if (pdata) {
|
||||
drv_data->freq_m = pdata->freq_m;
|
||||
drv_data->freq_n = pdata->freq_n;
|
||||
@@ -964,13 +954,10 @@ exit_reset:
|
||||
if (!IS_ERR_OR_NULL(drv_data->rstc))
|
||||
reset_control_assert(drv_data->rstc);
|
||||
exit_clk:
|
||||
#if defined(CONFIG_HAVE_CLK)
|
||||
/* Not all platforms have a clk */
|
||||
if (!IS_ERR(drv_data->clk)) {
|
||||
clk_disable(drv_data->clk);
|
||||
clk_unprepare(drv_data->clk);
|
||||
}
|
||||
#endif
|
||||
if (!IS_ERR(drv_data->clk))
|
||||
clk_disable_unprepare(drv_data->clk);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -983,13 +970,9 @@ mv64xxx_i2c_remove(struct platform_device *dev)
|
||||
free_irq(drv_data->irq, drv_data);
|
||||
if (!IS_ERR_OR_NULL(drv_data->rstc))
|
||||
reset_control_assert(drv_data->rstc);
|
||||
#if defined(CONFIG_HAVE_CLK)
|
||||
/* Not all platforms have a clk */
|
||||
if (!IS_ERR(drv_data->clk)) {
|
||||
clk_disable(drv_data->clk);
|
||||
clk_unprepare(drv_data->clk);
|
||||
}
|
||||
#endif
|
||||
if (!IS_ERR(drv_data->clk))
|
||||
clk_disable_unprepare(drv_data->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ static struct pci_driver nforce2_driver;
|
||||
|
||||
/* For multiplexing support, we need a global reference to the 1st
|
||||
SMBus channel */
|
||||
#if defined CONFIG_I2C_NFORCE2_S4985 || defined CONFIG_I2C_NFORCE2_S4985_MODULE
|
||||
#if IS_ENABLED(CONFIG_I2C_NFORCE2_S4985)
|
||||
struct i2c_adapter *nforce2_smbus;
|
||||
EXPORT_SYMBOL_GPL(nforce2_smbus);
|
||||
|
||||
|
||||
@@ -178,10 +178,7 @@ static void ocores_process(struct ocores_i2c *i2c)
|
||||
if (i2c->nmsgs) { /* end? */
|
||||
/* send start? */
|
||||
if (!(msg->flags & I2C_M_NOSTART)) {
|
||||
u8 addr = (msg->addr << 1);
|
||||
|
||||
if (msg->flags & I2C_M_RD)
|
||||
addr |= 1;
|
||||
u8 addr = i2c_8bit_addr_from_msg(msg);
|
||||
|
||||
i2c->state = STATE_START;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -185,7 +185,6 @@ enum {
|
||||
#define OMAP_I2C_IP_V2_INTERRUPTS_MASK 0x6FFF
|
||||
|
||||
struct omap_i2c_dev {
|
||||
spinlock_t lock; /* IRQ synchronization */
|
||||
struct device *dev;
|
||||
void __iomem *base; /* virtual */
|
||||
int irq;
|
||||
@@ -995,15 +994,12 @@ omap_i2c_isr(int irq, void *dev_id)
|
||||
u16 mask;
|
||||
u16 stat;
|
||||
|
||||
spin_lock(&omap->lock);
|
||||
mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
|
||||
stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
|
||||
mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
|
||||
|
||||
if (stat & mask)
|
||||
ret = IRQ_WAKE_THREAD;
|
||||
|
||||
spin_unlock(&omap->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1011,12 +1007,10 @@ static irqreturn_t
|
||||
omap_i2c_isr_thread(int this_irq, void *dev_id)
|
||||
{
|
||||
struct omap_i2c_dev *omap = dev_id;
|
||||
unsigned long flags;
|
||||
u16 bits;
|
||||
u16 stat;
|
||||
int err = 0, count = 0;
|
||||
|
||||
spin_lock_irqsave(&omap->lock, flags);
|
||||
do {
|
||||
bits = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
|
||||
stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
|
||||
@@ -1142,8 +1136,6 @@ omap_i2c_isr_thread(int this_irq, void *dev_id)
|
||||
omap_i2c_complete_cmd(omap, err);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&omap->lock, flags);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -1330,8 +1322,6 @@ omap_i2c_probe(struct platform_device *pdev)
|
||||
omap->dev = &pdev->dev;
|
||||
omap->irq = irq;
|
||||
|
||||
spin_lock_init(&omap->lock);
|
||||
|
||||
platform_set_drvdata(pdev, omap);
|
||||
init_completion(&omap->cmd_complete);
|
||||
|
||||
|
||||
@@ -150,13 +150,11 @@ static int i2c_powermac_master_xfer( struct i2c_adapter *adap,
|
||||
{
|
||||
struct pmac_i2c_bus *bus = i2c_get_adapdata(adap);
|
||||
int rc = 0;
|
||||
int read;
|
||||
int addrdir;
|
||||
|
||||
if (msgs->flags & I2C_M_TEN)
|
||||
return -EINVAL;
|
||||
read = (msgs->flags & I2C_M_RD) != 0;
|
||||
addrdir = (msgs->addr << 1) | read;
|
||||
addrdir = i2c_8bit_addr_from_msg(msgs);
|
||||
|
||||
rc = pmac_i2c_open(bus, 0);
|
||||
if (rc) {
|
||||
|
||||
@@ -515,7 +515,7 @@ static int qup_i2c_get_data_len(struct qup_i2c_dev *qup)
|
||||
static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
|
||||
struct i2c_msg *msg, int is_dma)
|
||||
{
|
||||
u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD);
|
||||
u16 addr = i2c_8bit_addr_from_msg(msg);
|
||||
int len = 0;
|
||||
int data_len;
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
@@ -43,6 +45,8 @@
|
||||
#define ICSAR 0x1C /* slave address */
|
||||
#define ICMAR 0x20 /* master address */
|
||||
#define ICRXTX 0x24 /* data port */
|
||||
#define ICDMAER 0x3c /* DMA enable */
|
||||
#define ICFBSCR 0x38 /* first bit setup cycle */
|
||||
|
||||
/* ICSCR */
|
||||
#define SDBS (1 << 3) /* slave data buffer select */
|
||||
@@ -78,6 +82,16 @@
|
||||
#define MDR (1 << 1)
|
||||
#define MAT (1 << 0) /* slave addr xfer done */
|
||||
|
||||
/* ICDMAER */
|
||||
#define RSDMAE (1 << 3) /* DMA Slave Received Enable */
|
||||
#define TSDMAE (1 << 2) /* DMA Slave Transmitted Enable */
|
||||
#define RMDMAE (1 << 1) /* DMA Master Received Enable */
|
||||
#define TMDMAE (1 << 0) /* DMA Master Transmitted Enable */
|
||||
|
||||
/* ICFBSCR */
|
||||
#define TCYC06 0x04 /* 6*Tcyc delay 1st bit between SDA and SCL */
|
||||
#define TCYC17 0x0f /* 17*Tcyc delay 1st bit between SDA and SCL */
|
||||
|
||||
|
||||
#define RCAR_BUS_PHASE_START (MDBS | MIE | ESG)
|
||||
#define RCAR_BUS_PHASE_DATA (MDBS | MIE)
|
||||
@@ -120,6 +134,12 @@ struct rcar_i2c_priv {
|
||||
u32 flags;
|
||||
enum rcar_i2c_type devtype;
|
||||
struct i2c_client *slave;
|
||||
|
||||
struct resource *res;
|
||||
struct dma_chan *dma_tx;
|
||||
struct dma_chan *dma_rx;
|
||||
struct scatterlist sg;
|
||||
enum dma_data_direction dma_direction;
|
||||
};
|
||||
|
||||
#define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent)
|
||||
@@ -287,6 +307,118 @@ static void rcar_i2c_next_msg(struct rcar_i2c_priv *priv)
|
||||
/*
|
||||
* interrupt functions
|
||||
*/
|
||||
static void rcar_i2c_dma_unmap(struct rcar_i2c_priv *priv)
|
||||
{
|
||||
struct dma_chan *chan = priv->dma_direction == DMA_FROM_DEVICE
|
||||
? priv->dma_rx : priv->dma_tx;
|
||||
|
||||
/* Disable DMA Master Received/Transmitted */
|
||||
rcar_i2c_write(priv, ICDMAER, 0);
|
||||
|
||||
/* Reset default delay */
|
||||
rcar_i2c_write(priv, ICFBSCR, TCYC06);
|
||||
|
||||
dma_unmap_single(chan->device->dev, sg_dma_address(&priv->sg),
|
||||
priv->msg->len, priv->dma_direction);
|
||||
|
||||
priv->dma_direction = DMA_NONE;
|
||||
}
|
||||
|
||||
static void rcar_i2c_cleanup_dma(struct rcar_i2c_priv *priv)
|
||||
{
|
||||
if (priv->dma_direction == DMA_NONE)
|
||||
return;
|
||||
else if (priv->dma_direction == DMA_FROM_DEVICE)
|
||||
dmaengine_terminate_all(priv->dma_rx);
|
||||
else if (priv->dma_direction == DMA_TO_DEVICE)
|
||||
dmaengine_terminate_all(priv->dma_tx);
|
||||
|
||||
rcar_i2c_dma_unmap(priv);
|
||||
}
|
||||
|
||||
static void rcar_i2c_dma_callback(void *data)
|
||||
{
|
||||
struct rcar_i2c_priv *priv = data;
|
||||
|
||||
priv->pos += sg_dma_len(&priv->sg);
|
||||
|
||||
rcar_i2c_dma_unmap(priv);
|
||||
}
|
||||
|
||||
static void rcar_i2c_dma(struct rcar_i2c_priv *priv)
|
||||
{
|
||||
struct device *dev = rcar_i2c_priv_to_dev(priv);
|
||||
struct i2c_msg *msg = priv->msg;
|
||||
bool read = msg->flags & I2C_M_RD;
|
||||
enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
|
||||
struct dma_chan *chan = read ? priv->dma_rx : priv->dma_tx;
|
||||
struct dma_async_tx_descriptor *txdesc;
|
||||
dma_addr_t dma_addr;
|
||||
dma_cookie_t cookie;
|
||||
unsigned char *buf;
|
||||
int len;
|
||||
|
||||
/* Do not use DMA if it's not available or for messages < 8 bytes */
|
||||
if (IS_ERR(chan) || msg->len < 8)
|
||||
return;
|
||||
|
||||
if (read) {
|
||||
/*
|
||||
* The last two bytes needs to be fetched using PIO in
|
||||
* order for the STOP phase to work.
|
||||
*/
|
||||
buf = priv->msg->buf;
|
||||
len = priv->msg->len - 2;
|
||||
} else {
|
||||
/*
|
||||
* First byte in message was sent using PIO.
|
||||
*/
|
||||
buf = priv->msg->buf + 1;
|
||||
len = priv->msg->len - 1;
|
||||
}
|
||||
|
||||
dma_addr = dma_map_single(chan->device->dev, buf, len, dir);
|
||||
if (dma_mapping_error(dev, dma_addr)) {
|
||||
dev_dbg(dev, "dma map failed, using PIO\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sg_dma_len(&priv->sg) = len;
|
||||
sg_dma_address(&priv->sg) = dma_addr;
|
||||
|
||||
priv->dma_direction = dir;
|
||||
|
||||
txdesc = dmaengine_prep_slave_sg(chan, &priv->sg, 1,
|
||||
read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!txdesc) {
|
||||
dev_dbg(dev, "dma prep slave sg failed, using PIO\n");
|
||||
rcar_i2c_cleanup_dma(priv);
|
||||
return;
|
||||
}
|
||||
|
||||
txdesc->callback = rcar_i2c_dma_callback;
|
||||
txdesc->callback_param = priv;
|
||||
|
||||
cookie = dmaengine_submit(txdesc);
|
||||
if (dma_submit_error(cookie)) {
|
||||
dev_dbg(dev, "submitting dma failed, using PIO\n");
|
||||
rcar_i2c_cleanup_dma(priv);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set delay for DMA operations */
|
||||
rcar_i2c_write(priv, ICFBSCR, TCYC17);
|
||||
|
||||
/* Enable DMA Master Received/Transmitted */
|
||||
if (read)
|
||||
rcar_i2c_write(priv, ICDMAER, RMDMAE);
|
||||
else
|
||||
rcar_i2c_write(priv, ICDMAER, TMDMAE);
|
||||
|
||||
dma_async_issue_pending(chan);
|
||||
}
|
||||
|
||||
static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
|
||||
{
|
||||
struct i2c_msg *msg = priv->msg;
|
||||
@@ -306,6 +438,12 @@ static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
|
||||
rcar_i2c_write(priv, ICRXTX, msg->buf[priv->pos]);
|
||||
priv->pos++;
|
||||
|
||||
/*
|
||||
* Try to use DMA to transmit the rest of the data if
|
||||
* address transfer pashe just finished.
|
||||
*/
|
||||
if (msr & MAT)
|
||||
rcar_i2c_dma(priv);
|
||||
} else {
|
||||
/*
|
||||
* The last data was pushed to ICRXTX on _PREV_ empty irq.
|
||||
@@ -340,7 +478,11 @@ static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
|
||||
return;
|
||||
|
||||
if (msr & MAT) {
|
||||
/* Address transfer phase finished, but no data at this point. */
|
||||
/*
|
||||
* Address transfer phase finished, but no data at this point.
|
||||
* Try to use DMA to receive data.
|
||||
*/
|
||||
rcar_i2c_dma(priv);
|
||||
} else if (priv->pos < msg->len) {
|
||||
/* get received data */
|
||||
msg->buf[priv->pos] = rcar_i2c_read(priv, ICRXTX);
|
||||
@@ -472,6 +614,81 @@ out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct dma_chan *rcar_i2c_request_dma_chan(struct device *dev,
|
||||
enum dma_transfer_direction dir,
|
||||
dma_addr_t port_addr)
|
||||
{
|
||||
struct dma_chan *chan;
|
||||
struct dma_slave_config cfg;
|
||||
char *chan_name = dir == DMA_MEM_TO_DEV ? "tx" : "rx";
|
||||
int ret;
|
||||
|
||||
chan = dma_request_slave_channel_reason(dev, chan_name);
|
||||
if (IS_ERR(chan)) {
|
||||
ret = PTR_ERR(chan);
|
||||
dev_dbg(dev, "request_channel failed for %s (%d)\n",
|
||||
chan_name, ret);
|
||||
return chan;
|
||||
}
|
||||
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
cfg.direction = dir;
|
||||
if (dir == DMA_MEM_TO_DEV) {
|
||||
cfg.dst_addr = port_addr;
|
||||
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
} else {
|
||||
cfg.src_addr = port_addr;
|
||||
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
}
|
||||
|
||||
ret = dmaengine_slave_config(chan, &cfg);
|
||||
if (ret) {
|
||||
dev_dbg(dev, "slave_config failed for %s (%d)\n",
|
||||
chan_name, ret);
|
||||
dma_release_channel(chan);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
dev_dbg(dev, "got DMA channel for %s\n", chan_name);
|
||||
return chan;
|
||||
}
|
||||
|
||||
static void rcar_i2c_request_dma(struct rcar_i2c_priv *priv,
|
||||
struct i2c_msg *msg)
|
||||
{
|
||||
struct device *dev = rcar_i2c_priv_to_dev(priv);
|
||||
bool read;
|
||||
struct dma_chan *chan;
|
||||
enum dma_transfer_direction dir;
|
||||
|
||||
read = msg->flags & I2C_M_RD;
|
||||
|
||||
chan = read ? priv->dma_rx : priv->dma_tx;
|
||||
if (PTR_ERR(chan) != -EPROBE_DEFER)
|
||||
return;
|
||||
|
||||
dir = read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
|
||||
chan = rcar_i2c_request_dma_chan(dev, dir, priv->res->start + ICRXTX);
|
||||
|
||||
if (read)
|
||||
priv->dma_rx = chan;
|
||||
else
|
||||
priv->dma_tx = chan;
|
||||
}
|
||||
|
||||
static void rcar_i2c_release_dma(struct rcar_i2c_priv *priv)
|
||||
{
|
||||
if (!IS_ERR(priv->dma_tx)) {
|
||||
dma_release_channel(priv->dma_tx);
|
||||
priv->dma_tx = ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
|
||||
if (!IS_ERR(priv->dma_rx)) {
|
||||
dma_release_channel(priv->dma_rx);
|
||||
priv->dma_rx = ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
}
|
||||
|
||||
static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msgs,
|
||||
int num)
|
||||
@@ -493,6 +710,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
rcar_i2c_request_dma(priv, msgs + i);
|
||||
}
|
||||
|
||||
/* init first message */
|
||||
@@ -504,6 +722,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
|
||||
time_left = wait_event_timeout(priv->wait, priv->flags & ID_DONE,
|
||||
num * adap->timeout);
|
||||
if (!time_left) {
|
||||
rcar_i2c_cleanup_dma(priv);
|
||||
rcar_i2c_init(priv);
|
||||
ret = -ETIMEDOUT;
|
||||
} else if (priv->flags & ID_NACK) {
|
||||
@@ -591,7 +810,6 @@ static int rcar_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rcar_i2c_priv *priv;
|
||||
struct i2c_adapter *adap;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct i2c_timings i2c_t;
|
||||
int irq, ret;
|
||||
@@ -606,8 +824,9 @@ static int rcar_i2c_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(priv->clk);
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->io = devm_ioremap_resource(dev, res);
|
||||
priv->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
priv->io = devm_ioremap_resource(dev, priv->res);
|
||||
if (IS_ERR(priv->io))
|
||||
return PTR_ERR(priv->io);
|
||||
|
||||
@@ -626,6 +845,11 @@ static int rcar_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
i2c_parse_fw_timings(dev, &i2c_t, false);
|
||||
|
||||
/* Init DMA */
|
||||
sg_init_table(&priv->sg, 1);
|
||||
priv->dma_direction = DMA_NONE;
|
||||
priv->dma_rx = priv->dma_tx = ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_get_sync(dev);
|
||||
ret = rcar_i2c_clock_calculate(priv, &i2c_t);
|
||||
@@ -673,6 +897,7 @@ static int rcar_i2c_remove(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
i2c_del_adapter(&priv->adap);
|
||||
rcar_i2c_release_dma(priv);
|
||||
if (priv->flags & ID_P_PM_BLOCKED)
|
||||
pm_runtime_put(dev);
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
@@ -101,10 +101,7 @@ struct rk3x_i2c {
|
||||
struct notifier_block clk_rate_nb;
|
||||
|
||||
/* Settings */
|
||||
unsigned int scl_frequency;
|
||||
unsigned int scl_rise_ns;
|
||||
unsigned int scl_fall_ns;
|
||||
unsigned int sda_fall_ns;
|
||||
struct i2c_timings t;
|
||||
|
||||
/* Synchronization & notification */
|
||||
spinlock_t lock;
|
||||
@@ -437,10 +434,7 @@ out:
|
||||
* Calculate divider values for desired SCL frequency
|
||||
*
|
||||
* @clk_rate: I2C input clock rate
|
||||
* @scl_rate: Desired SCL rate
|
||||
* @scl_rise_ns: How many ns it takes for SCL to rise.
|
||||
* @scl_fall_ns: How many ns it takes for SCL to fall.
|
||||
* @sda_fall_ns: How many ns it takes for SDA to fall.
|
||||
* @t: Known I2C timing information.
|
||||
* @div_low: Divider output for low
|
||||
* @div_high: Divider output for high
|
||||
*
|
||||
@@ -448,11 +442,10 @@ out:
|
||||
* 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, unsigned long scl_rate,
|
||||
unsigned long scl_rise_ns,
|
||||
unsigned long scl_fall_ns,
|
||||
unsigned long sda_fall_ns,
|
||||
unsigned long *div_low, unsigned long *div_high)
|
||||
static int rk3x_i2c_calc_divs(unsigned long clk_rate,
|
||||
struct i2c_timings *t,
|
||||
unsigned long *div_low,
|
||||
unsigned long *div_high)
|
||||
{
|
||||
unsigned long spec_min_low_ns, spec_min_high_ns;
|
||||
unsigned long spec_setup_start, spec_max_data_hold_ns;
|
||||
@@ -472,12 +465,12 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
|
||||
int ret = 0;
|
||||
|
||||
/* Only support standard-mode and fast-mode */
|
||||
if (WARN_ON(scl_rate > 400000))
|
||||
scl_rate = 400000;
|
||||
if (WARN_ON(t->bus_freq_hz > 400000))
|
||||
t->bus_freq_hz = 400000;
|
||||
|
||||
/* prevent scl_rate_khz from becoming 0 */
|
||||
if (WARN_ON(scl_rate < 1000))
|
||||
scl_rate = 1000;
|
||||
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
|
||||
@@ -491,7 +484,7 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
|
||||
* This is because the i2c host on Rockchip holds the data line
|
||||
* for half the low time.
|
||||
*/
|
||||
if (scl_rate <= 100000) {
|
||||
if (t->bus_freq_hz <= 100000) {
|
||||
/* Standard-mode */
|
||||
spec_min_low_ns = 4700;
|
||||
spec_setup_start = 4700;
|
||||
@@ -506,7 +499,7 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
|
||||
spec_max_data_hold_ns = 900;
|
||||
data_hold_buffer_ns = 50;
|
||||
}
|
||||
min_high_ns = scl_rise_ns + spec_min_high_ns;
|
||||
min_high_ns = t->scl_rise_ns + spec_min_high_ns;
|
||||
|
||||
/*
|
||||
* Timings for repeated start:
|
||||
@@ -517,18 +510,18 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
|
||||
* we meet tSU;STA and tHD;STA times.
|
||||
*/
|
||||
min_high_ns = max(min_high_ns,
|
||||
DIV_ROUND_UP((scl_rise_ns + spec_setup_start) * 1000, 875));
|
||||
DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start) * 1000, 875));
|
||||
min_high_ns = max(min_high_ns,
|
||||
DIV_ROUND_UP((scl_rise_ns + spec_setup_start +
|
||||
sda_fall_ns + spec_min_high_ns), 2));
|
||||
DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start +
|
||||
t->sda_fall_ns + spec_min_high_ns), 2));
|
||||
|
||||
min_low_ns = scl_fall_ns + spec_min_low_ns;
|
||||
min_low_ns = t->scl_fall_ns + spec_min_low_ns;
|
||||
max_low_ns = spec_max_data_hold_ns * 2 - data_hold_buffer_ns;
|
||||
min_total_ns = min_low_ns + min_high_ns;
|
||||
|
||||
/* Adjust to avoid overflow */
|
||||
clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000);
|
||||
scl_rate_khz = scl_rate / 1000;
|
||||
scl_rate_khz = t->bus_freq_hz / 1000;
|
||||
|
||||
/*
|
||||
* We need the total div to be >= this number
|
||||
@@ -616,14 +609,13 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_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;
|
||||
u64 t_low_ns, t_high_ns;
|
||||
int ret;
|
||||
|
||||
ret = rk3x_i2c_calc_divs(clk_rate, i2c->scl_frequency, i2c->scl_rise_ns,
|
||||
i2c->scl_fall_ns, i2c->sda_fall_ns,
|
||||
&div_low, &div_high);
|
||||
WARN_ONCE(ret != 0, "Could not reach SCL freq %u", i2c->scl_frequency);
|
||||
ret = rk3x_i2c_calc_divs(clk_rate, t, &div_low, &div_high);
|
||||
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);
|
||||
@@ -634,7 +626,7 @@ static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
|
||||
dev_dbg(i2c->dev,
|
||||
"CLK %lukhz, Req %uns, Act low %lluns high %lluns\n",
|
||||
clk_rate / 1000,
|
||||
1000000000 / i2c->scl_frequency,
|
||||
1000000000 / t->bus_freq_hz,
|
||||
t_low_ns, t_high_ns);
|
||||
}
|
||||
|
||||
@@ -664,9 +656,7 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
|
||||
|
||||
switch (event) {
|
||||
case PRE_RATE_CHANGE:
|
||||
if (rk3x_i2c_calc_divs(ndata->new_rate, i2c->scl_frequency,
|
||||
i2c->scl_rise_ns, i2c->scl_fall_ns,
|
||||
i2c->sda_fall_ns,
|
||||
if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t,
|
||||
&div_low, &div_high) != 0)
|
||||
return NOTIFY_STOP;
|
||||
|
||||
@@ -880,37 +870,8 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
|
||||
match = of_match_node(rk3x_i2c_match, np);
|
||||
i2c->soc_data = (struct rk3x_i2c_soc_data *)match->data;
|
||||
|
||||
if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
|
||||
&i2c->scl_frequency)) {
|
||||
dev_info(&pdev->dev, "using default SCL frequency: %d\n",
|
||||
DEFAULT_SCL_RATE);
|
||||
i2c->scl_frequency = DEFAULT_SCL_RATE;
|
||||
}
|
||||
|
||||
if (i2c->scl_frequency == 0 || i2c->scl_frequency > 400 * 1000) {
|
||||
dev_warn(&pdev->dev, "invalid SCL frequency specified.\n");
|
||||
dev_warn(&pdev->dev, "using default SCL frequency: %d\n",
|
||||
DEFAULT_SCL_RATE);
|
||||
i2c->scl_frequency = DEFAULT_SCL_RATE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read rise and fall time from device tree. If not available use
|
||||
* the default maximum timing from the specification.
|
||||
*/
|
||||
if (of_property_read_u32(pdev->dev.of_node, "i2c-scl-rising-time-ns",
|
||||
&i2c->scl_rise_ns)) {
|
||||
if (i2c->scl_frequency <= 100000)
|
||||
i2c->scl_rise_ns = 1000;
|
||||
else
|
||||
i2c->scl_rise_ns = 300;
|
||||
}
|
||||
if (of_property_read_u32(pdev->dev.of_node, "i2c-scl-falling-time-ns",
|
||||
&i2c->scl_fall_ns))
|
||||
i2c->scl_fall_ns = 300;
|
||||
if (of_property_read_u32(pdev->dev.of_node, "i2c-sda-falling-time-ns",
|
||||
&i2c->sda_fall_ns))
|
||||
i2c->sda_fall_ns = i2c->scl_fall_ns;
|
||||
/* use common interface to get I2C timing properties */
|
||||
i2c_parse_fw_timings(&pdev->dev, &i2c->t, true);
|
||||
|
||||
strlcpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name));
|
||||
i2c->adap.owner = THIS_MODULE;
|
||||
|
||||
@@ -163,15 +163,14 @@ static const struct of_device_id s3c24xx_i2c_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, s3c24xx_i2c_match);
|
||||
#endif
|
||||
|
||||
/* s3c24xx_get_device_quirks
|
||||
*
|
||||
/*
|
||||
* Get controller type either from device tree or platform device variant.
|
||||
*/
|
||||
|
||||
*/
|
||||
static inline kernel_ulong_t s3c24xx_get_device_quirks(struct platform_device *pdev)
|
||||
{
|
||||
if (pdev->dev.of_node) {
|
||||
const struct of_device_id *match;
|
||||
|
||||
match = of_match_node(s3c24xx_i2c_match, pdev->dev.of_node);
|
||||
return (kernel_ulong_t)match->data;
|
||||
}
|
||||
@@ -179,12 +178,10 @@ static inline kernel_ulong_t s3c24xx_get_device_quirks(struct platform_device *p
|
||||
return platform_get_device_id(pdev)->driver_data;
|
||||
}
|
||||
|
||||
/* s3c24xx_i2c_master_complete
|
||||
*
|
||||
* complete the message and wake up the caller, using the given return code,
|
||||
/*
|
||||
* Complete the message and wake up the caller, using the given return code,
|
||||
* or zero to mean ok.
|
||||
*/
|
||||
|
||||
*/
|
||||
static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret)
|
||||
{
|
||||
dev_dbg(i2c->dev, "master_complete %d\n", ret);
|
||||
@@ -217,7 +214,6 @@ static inline void s3c24xx_i2c_enable_ack(struct s3c24xx_i2c *i2c)
|
||||
}
|
||||
|
||||
/* irq enable/disable functions */
|
||||
|
||||
static inline void s3c24xx_i2c_disable_irq(struct s3c24xx_i2c *i2c)
|
||||
{
|
||||
unsigned long tmp;
|
||||
@@ -251,11 +247,9 @@ static bool is_ack(struct s3c24xx_i2c *i2c)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* s3c24xx_i2c_message_start
|
||||
*
|
||||
/*
|
||||
* put the start of a message onto the bus
|
||||
*/
|
||||
|
||||
*/
|
||||
static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
|
||||
struct i2c_msg *msg)
|
||||
{
|
||||
@@ -284,9 +278,10 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
|
||||
dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);
|
||||
writeb(addr, i2c->regs + S3C2410_IICDS);
|
||||
|
||||
/* delay here to ensure the data byte has gotten onto the bus
|
||||
* before the transaction is started */
|
||||
|
||||
/*
|
||||
* delay here to ensure the data byte has gotten onto the bus
|
||||
* before the transaction is started
|
||||
*/
|
||||
ndelay(i2c->tx_setup);
|
||||
|
||||
dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon);
|
||||
@@ -361,50 +356,46 @@ static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
|
||||
s3c24xx_i2c_disable_irq(i2c);
|
||||
}
|
||||
|
||||
/* helper functions to determine the current state in the set of
|
||||
* messages we are sending */
|
||||
/*
|
||||
* helper functions to determine the current state in the set of
|
||||
* messages we are sending
|
||||
*/
|
||||
|
||||
/* is_lastmsg()
|
||||
*
|
||||
/*
|
||||
* returns TRUE if the current message is the last in the set
|
||||
*/
|
||||
|
||||
*/
|
||||
static inline int is_lastmsg(struct s3c24xx_i2c *i2c)
|
||||
{
|
||||
return i2c->msg_idx >= (i2c->msg_num - 1);
|
||||
}
|
||||
|
||||
/* is_msglast
|
||||
*
|
||||
/*
|
||||
* returns TRUE if we this is the last byte in the current message
|
||||
*/
|
||||
|
||||
*/
|
||||
static inline int is_msglast(struct s3c24xx_i2c *i2c)
|
||||
{
|
||||
/* msg->len is always 1 for the first byte of smbus block read.
|
||||
/*
|
||||
* msg->len is always 1 for the first byte of smbus block read.
|
||||
* Actual length will be read from slave. More bytes will be
|
||||
* read according to the length then. */
|
||||
* read according to the length then.
|
||||
*/
|
||||
if (i2c->msg->flags & I2C_M_RECV_LEN && i2c->msg->len == 1)
|
||||
return 0;
|
||||
|
||||
return i2c->msg_ptr == i2c->msg->len-1;
|
||||
}
|
||||
|
||||
/* is_msgend
|
||||
*
|
||||
/*
|
||||
* returns TRUE if we reached the end of the current message
|
||||
*/
|
||||
|
||||
*/
|
||||
static inline int is_msgend(struct s3c24xx_i2c *i2c)
|
||||
{
|
||||
return i2c->msg_ptr >= i2c->msg->len;
|
||||
}
|
||||
|
||||
/* i2c_s3c_irq_nextbyte
|
||||
*
|
||||
/*
|
||||
* process an interrupt and work out what to do
|
||||
*/
|
||||
|
||||
static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
|
||||
{
|
||||
unsigned long tmp;
|
||||
@@ -423,14 +414,13 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
|
||||
goto out_ack;
|
||||
|
||||
case STATE_START:
|
||||
/* last thing we did was send a start condition on the
|
||||
/*
|
||||
* last thing we did was send a start condition on the
|
||||
* bus, or started a new i2c message
|
||||
*/
|
||||
|
||||
if (iicstat & S3C2410_IICSTAT_LASTBIT &&
|
||||
!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
|
||||
/* ack was not received... */
|
||||
|
||||
dev_dbg(i2c->dev, "ack was not received\n");
|
||||
s3c24xx_i2c_stop(i2c, -ENXIO);
|
||||
goto out_ack;
|
||||
@@ -441,9 +431,10 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
|
||||
else
|
||||
i2c->state = STATE_WRITE;
|
||||
|
||||
/* terminate the transfer if there is nothing to do
|
||||
* as this is used by the i2c probe to find devices. */
|
||||
|
||||
/*
|
||||
* Terminate the transfer if there is nothing to do
|
||||
* as this is used by the i2c probe to find devices.
|
||||
*/
|
||||
if (is_lastmsg(i2c) && i2c->msg->len == 0) {
|
||||
s3c24xx_i2c_stop(i2c, 0);
|
||||
goto out_ack;
|
||||
@@ -452,14 +443,16 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
|
||||
if (i2c->state == STATE_READ)
|
||||
goto prepare_read;
|
||||
|
||||
/* fall through to the write state, as we will need to
|
||||
* send a byte as well */
|
||||
|
||||
case STATE_WRITE:
|
||||
/* we are writing data to the device... check for the
|
||||
* end of the message, and if so, work out what to do
|
||||
/*
|
||||
* fall through to the write state, as we will need to
|
||||
* send a byte as well
|
||||
*/
|
||||
|
||||
case STATE_WRITE:
|
||||
/*
|
||||
* we are writing data to the device... check for the
|
||||
* end of the message, and if so, work out what to do
|
||||
*/
|
||||
if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
|
||||
if (iicstat & S3C2410_IICSTAT_LASTBIT) {
|
||||
dev_dbg(i2c->dev, "WRITE: No Ack\n");
|
||||
@@ -475,12 +468,13 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
|
||||
byte = i2c->msg->buf[i2c->msg_ptr++];
|
||||
writeb(byte, i2c->regs + S3C2410_IICDS);
|
||||
|
||||
/* delay after writing the byte to allow the
|
||||
/*
|
||||
* delay after writing the byte to allow the
|
||||
* data setup time on the bus, as writing the
|
||||
* data to the register causes the first bit
|
||||
* to appear on SDA, and SCL will change as
|
||||
* soon as the interrupt is acknowledged */
|
||||
|
||||
* soon as the interrupt is acknowledged
|
||||
*/
|
||||
ndelay(i2c->tx_setup);
|
||||
|
||||
} else if (!is_lastmsg(i2c)) {
|
||||
@@ -496,10 +490,11 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
|
||||
if (i2c->msg->flags & I2C_M_NOSTART) {
|
||||
|
||||
if (i2c->msg->flags & I2C_M_RD) {
|
||||
/* cannot do this, the controller
|
||||
/*
|
||||
* cannot do this, the controller
|
||||
* forces us to send a new START
|
||||
* when we change direction */
|
||||
|
||||
* when we change direction
|
||||
*/
|
||||
s3c24xx_i2c_stop(i2c, -EINVAL);
|
||||
}
|
||||
|
||||
@@ -512,17 +507,16 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
|
||||
|
||||
} else {
|
||||
/* send stop */
|
||||
|
||||
s3c24xx_i2c_stop(i2c, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_READ:
|
||||
/* we have a byte of data in the data register, do
|
||||
/*
|
||||
* we have a byte of data in the data register, do
|
||||
* something with it, and then work out whether we are
|
||||
* going to do any more read/write
|
||||
*/
|
||||
|
||||
byte = readb(i2c->regs + S3C2410_IICDS);
|
||||
i2c->msg->buf[i2c->msg_ptr++] = byte;
|
||||
|
||||
@@ -537,9 +531,10 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
|
||||
s3c24xx_i2c_disable_ack(i2c);
|
||||
|
||||
} else if (is_msgend(i2c)) {
|
||||
/* ok, we've read the entire buffer, see if there
|
||||
* is anything else we need to do */
|
||||
|
||||
/*
|
||||
* ok, we've read the entire buffer, see if there
|
||||
* is anything else we need to do
|
||||
*/
|
||||
if (is_lastmsg(i2c)) {
|
||||
/* last message, send stop and complete */
|
||||
dev_dbg(i2c->dev, "READ: Send Stop\n");
|
||||
@@ -568,11 +563,9 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* s3c24xx_i2c_irq
|
||||
*
|
||||
/*
|
||||
* top level IRQ servicing routine
|
||||
*/
|
||||
|
||||
*/
|
||||
static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
|
||||
{
|
||||
struct s3c24xx_i2c *i2c = dev_id;
|
||||
@@ -595,9 +588,10 @@ static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* pretty much this leaves us with the fact that we've
|
||||
* transmitted or received whatever byte we last sent */
|
||||
|
||||
/*
|
||||
* pretty much this leaves us with the fact that we've
|
||||
* transmitted or received whatever byte we last sent
|
||||
*/
|
||||
i2c_s3c_irq_nextbyte(i2c, status);
|
||||
|
||||
out:
|
||||
@@ -630,11 +624,9 @@ static inline void s3c24xx_i2c_disable_bus(struct s3c24xx_i2c *i2c)
|
||||
}
|
||||
|
||||
|
||||
/* s3c24xx_i2c_set_master
|
||||
*
|
||||
/*
|
||||
* get the i2c bus for a master transaction
|
||||
*/
|
||||
|
||||
*/
|
||||
static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
|
||||
{
|
||||
unsigned long iicstat;
|
||||
@@ -652,11 +644,9 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* s3c24xx_i2c_wait_idle
|
||||
*
|
||||
/*
|
||||
* wait for the i2c bus to become idle.
|
||||
*/
|
||||
|
||||
*/
|
||||
static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c)
|
||||
{
|
||||
unsigned long iicstat;
|
||||
@@ -706,11 +696,9 @@ static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c)
|
||||
dev_warn(i2c->dev, "timeout waiting for bus idle\n");
|
||||
}
|
||||
|
||||
/* s3c24xx_i2c_doxfer
|
||||
*
|
||||
/*
|
||||
* this starts an i2c transfer
|
||||
*/
|
||||
|
||||
*/
|
||||
static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
|
||||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
@@ -749,9 +737,10 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
|
||||
|
||||
ret = i2c->msg_idx;
|
||||
|
||||
/* having these next two as dev_err() makes life very
|
||||
* noisy when doing an i2cdetect */
|
||||
|
||||
/*
|
||||
* Having these next two as dev_err() makes life very
|
||||
* noisy when doing an i2cdetect
|
||||
*/
|
||||
if (timeout == 0)
|
||||
dev_dbg(i2c->dev, "timeout\n");
|
||||
else if (ret != num)
|
||||
@@ -771,12 +760,10 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* s3c24xx_i2c_xfer
|
||||
*
|
||||
/*
|
||||
* first port of call from the i2c bus code when an message needs
|
||||
* transferring across the i2c bus.
|
||||
*/
|
||||
|
||||
*/
|
||||
static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
@@ -814,17 +801,14 @@ static u32 s3c24xx_i2c_func(struct i2c_adapter *adap)
|
||||
}
|
||||
|
||||
/* i2c bus registration info */
|
||||
|
||||
static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
|
||||
.master_xfer = s3c24xx_i2c_xfer,
|
||||
.functionality = s3c24xx_i2c_func,
|
||||
};
|
||||
|
||||
/* s3c24xx_i2c_calcdivisor
|
||||
*
|
||||
/*
|
||||
* return the divisor settings for a given frequency
|
||||
*/
|
||||
|
||||
*/
|
||||
static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted,
|
||||
unsigned int *div1, unsigned int *divs)
|
||||
{
|
||||
@@ -850,13 +834,11 @@ static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted,
|
||||
return clkin / (calc_divs * calc_div1);
|
||||
}
|
||||
|
||||
/* s3c24xx_i2c_clockrate
|
||||
*
|
||||
/*
|
||||
* work out a divisor for the user requested frequency setting,
|
||||
* either by the requested frequency, or scanning the acceptable
|
||||
* range of frequencies until something is found
|
||||
*/
|
||||
|
||||
*/
|
||||
static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)
|
||||
{
|
||||
struct s3c2410_platform_i2c *pdata = i2c->pdata;
|
||||
@@ -944,7 +926,7 @@ static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb,
|
||||
i2c_unlock_adapter(&i2c->adap);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(i2c->dev, "cannot find frequency\n");
|
||||
dev_err(i2c->dev, "cannot find frequency (%d)\n", ret);
|
||||
else
|
||||
dev_info(i2c->dev, "setting freq %d\n", got);
|
||||
}
|
||||
@@ -995,7 +977,8 @@ static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c)
|
||||
|
||||
ret = gpio_request(gpio, "i2c-bus");
|
||||
if (ret) {
|
||||
dev_err(i2c->dev, "gpio [%d] request failed\n", gpio);
|
||||
dev_err(i2c->dev, "gpio [%d] request failed (%d)\n",
|
||||
gpio, ret);
|
||||
goto free_gpio;
|
||||
}
|
||||
}
|
||||
@@ -1028,11 +1011,9 @@ static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* s3c24xx_i2c_init
|
||||
*
|
||||
/*
|
||||
* initialise the controller, set the IO lines and frequency
|
||||
*/
|
||||
|
||||
*/
|
||||
static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
|
||||
{
|
||||
struct s3c2410_platform_i2c *pdata;
|
||||
@@ -1068,11 +1049,9 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/* s3c24xx_i2c_parse_dt
|
||||
*
|
||||
/*
|
||||
* Parse the device tree node and retreive the platform data.
|
||||
*/
|
||||
|
||||
*/
|
||||
static void
|
||||
s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
|
||||
{
|
||||
@@ -1105,17 +1084,9 @@ s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
|
||||
}
|
||||
#else
|
||||
static void
|
||||
s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c) { }
|
||||
#endif
|
||||
|
||||
/* s3c24xx_i2c_probe
|
||||
*
|
||||
* called by the bus driver when a suitable device is found
|
||||
*/
|
||||
|
||||
static int s3c24xx_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct s3c24xx_i2c *i2c;
|
||||
@@ -1156,7 +1127,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
|
||||
init_waitqueue_head(&i2c->wait);
|
||||
|
||||
/* find the clock and enable it */
|
||||
|
||||
i2c->dev = &pdev->dev;
|
||||
i2c->clk = devm_clk_get(&pdev->dev, "i2c");
|
||||
if (IS_ERR(i2c->clk)) {
|
||||
@@ -1166,9 +1136,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
|
||||
|
||||
|
||||
/* map the registers */
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
i2c->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
|
||||
@@ -1179,33 +1147,35 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
|
||||
i2c->regs, res);
|
||||
|
||||
/* setup info block for the i2c core */
|
||||
|
||||
i2c->adap.algo_data = i2c;
|
||||
i2c->adap.dev.parent = &pdev->dev;
|
||||
|
||||
i2c->pctrl = devm_pinctrl_get_select_default(i2c->dev);
|
||||
|
||||
/* inititalise the i2c gpio lines */
|
||||
|
||||
if (i2c->pdata->cfg_gpio) {
|
||||
if (i2c->pdata->cfg_gpio)
|
||||
i2c->pdata->cfg_gpio(to_platform_device(i2c->dev));
|
||||
} else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c)) {
|
||||
else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* initialise the i2c controller */
|
||||
ret = clk_prepare_enable(i2c->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "I2C clock enable failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
clk_prepare_enable(i2c->clk);
|
||||
ret = s3c24xx_i2c_init(i2c);
|
||||
clk_disable(i2c->clk);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "I2C controller init failed\n");
|
||||
clk_unprepare(i2c->clk);
|
||||
return ret;
|
||||
}
|
||||
/* find the IRQ for this unit (note, this relies on the init call to
|
||||
|
||||
/*
|
||||
* find the IRQ for this unit (note, this relies on the init call to
|
||||
* ensure no current IRQs pending
|
||||
*/
|
||||
|
||||
if (!(i2c->quirks & QUIRK_POLL)) {
|
||||
i2c->irq = ret = platform_get_irq(pdev, 0);
|
||||
if (ret <= 0) {
|
||||
@@ -1214,9 +1184,8 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq, 0,
|
||||
dev_name(&pdev->dev), i2c);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq,
|
||||
0, dev_name(&pdev->dev), i2c);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
|
||||
clk_unprepare(i2c->clk);
|
||||
@@ -1231,12 +1200,12 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Note, previous versions of the driver used i2c_add_adapter()
|
||||
/*
|
||||
* Note, previous versions of the driver used i2c_add_adapter()
|
||||
* to add the bus at any number. We now pass the bus number via
|
||||
* the platform data, so if unset it will now default to always
|
||||
* being bus 0.
|
||||
*/
|
||||
|
||||
i2c->adap.nr = i2c->pdata->bus_num;
|
||||
i2c->adap.dev.of_node = pdev->dev.of_node;
|
||||
|
||||
@@ -1257,11 +1226,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* s3c24xx_i2c_remove
|
||||
*
|
||||
* called when device is removed from the bus
|
||||
*/
|
||||
|
||||
static int s3c24xx_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
|
||||
@@ -1316,14 +1280,8 @@ static int s3c24xx_i2c_resume_noirq(struct device *dev)
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = {
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.suspend_noirq = s3c24xx_i2c_suspend_noirq,
|
||||
.resume_noirq = s3c24xx_i2c_resume_noirq,
|
||||
.freeze_noirq = s3c24xx_i2c_suspend_noirq,
|
||||
.thaw_noirq = s3c24xx_i2c_resume_noirq,
|
||||
.poweroff_noirq = s3c24xx_i2c_suspend_noirq,
|
||||
.restore_noirq = s3c24xx_i2c_resume_noirq,
|
||||
#endif
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(s3c24xx_i2c_suspend_noirq,
|
||||
s3c24xx_i2c_resume_noirq)
|
||||
};
|
||||
|
||||
#define S3C24XX_DEV_PM_OPS (&s3c24xx_i2c_dev_pm_ops)
|
||||
@@ -1331,8 +1289,6 @@ static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = {
|
||||
#define S3C24XX_DEV_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
/* device driver for platform bus bits */
|
||||
|
||||
static struct platform_driver s3c24xx_i2c_driver = {
|
||||
.probe = s3c24xx_i2c_probe,
|
||||
.remove = s3c24xx_i2c_remove,
|
||||
|
||||
@@ -398,8 +398,7 @@ static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd,
|
||||
{
|
||||
switch (pd->pos) {
|
||||
case -1:
|
||||
*buf = (pd->msg->addr & 0x7f) << 1;
|
||||
*buf |= (pd->msg->flags & I2C_M_RD) ? 1 : 0;
|
||||
*buf = i2c_8bit_addr_from_msg(pd->msg);
|
||||
break;
|
||||
default:
|
||||
*buf = pd->msg->buf[pd->pos];
|
||||
|
||||
@@ -190,9 +190,7 @@ static void i2c_sirfsoc_set_address(struct sirfsoc_i2c *siic,
|
||||
|
||||
writel(regval, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
|
||||
|
||||
addr = msg->addr << 1; /* Generate address */
|
||||
if (msg->flags & I2C_M_RD)
|
||||
addr |= 1;
|
||||
addr = i2c_8bit_addr_from_msg(msg);
|
||||
|
||||
/* Reverse direction bit */
|
||||
if (msg->flags & I2C_M_REV_DIR_ADDR)
|
||||
|
||||
@@ -337,10 +337,42 @@ static void st_i2c_hw_config(struct st_i2c_dev *i2c_dev)
|
||||
writel_relaxed(val, i2c_dev->base + SSC_NOISE_SUPP_WIDTH_DATAOUT);
|
||||
}
|
||||
|
||||
static int st_i2c_recover_bus(struct i2c_adapter *i2c_adap)
|
||||
{
|
||||
struct st_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
|
||||
u32 ctl;
|
||||
|
||||
dev_dbg(i2c_dev->dev, "Trying to recover bus\n");
|
||||
|
||||
/*
|
||||
* SSP IP is dual role SPI/I2C to generate 9 clock pulses
|
||||
* we switch to SPI node, 9 bit words and write a 0. This
|
||||
* has been validate with a oscilloscope and is easier
|
||||
* than switching to GPIO mode.
|
||||
*/
|
||||
|
||||
/* Disable interrupts */
|
||||
writel_relaxed(0, i2c_dev->base + SSC_IEN);
|
||||
|
||||
st_i2c_hw_config(i2c_dev);
|
||||
|
||||
ctl = SSC_CTL_EN | SSC_CTL_MS | SSC_CTL_EN_RX_FIFO | SSC_CTL_EN_TX_FIFO;
|
||||
st_i2c_set_bits(i2c_dev->base + SSC_CTL, ctl);
|
||||
|
||||
st_i2c_clr_bits(i2c_dev->base + SSC_I2C, SSC_I2C_I2CM);
|
||||
usleep_range(8000, 10000);
|
||||
|
||||
writel_relaxed(0, i2c_dev->base + SSC_TBUF);
|
||||
usleep_range(2000, 4000);
|
||||
st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_I2CM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_i2c_wait_free_bus(struct st_i2c_dev *i2c_dev)
|
||||
{
|
||||
u32 sta;
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
sta = readl_relaxed(i2c_dev->base + SSC_STA);
|
||||
@@ -352,6 +384,12 @@ static int st_i2c_wait_free_bus(struct st_i2c_dev *i2c_dev)
|
||||
|
||||
dev_err(i2c_dev->dev, "bus not free (status = 0x%08x)\n", sta);
|
||||
|
||||
ret = i2c_recover_bus(&i2c_dev->adap);
|
||||
if (ret) {
|
||||
dev_err(i2c_dev->dev, "Failed to recover the bus (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
@@ -614,8 +652,7 @@ static int st_i2c_xfer_msg(struct st_i2c_dev *i2c_dev, struct i2c_msg *msg,
|
||||
unsigned long timeout;
|
||||
int ret;
|
||||
|
||||
c->addr = (u8)(msg->addr << 1);
|
||||
c->addr |= (msg->flags & I2C_M_RD);
|
||||
c->addr = i2c_8bit_addr_from_msg(msg);
|
||||
c->buf = msg->buf;
|
||||
c->count = msg->len;
|
||||
c->xfered = 0;
|
||||
@@ -744,6 +781,10 @@ static struct i2c_algorithm st_i2c_algo = {
|
||||
.functionality = st_i2c_func,
|
||||
};
|
||||
|
||||
static struct i2c_bus_recovery_info st_i2c_recovery_info = {
|
||||
.recover_bus = st_i2c_recover_bus,
|
||||
};
|
||||
|
||||
static int st_i2c_of_get_deglitch(struct device_node *np,
|
||||
struct st_i2c_dev *i2c_dev)
|
||||
{
|
||||
@@ -826,6 +867,7 @@ static int st_i2c_probe(struct platform_device *pdev)
|
||||
adap->timeout = 2 * HZ;
|
||||
adap->retries = 0;
|
||||
adap->algo = &st_i2c_algo;
|
||||
adap->bus_recovery_info = &st_i2c_recovery_info;
|
||||
adap->dev.parent = &pdev->dev;
|
||||
adap->dev.of_node = pdev->dev.of_node;
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12
|
||||
#define I2C_CNFG_PACKET_MODE_EN (1<<10)
|
||||
#define I2C_CNFG_NEW_MASTER_FSM (1<<11)
|
||||
#define I2C_CNFG_MULTI_MASTER_MODE (1<<17)
|
||||
#define I2C_STATUS 0x01C
|
||||
#define I2C_SL_CNFG 0x020
|
||||
#define I2C_SL_CNFG_NACK (1<<1)
|
||||
@@ -106,6 +107,9 @@
|
||||
#define I2C_SLV_CONFIG_LOAD (1 << 1)
|
||||
#define I2C_TIMEOUT_CONFIG_LOAD (1 << 2)
|
||||
|
||||
#define I2C_CLKEN_OVERRIDE 0x090
|
||||
#define I2C_MST_CORE_CLKEN_OVR (1 << 0)
|
||||
|
||||
/*
|
||||
* msg_end_type: The bus control which need to be send at end of transfer.
|
||||
* @MSG_END_STOP: Send stop pulse at end of transfer.
|
||||
@@ -143,6 +147,8 @@ struct tegra_i2c_hw_feature {
|
||||
int clk_divisor_hs_mode;
|
||||
int clk_divisor_std_fast_mode;
|
||||
u16 clk_divisor_fast_plus_mode;
|
||||
bool has_multi_master_mode;
|
||||
bool has_slcg_override_reg;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -184,6 +190,7 @@ struct tegra_i2c_dev {
|
||||
u32 bus_clk_rate;
|
||||
u16 clk_divisor_non_hs_mode;
|
||||
bool is_suspended;
|
||||
bool is_multimaster_mode;
|
||||
};
|
||||
|
||||
static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned long reg)
|
||||
@@ -438,6 +445,10 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
|
||||
|
||||
val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN |
|
||||
(0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
|
||||
|
||||
if (i2c_dev->hw->has_multi_master_mode)
|
||||
val |= I2C_CNFG_MULTI_MASTER_MODE;
|
||||
|
||||
i2c_writel(i2c_dev, val, I2C_CNFG);
|
||||
i2c_writel(i2c_dev, 0, I2C_INT_MASK);
|
||||
|
||||
@@ -463,25 +474,29 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
|
||||
if (tegra_i2c_flush_fifos(i2c_dev))
|
||||
err = -ETIMEDOUT;
|
||||
|
||||
if (i2c_dev->is_multimaster_mode && i2c_dev->hw->has_slcg_override_reg)
|
||||
i2c_writel(i2c_dev, I2C_MST_CORE_CLKEN_OVR, I2C_CLKEN_OVERRIDE);
|
||||
|
||||
if (i2c_dev->hw->has_config_load_reg) {
|
||||
i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD);
|
||||
while (i2c_readl(i2c_dev, I2C_CONFIG_LOAD) != 0) {
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_warn(i2c_dev->dev,
|
||||
"timeout waiting for config load\n");
|
||||
return -ETIMEDOUT;
|
||||
err = -ETIMEDOUT;
|
||||
goto err;
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
tegra_i2c_clock_disable(i2c_dev);
|
||||
|
||||
if (i2c_dev->irq_disabled) {
|
||||
i2c_dev->irq_disabled = 0;
|
||||
enable_irq(i2c_dev->irq);
|
||||
}
|
||||
|
||||
err:
|
||||
tegra_i2c_clock_disable(i2c_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -688,6 +703,20 @@ static u32 tegra_i2c_func(struct i2c_adapter *adap)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
struct device_node *np = i2c_dev->dev->of_node;
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_u32(np, "clock-frequency",
|
||||
&i2c_dev->bus_clk_rate);
|
||||
if (ret)
|
||||
i2c_dev->bus_clk_rate = 100000; /* default clock rate */
|
||||
|
||||
i2c_dev->is_multimaster_mode = of_property_read_bool(np,
|
||||
"multi-master");
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm tegra_i2c_algo = {
|
||||
.master_xfer = tegra_i2c_xfer,
|
||||
.functionality = tegra_i2c_func,
|
||||
@@ -707,6 +736,8 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
|
||||
.clk_divisor_std_fast_mode = 0,
|
||||
.clk_divisor_fast_plus_mode = 0,
|
||||
.has_config_load_reg = false,
|
||||
.has_multi_master_mode = false,
|
||||
.has_slcg_override_reg = false,
|
||||
};
|
||||
|
||||
static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
|
||||
@@ -717,6 +748,8 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
|
||||
.clk_divisor_std_fast_mode = 0,
|
||||
.clk_divisor_fast_plus_mode = 0,
|
||||
.has_config_load_reg = false,
|
||||
.has_multi_master_mode = false,
|
||||
.has_slcg_override_reg = false,
|
||||
};
|
||||
|
||||
static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
|
||||
@@ -727,6 +760,8 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
|
||||
.clk_divisor_std_fast_mode = 0x19,
|
||||
.clk_divisor_fast_plus_mode = 0x10,
|
||||
.has_config_load_reg = false,
|
||||
.has_multi_master_mode = false,
|
||||
.has_slcg_override_reg = false,
|
||||
};
|
||||
|
||||
static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
|
||||
@@ -737,10 +772,25 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
|
||||
.clk_divisor_std_fast_mode = 0x19,
|
||||
.clk_divisor_fast_plus_mode = 0x10,
|
||||
.has_config_load_reg = true,
|
||||
.has_multi_master_mode = false,
|
||||
.has_slcg_override_reg = true,
|
||||
};
|
||||
|
||||
static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
|
||||
.has_continue_xfer_support = true,
|
||||
.has_per_pkt_xfer_complete_irq = true,
|
||||
.has_single_clk_source = true,
|
||||
.clk_divisor_hs_mode = 1,
|
||||
.clk_divisor_std_fast_mode = 0x19,
|
||||
.clk_divisor_fast_plus_mode = 0x10,
|
||||
.has_config_load_reg = true,
|
||||
.has_multi_master_mode = true,
|
||||
.has_slcg_override_reg = true,
|
||||
};
|
||||
|
||||
/* Match table for of_platform binding */
|
||||
static const struct of_device_id tegra_i2c_of_match[] = {
|
||||
{ .compatible = "nvidia,tegra210-i2c", .data = &tegra210_i2c_hw, },
|
||||
{ .compatible = "nvidia,tegra124-i2c", .data = &tegra124_i2c_hw, },
|
||||
{ .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, },
|
||||
{ .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, },
|
||||
@@ -797,10 +847,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(i2c_dev->rst);
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(i2c_dev->dev->of_node, "clock-frequency",
|
||||
&i2c_dev->bus_clk_rate);
|
||||
if (ret)
|
||||
i2c_dev->bus_clk_rate = 100000; /* default clock rate */
|
||||
tegra_i2c_parse_dt(i2c_dev);
|
||||
|
||||
i2c_dev->hw = &tegra20_i2c_hw;
|
||||
|
||||
@@ -853,6 +900,15 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
||||
goto unprepare_fast_clk;
|
||||
}
|
||||
|
||||
if (i2c_dev->is_multimaster_mode) {
|
||||
ret = clk_enable(i2c_dev->div_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(i2c_dev->dev, "div_clk enable failed %d\n",
|
||||
ret);
|
||||
goto unprepare_div_clk;
|
||||
}
|
||||
}
|
||||
|
||||
ret = tegra_i2c_init(i2c_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to initialize i2c controller");
|
||||
@@ -863,7 +919,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
||||
tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
|
||||
goto unprepare_div_clk;
|
||||
goto disable_div_clk;
|
||||
}
|
||||
|
||||
i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
|
||||
@@ -878,11 +934,15 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
||||
ret = i2c_add_numbered_adapter(&i2c_dev->adapter);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to add I2C adapter\n");
|
||||
goto unprepare_div_clk;
|
||||
goto disable_div_clk;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
disable_div_clk:
|
||||
if (i2c_dev->is_multimaster_mode)
|
||||
clk_disable(i2c_dev->div_clk);
|
||||
|
||||
unprepare_div_clk:
|
||||
clk_unprepare(i2c_dev->div_clk);
|
||||
|
||||
@@ -898,6 +958,9 @@ static int tegra_i2c_remove(struct platform_device *pdev)
|
||||
struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
|
||||
i2c_del_adapter(&i2c_dev->adapter);
|
||||
|
||||
if (i2c_dev->is_multimaster_mode)
|
||||
clk_disable(i2c_dev->div_clk);
|
||||
|
||||
clk_unprepare(i2c_dev->div_clk);
|
||||
if (!i2c_dev->hw->has_single_clk_source)
|
||||
clk_unprepare(i2c_dev->fast_clk);
|
||||
|
||||
@@ -524,7 +524,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "failed to get IRQ number");
|
||||
dev_err(dev, "failed to get IRQ number\n");
|
||||
return irq;
|
||||
}
|
||||
|
||||
|
||||
@@ -381,7 +381,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "failed to get IRQ number");
|
||||
dev_err(dev, "failed to get IRQ number\n");
|
||||
return irq;
|
||||
}
|
||||
|
||||
|
||||
@@ -954,48 +954,40 @@ static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
|
||||
}
|
||||
|
||||
/**
|
||||
* i2c_lock_adapter - Get exclusive access to an I2C bus segment
|
||||
* i2c_adapter_lock_bus - Get exclusive access to an I2C bus segment
|
||||
* @adapter: Target I2C bus segment
|
||||
* @flags: I2C_LOCK_ROOT_ADAPTER locks the root i2c adapter, I2C_LOCK_SEGMENT
|
||||
* locks only this branch in the adapter tree
|
||||
*/
|
||||
void i2c_lock_adapter(struct i2c_adapter *adapter)
|
||||
static void i2c_adapter_lock_bus(struct i2c_adapter *adapter,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
|
||||
|
||||
if (parent)
|
||||
i2c_lock_adapter(parent);
|
||||
else
|
||||
rt_mutex_lock(&adapter->bus_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_lock_adapter);
|
||||
|
||||
/**
|
||||
* i2c_trylock_adapter - Try to get exclusive access to an I2C bus segment
|
||||
* @adapter: Target I2C bus segment
|
||||
*/
|
||||
static int i2c_trylock_adapter(struct i2c_adapter *adapter)
|
||||
{
|
||||
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
|
||||
|
||||
if (parent)
|
||||
return i2c_trylock_adapter(parent);
|
||||
else
|
||||
return rt_mutex_trylock(&adapter->bus_lock);
|
||||
rt_mutex_lock(&adapter->bus_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* i2c_unlock_adapter - Release exclusive access to an I2C bus segment
|
||||
* i2c_adapter_trylock_bus - Try to get exclusive access to an I2C bus segment
|
||||
* @adapter: Target I2C bus segment
|
||||
* @flags: I2C_LOCK_ROOT_ADAPTER trylocks the root i2c adapter, I2C_LOCK_SEGMENT
|
||||
* trylocks only this branch in the adapter tree
|
||||
*/
|
||||
void i2c_unlock_adapter(struct i2c_adapter *adapter)
|
||||
static int i2c_adapter_trylock_bus(struct i2c_adapter *adapter,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
|
||||
|
||||
if (parent)
|
||||
i2c_unlock_adapter(parent);
|
||||
else
|
||||
rt_mutex_unlock(&adapter->bus_lock);
|
||||
return rt_mutex_trylock(&adapter->bus_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* i2c_adapter_unlock_bus - Release exclusive access to an I2C bus segment
|
||||
* @adapter: Target I2C bus segment
|
||||
* @flags: I2C_LOCK_ROOT_ADAPTER unlocks the root i2c adapter, I2C_LOCK_SEGMENT
|
||||
* unlocks only this branch in the adapter tree
|
||||
*/
|
||||
static void i2c_adapter_unlock_bus(struct i2c_adapter *adapter,
|
||||
unsigned int flags)
|
||||
{
|
||||
rt_mutex_unlock(&adapter->bus_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_unlock_adapter);
|
||||
|
||||
static void i2c_dev_set_name(struct i2c_adapter *adap,
|
||||
struct i2c_client *client)
|
||||
@@ -1541,7 +1533,14 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!adap->lock_bus) {
|
||||
adap->lock_bus = i2c_adapter_lock_bus;
|
||||
adap->trylock_bus = i2c_adapter_trylock_bus;
|
||||
adap->unlock_bus = i2c_adapter_unlock_bus;
|
||||
}
|
||||
|
||||
rt_mutex_init(&adap->bus_lock);
|
||||
rt_mutex_init(&adap->mux_lock);
|
||||
mutex_init(&adap->userspace_clients_lock);
|
||||
INIT_LIST_HEAD(&adap->userspace_clients);
|
||||
|
||||
@@ -1559,6 +1558,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
|
||||
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
|
||||
|
||||
pm_runtime_no_callbacks(&adap->dev);
|
||||
pm_suspend_ignore_children(&adap->dev, true);
|
||||
pm_runtime_enable(&adap->dev);
|
||||
|
||||
#ifdef CONFIG_I2C_COMPAT
|
||||
@@ -1594,10 +1594,12 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
|
||||
|
||||
bri->get_scl = get_scl_gpio_value;
|
||||
bri->set_scl = set_scl_gpio_value;
|
||||
} else if (!bri->set_scl || !bri->get_scl) {
|
||||
} else if (bri->recover_bus == i2c_generic_scl_recovery) {
|
||||
/* Generic SCL recovery */
|
||||
dev_err(&adap->dev, "No {get|set}_gpio() found, not using recovery\n");
|
||||
adap->bus_recovery_info = NULL;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2309,16 +2311,16 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
#endif
|
||||
|
||||
if (in_atomic() || irqs_disabled()) {
|
||||
ret = i2c_trylock_adapter(adap);
|
||||
ret = adap->trylock_bus(adap, I2C_LOCK_SEGMENT);
|
||||
if (!ret)
|
||||
/* I2C activity is ongoing. */
|
||||
return -EAGAIN;
|
||||
} else {
|
||||
i2c_lock_adapter(adap);
|
||||
i2c_lock_bus(adap, I2C_LOCK_SEGMENT);
|
||||
}
|
||||
|
||||
ret = __i2c_transfer(adap, msgs, num);
|
||||
i2c_unlock_adapter(adap);
|
||||
i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
@@ -2646,7 +2648,7 @@ static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count)
|
||||
static u8 i2c_smbus_msg_pec(u8 pec, struct i2c_msg *msg)
|
||||
{
|
||||
/* The address will be sent first */
|
||||
u8 addr = (msg->addr << 1) | !!(msg->flags & I2C_M_RD);
|
||||
u8 addr = i2c_8bit_addr_from_msg(msg);
|
||||
pec = i2c_smbus_pec(pec, &addr, 1);
|
||||
|
||||
/* The data buffer follows */
|
||||
@@ -3093,7 +3095,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
|
||||
flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB;
|
||||
|
||||
if (adapter->algo->smbus_xfer) {
|
||||
i2c_lock_adapter(adapter);
|
||||
i2c_lock_bus(adapter, I2C_LOCK_SEGMENT);
|
||||
|
||||
/* Retry automatically on arbitration loss */
|
||||
orig_jiffies = jiffies;
|
||||
@@ -3107,7 +3109,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
|
||||
orig_jiffies + adapter->timeout))
|
||||
break;
|
||||
}
|
||||
i2c_unlock_adapter(adapter);
|
||||
i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT);
|
||||
|
||||
if (res != -EOPNOTSUPP || !adapter->algo->master_xfer)
|
||||
goto trace;
|
||||
|
||||
@@ -31,30 +31,66 @@
|
||||
struct i2c_mux_priv {
|
||||
struct i2c_adapter adap;
|
||||
struct i2c_algorithm algo;
|
||||
|
||||
struct i2c_adapter *parent;
|
||||
struct device *mux_dev;
|
||||
void *mux_priv;
|
||||
struct i2c_mux_core *muxc;
|
||||
u32 chan_id;
|
||||
|
||||
int (*select)(struct i2c_adapter *, void *mux_priv, u32 chan_id);
|
||||
int (*deselect)(struct i2c_adapter *, void *mux_priv, u32 chan_id);
|
||||
};
|
||||
|
||||
static int __i2c_mux_master_xfer(struct i2c_adapter *adap,
|
||||
struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct i2c_mux_priv *priv = adap->algo_data;
|
||||
struct i2c_mux_core *muxc = priv->muxc;
|
||||
struct i2c_adapter *parent = muxc->parent;
|
||||
int ret;
|
||||
|
||||
/* Switch to the right mux port and perform the transfer. */
|
||||
|
||||
ret = muxc->select(muxc, priv->chan_id);
|
||||
if (ret >= 0)
|
||||
ret = __i2c_transfer(parent, msgs, num);
|
||||
if (muxc->deselect)
|
||||
muxc->deselect(muxc, priv->chan_id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int i2c_mux_master_xfer(struct i2c_adapter *adap,
|
||||
struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct i2c_mux_priv *priv = adap->algo_data;
|
||||
struct i2c_adapter *parent = priv->parent;
|
||||
struct i2c_mux_core *muxc = priv->muxc;
|
||||
struct i2c_adapter *parent = muxc->parent;
|
||||
int ret;
|
||||
|
||||
/* Switch to the right mux port and perform the transfer. */
|
||||
|
||||
ret = priv->select(parent, priv->mux_priv, priv->chan_id);
|
||||
ret = muxc->select(muxc, priv->chan_id);
|
||||
if (ret >= 0)
|
||||
ret = __i2c_transfer(parent, msgs, num);
|
||||
if (priv->deselect)
|
||||
priv->deselect(parent, priv->mux_priv, priv->chan_id);
|
||||
ret = i2c_transfer(parent, msgs, num);
|
||||
if (muxc->deselect)
|
||||
muxc->deselect(muxc, priv->chan_id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap,
|
||||
u16 addr, unsigned short flags,
|
||||
char read_write, u8 command,
|
||||
int size, union i2c_smbus_data *data)
|
||||
{
|
||||
struct i2c_mux_priv *priv = adap->algo_data;
|
||||
struct i2c_mux_core *muxc = priv->muxc;
|
||||
struct i2c_adapter *parent = muxc->parent;
|
||||
int ret;
|
||||
|
||||
/* Select the right mux port and perform the transfer. */
|
||||
|
||||
ret = muxc->select(muxc, priv->chan_id);
|
||||
if (ret >= 0)
|
||||
ret = parent->algo->smbus_xfer(parent, addr, flags,
|
||||
read_write, command, size, data);
|
||||
if (muxc->deselect)
|
||||
muxc->deselect(muxc, priv->chan_id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -65,17 +101,18 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
|
||||
int size, union i2c_smbus_data *data)
|
||||
{
|
||||
struct i2c_mux_priv *priv = adap->algo_data;
|
||||
struct i2c_adapter *parent = priv->parent;
|
||||
struct i2c_mux_core *muxc = priv->muxc;
|
||||
struct i2c_adapter *parent = muxc->parent;
|
||||
int ret;
|
||||
|
||||
/* Select the right mux port and perform the transfer. */
|
||||
|
||||
ret = priv->select(parent, priv->mux_priv, priv->chan_id);
|
||||
ret = muxc->select(muxc, priv->chan_id);
|
||||
if (ret >= 0)
|
||||
ret = parent->algo->smbus_xfer(parent, addr, flags,
|
||||
read_write, command, size, data);
|
||||
if (priv->deselect)
|
||||
priv->deselect(parent, priv->mux_priv, priv->chan_id);
|
||||
ret = i2c_smbus_xfer(parent, addr, flags,
|
||||
read_write, command, size, data);
|
||||
if (muxc->deselect)
|
||||
muxc->deselect(muxc, priv->chan_id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -84,7 +121,7 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
|
||||
static u32 i2c_mux_functionality(struct i2c_adapter *adap)
|
||||
{
|
||||
struct i2c_mux_priv *priv = adap->algo_data;
|
||||
struct i2c_adapter *parent = priv->parent;
|
||||
struct i2c_adapter *parent = priv->muxc->parent;
|
||||
|
||||
return parent->algo->functionality(parent);
|
||||
}
|
||||
@@ -102,38 +139,167 @@ static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent)
|
||||
return class;
|
||||
}
|
||||
|
||||
struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
|
||||
struct device *mux_dev,
|
||||
void *mux_priv, u32 force_nr, u32 chan_id,
|
||||
unsigned int class,
|
||||
int (*select) (struct i2c_adapter *,
|
||||
void *, u32),
|
||||
int (*deselect) (struct i2c_adapter *,
|
||||
void *, u32))
|
||||
static void i2c_mux_lock_bus(struct i2c_adapter *adapter, unsigned int flags)
|
||||
{
|
||||
struct i2c_mux_priv *priv = adapter->algo_data;
|
||||
struct i2c_adapter *parent = priv->muxc->parent;
|
||||
|
||||
rt_mutex_lock(&parent->mux_lock);
|
||||
if (!(flags & I2C_LOCK_ROOT_ADAPTER))
|
||||
return;
|
||||
i2c_lock_bus(parent, flags);
|
||||
}
|
||||
|
||||
static int i2c_mux_trylock_bus(struct i2c_adapter *adapter, unsigned int flags)
|
||||
{
|
||||
struct i2c_mux_priv *priv = adapter->algo_data;
|
||||
struct i2c_adapter *parent = priv->muxc->parent;
|
||||
|
||||
if (!rt_mutex_trylock(&parent->mux_lock))
|
||||
return 0; /* mux_lock not locked, failure */
|
||||
if (!(flags & I2C_LOCK_ROOT_ADAPTER))
|
||||
return 1; /* we only want mux_lock, success */
|
||||
if (parent->trylock_bus(parent, flags))
|
||||
return 1; /* parent locked too, success */
|
||||
rt_mutex_unlock(&parent->mux_lock);
|
||||
return 0; /* parent not locked, failure */
|
||||
}
|
||||
|
||||
static void i2c_mux_unlock_bus(struct i2c_adapter *adapter, unsigned int flags)
|
||||
{
|
||||
struct i2c_mux_priv *priv = adapter->algo_data;
|
||||
struct i2c_adapter *parent = priv->muxc->parent;
|
||||
|
||||
if (flags & I2C_LOCK_ROOT_ADAPTER)
|
||||
i2c_unlock_bus(parent, flags);
|
||||
rt_mutex_unlock(&parent->mux_lock);
|
||||
}
|
||||
|
||||
static void i2c_parent_lock_bus(struct i2c_adapter *adapter,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct i2c_mux_priv *priv = adapter->algo_data;
|
||||
struct i2c_adapter *parent = priv->muxc->parent;
|
||||
|
||||
rt_mutex_lock(&parent->mux_lock);
|
||||
i2c_lock_bus(parent, flags);
|
||||
}
|
||||
|
||||
static int i2c_parent_trylock_bus(struct i2c_adapter *adapter,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct i2c_mux_priv *priv = adapter->algo_data;
|
||||
struct i2c_adapter *parent = priv->muxc->parent;
|
||||
|
||||
if (!rt_mutex_trylock(&parent->mux_lock))
|
||||
return 0; /* mux_lock not locked, failure */
|
||||
if (parent->trylock_bus(parent, flags))
|
||||
return 1; /* parent locked too, success */
|
||||
rt_mutex_unlock(&parent->mux_lock);
|
||||
return 0; /* parent not locked, failure */
|
||||
}
|
||||
|
||||
static void i2c_parent_unlock_bus(struct i2c_adapter *adapter,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct i2c_mux_priv *priv = adapter->algo_data;
|
||||
struct i2c_adapter *parent = priv->muxc->parent;
|
||||
|
||||
i2c_unlock_bus(parent, flags);
|
||||
rt_mutex_unlock(&parent->mux_lock);
|
||||
}
|
||||
|
||||
struct i2c_adapter *i2c_root_adapter(struct device *dev)
|
||||
{
|
||||
struct device *i2c;
|
||||
struct i2c_adapter *i2c_root;
|
||||
|
||||
/*
|
||||
* Walk up the device tree to find an i2c adapter, indicating
|
||||
* that this is an i2c client device. Check all ancestors to
|
||||
* handle mfd devices etc.
|
||||
*/
|
||||
for (i2c = dev; i2c; i2c = i2c->parent) {
|
||||
if (i2c->type == &i2c_adapter_type)
|
||||
break;
|
||||
}
|
||||
if (!i2c)
|
||||
return NULL;
|
||||
|
||||
/* Continue up the tree to find the root i2c adapter */
|
||||
i2c_root = to_i2c_adapter(i2c);
|
||||
while (i2c_parent_is_i2c_adapter(i2c_root))
|
||||
i2c_root = i2c_parent_is_i2c_adapter(i2c_root);
|
||||
|
||||
return i2c_root;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_root_adapter);
|
||||
|
||||
struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
|
||||
struct device *dev, int max_adapters,
|
||||
int sizeof_priv, u32 flags,
|
||||
int (*select)(struct i2c_mux_core *, u32),
|
||||
int (*deselect)(struct i2c_mux_core *, u32))
|
||||
{
|
||||
struct i2c_mux_core *muxc;
|
||||
|
||||
muxc = devm_kzalloc(dev, sizeof(*muxc)
|
||||
+ max_adapters * sizeof(muxc->adapter[0])
|
||||
+ sizeof_priv, GFP_KERNEL);
|
||||
if (!muxc)
|
||||
return NULL;
|
||||
if (sizeof_priv)
|
||||
muxc->priv = &muxc->adapter[max_adapters];
|
||||
|
||||
muxc->parent = parent;
|
||||
muxc->dev = dev;
|
||||
if (flags & I2C_MUX_LOCKED)
|
||||
muxc->mux_locked = true;
|
||||
muxc->select = select;
|
||||
muxc->deselect = deselect;
|
||||
muxc->max_adapters = max_adapters;
|
||||
|
||||
return muxc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_mux_alloc);
|
||||
|
||||
int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
|
||||
u32 force_nr, u32 chan_id,
|
||||
unsigned int class)
|
||||
{
|
||||
struct i2c_adapter *parent = muxc->parent;
|
||||
struct i2c_mux_priv *priv;
|
||||
char symlink_name[20];
|
||||
int ret;
|
||||
|
||||
priv = kzalloc(sizeof(struct i2c_mux_priv), GFP_KERNEL);
|
||||
if (muxc->num_adapters >= muxc->max_adapters) {
|
||||
dev_err(muxc->dev, "No room for more i2c-mux adapters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return NULL;
|
||||
return -ENOMEM;
|
||||
|
||||
/* Set up private adapter data */
|
||||
priv->parent = parent;
|
||||
priv->mux_dev = mux_dev;
|
||||
priv->mux_priv = mux_priv;
|
||||
priv->muxc = muxc;
|
||||
priv->chan_id = chan_id;
|
||||
priv->select = select;
|
||||
priv->deselect = deselect;
|
||||
|
||||
/* Need to do algo dynamically because we don't know ahead
|
||||
* of time what sort of physical adapter we'll be dealing with.
|
||||
*/
|
||||
if (parent->algo->master_xfer)
|
||||
priv->algo.master_xfer = i2c_mux_master_xfer;
|
||||
if (parent->algo->smbus_xfer)
|
||||
priv->algo.smbus_xfer = i2c_mux_smbus_xfer;
|
||||
if (parent->algo->master_xfer) {
|
||||
if (muxc->mux_locked)
|
||||
priv->algo.master_xfer = i2c_mux_master_xfer;
|
||||
else
|
||||
priv->algo.master_xfer = __i2c_mux_master_xfer;
|
||||
}
|
||||
if (parent->algo->smbus_xfer) {
|
||||
if (muxc->mux_locked)
|
||||
priv->algo.smbus_xfer = i2c_mux_smbus_xfer;
|
||||
else
|
||||
priv->algo.smbus_xfer = __i2c_mux_smbus_xfer;
|
||||
}
|
||||
priv->algo.functionality = i2c_mux_functionality;
|
||||
|
||||
/* Now fill out new adapter structure */
|
||||
@@ -146,6 +312,15 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
|
||||
priv->adap.retries = parent->retries;
|
||||
priv->adap.timeout = parent->timeout;
|
||||
priv->adap.quirks = parent->quirks;
|
||||
if (muxc->mux_locked) {
|
||||
priv->adap.lock_bus = i2c_mux_lock_bus;
|
||||
priv->adap.trylock_bus = i2c_mux_trylock_bus;
|
||||
priv->adap.unlock_bus = i2c_mux_unlock_bus;
|
||||
} else {
|
||||
priv->adap.lock_bus = i2c_parent_lock_bus;
|
||||
priv->adap.trylock_bus = i2c_parent_trylock_bus;
|
||||
priv->adap.unlock_bus = i2c_parent_unlock_bus;
|
||||
}
|
||||
|
||||
/* Sanity check on class */
|
||||
if (i2c_mux_parent_classes(parent) & class)
|
||||
@@ -159,11 +334,11 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
|
||||
* Try to populate the mux adapter's of_node, expands to
|
||||
* nothing if !CONFIG_OF.
|
||||
*/
|
||||
if (mux_dev->of_node) {
|
||||
if (muxc->dev->of_node) {
|
||||
struct device_node *child;
|
||||
u32 reg;
|
||||
|
||||
for_each_child_of_node(mux_dev->of_node, child) {
|
||||
for_each_child_of_node(muxc->dev->of_node, child) {
|
||||
ret = of_property_read_u32(child, "reg", ®);
|
||||
if (ret)
|
||||
continue;
|
||||
@@ -177,8 +352,9 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
|
||||
/*
|
||||
* Associate the mux channel with an ACPI node.
|
||||
*/
|
||||
if (has_acpi_companion(mux_dev))
|
||||
acpi_preset_companion(&priv->adap.dev, ACPI_COMPANION(mux_dev),
|
||||
if (has_acpi_companion(muxc->dev))
|
||||
acpi_preset_companion(&priv->adap.dev,
|
||||
ACPI_COMPANION(muxc->dev),
|
||||
chan_id);
|
||||
|
||||
if (force_nr) {
|
||||
@@ -192,35 +368,45 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
|
||||
"failed to add mux-adapter (error=%d)\n",
|
||||
ret);
|
||||
kfree(priv);
|
||||
return NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
WARN(sysfs_create_link(&priv->adap.dev.kobj, &mux_dev->kobj, "mux_device"),
|
||||
"can't create symlink to mux device\n");
|
||||
WARN(sysfs_create_link(&priv->adap.dev.kobj, &muxc->dev->kobj,
|
||||
"mux_device"),
|
||||
"can't create symlink to mux device\n");
|
||||
|
||||
snprintf(symlink_name, sizeof(symlink_name), "channel-%u", chan_id);
|
||||
WARN(sysfs_create_link(&mux_dev->kobj, &priv->adap.dev.kobj, symlink_name),
|
||||
"can't create symlink for channel %u\n", chan_id);
|
||||
WARN(sysfs_create_link(&muxc->dev->kobj, &priv->adap.dev.kobj,
|
||||
symlink_name),
|
||||
"can't create symlink for channel %u\n", chan_id);
|
||||
dev_info(&parent->dev, "Added multiplexed i2c bus %d\n",
|
||||
i2c_adapter_id(&priv->adap));
|
||||
|
||||
return &priv->adap;
|
||||
muxc->adapter[muxc->num_adapters++] = &priv->adap;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_add_mux_adapter);
|
||||
EXPORT_SYMBOL_GPL(i2c_mux_add_adapter);
|
||||
|
||||
void i2c_del_mux_adapter(struct i2c_adapter *adap)
|
||||
void i2c_mux_del_adapters(struct i2c_mux_core *muxc)
|
||||
{
|
||||
struct i2c_mux_priv *priv = adap->algo_data;
|
||||
char symlink_name[20];
|
||||
|
||||
snprintf(symlink_name, sizeof(symlink_name), "channel-%u", priv->chan_id);
|
||||
sysfs_remove_link(&priv->mux_dev->kobj, symlink_name);
|
||||
while (muxc->num_adapters) {
|
||||
struct i2c_adapter *adap = muxc->adapter[--muxc->num_adapters];
|
||||
struct i2c_mux_priv *priv = adap->algo_data;
|
||||
|
||||
sysfs_remove_link(&priv->adap.dev.kobj, "mux_device");
|
||||
i2c_del_adapter(adap);
|
||||
kfree(priv);
|
||||
muxc->adapter[muxc->num_adapters] = NULL;
|
||||
|
||||
snprintf(symlink_name, sizeof(symlink_name),
|
||||
"channel-%u", priv->chan_id);
|
||||
sysfs_remove_link(&muxc->dev->kobj, symlink_name);
|
||||
|
||||
sysfs_remove_link(&priv->adap.dev.kobj, "mux_device");
|
||||
i2c_del_adapter(adap);
|
||||
kfree(priv);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_del_mux_adapter);
|
||||
EXPORT_SYMBOL_GPL(i2c_mux_del_adapters);
|
||||
|
||||
MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
|
||||
MODULE_DESCRIPTION("I2C driver for multiplexed I2C busses");
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
/**
|
||||
* struct i2c_arbitrator_data - Driver data for I2C arbitrator
|
||||
*
|
||||
* @parent: Parent adapter
|
||||
* @child: Child bus
|
||||
* @our_gpio: GPIO we'll use to claim.
|
||||
* @our_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO ==
|
||||
* this then consider it released.
|
||||
@@ -42,8 +40,6 @@
|
||||
*/
|
||||
|
||||
struct i2c_arbitrator_data {
|
||||
struct i2c_adapter *parent;
|
||||
struct i2c_adapter *child;
|
||||
int our_gpio;
|
||||
int our_gpio_release;
|
||||
int their_gpio;
|
||||
@@ -59,9 +55,9 @@ struct i2c_arbitrator_data {
|
||||
*
|
||||
* Use the GPIO-based signalling protocol; return -EBUSY if we fail.
|
||||
*/
|
||||
static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan)
|
||||
static int i2c_arbitrator_select(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
const struct i2c_arbitrator_data *arb = data;
|
||||
const struct i2c_arbitrator_data *arb = i2c_mux_priv(muxc);
|
||||
unsigned long stop_retry, stop_time;
|
||||
|
||||
/* Start a round of trying to claim the bus */
|
||||
@@ -93,7 +89,7 @@ static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan)
|
||||
/* Give up, release our claim */
|
||||
gpio_set_value(arb->our_gpio, arb->our_gpio_release);
|
||||
udelay(arb->slew_delay_us);
|
||||
dev_err(&adap->dev, "Could not claim bus, timeout\n");
|
||||
dev_err(muxc->dev, "Could not claim bus, timeout\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
@@ -102,10 +98,9 @@ static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan)
|
||||
*
|
||||
* Release the I2C bus using the GPIO-based signalling protocol.
|
||||
*/
|
||||
static int i2c_arbitrator_deselect(struct i2c_adapter *adap, void *data,
|
||||
u32 chan)
|
||||
static int i2c_arbitrator_deselect(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
const struct i2c_arbitrator_data *arb = data;
|
||||
const struct i2c_arbitrator_data *arb = i2c_mux_priv(muxc);
|
||||
|
||||
/* Release the bus and wait for the other master to notice */
|
||||
gpio_set_value(arb->our_gpio, arb->our_gpio_release);
|
||||
@@ -119,6 +114,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct device_node *parent_np;
|
||||
struct i2c_mux_core *muxc;
|
||||
struct i2c_arbitrator_data *arb;
|
||||
enum of_gpio_flags gpio_flags;
|
||||
unsigned long out_init;
|
||||
@@ -134,12 +130,13 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL);
|
||||
if (!arb) {
|
||||
dev_err(dev, "Cannot allocate i2c_arbitrator_data\n");
|
||||
muxc = i2c_mux_alloc(NULL, dev, 1, sizeof(*arb), 0,
|
||||
i2c_arbitrator_select, i2c_arbitrator_deselect);
|
||||
if (!muxc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
platform_set_drvdata(pdev, arb);
|
||||
arb = i2c_mux_priv(muxc);
|
||||
|
||||
platform_set_drvdata(pdev, muxc);
|
||||
|
||||
/* Request GPIOs */
|
||||
ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags);
|
||||
@@ -196,21 +193,18 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
|
||||
dev_err(dev, "Cannot parse i2c-parent\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
arb->parent = of_get_i2c_adapter_by_node(parent_np);
|
||||
muxc->parent = of_get_i2c_adapter_by_node(parent_np);
|
||||
of_node_put(parent_np);
|
||||
if (!arb->parent) {
|
||||
if (!muxc->parent) {
|
||||
dev_err(dev, "Cannot find parent bus\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
/* Actually add the mux adapter */
|
||||
arb->child = i2c_add_mux_adapter(arb->parent, dev, arb, 0, 0, 0,
|
||||
i2c_arbitrator_select,
|
||||
i2c_arbitrator_deselect);
|
||||
if (!arb->child) {
|
||||
ret = i2c_mux_add_adapter(muxc, 0, 0, 0);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to add adapter\n");
|
||||
ret = -ENODEV;
|
||||
i2c_put_adapter(arb->parent);
|
||||
i2c_put_adapter(muxc->parent);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -218,11 +212,10 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
|
||||
|
||||
static int i2c_arbitrator_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct i2c_arbitrator_data *arb = platform_get_drvdata(pdev);
|
||||
|
||||
i2c_del_mux_adapter(arb->child);
|
||||
i2c_put_adapter(arb->parent);
|
||||
struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
|
||||
|
||||
i2c_mux_del_adapters(muxc);
|
||||
i2c_put_adapter(muxc->parent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,11 +15,10 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio.h>
|
||||
#include "../../gpio/gpiolib.h"
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
struct gpiomux {
|
||||
struct i2c_adapter *parent;
|
||||
struct i2c_adapter **adap; /* child busses */
|
||||
struct i2c_mux_gpio_platform_data data;
|
||||
unsigned gpio_base;
|
||||
};
|
||||
@@ -33,18 +32,18 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val)
|
||||
val & (1 << i));
|
||||
}
|
||||
|
||||
static int i2c_mux_gpio_select(struct i2c_adapter *adap, void *data, u32 chan)
|
||||
static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
struct gpiomux *mux = data;
|
||||
struct gpiomux *mux = i2c_mux_priv(muxc);
|
||||
|
||||
i2c_mux_gpio_set(mux, chan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_mux_gpio_deselect(struct i2c_adapter *adap, void *data, u32 chan)
|
||||
static int i2c_mux_gpio_deselect(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
struct gpiomux *mux = data;
|
||||
struct gpiomux *mux = i2c_mux_priv(muxc);
|
||||
|
||||
i2c_mux_gpio_set(mux, mux->data.idle);
|
||||
|
||||
@@ -136,19 +135,16 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
|
||||
|
||||
static int i2c_mux_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct i2c_mux_core *muxc;
|
||||
struct gpiomux *mux;
|
||||
struct i2c_adapter *parent;
|
||||
int (*deselect) (struct i2c_adapter *, void *, u32);
|
||||
struct i2c_adapter *root;
|
||||
unsigned initial_state, gpio_base;
|
||||
int i, ret;
|
||||
|
||||
mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
|
||||
if (!mux) {
|
||||
dev_err(&pdev->dev, "Cannot allocate gpiomux structure");
|
||||
if (!mux)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, mux);
|
||||
|
||||
if (!dev_get_platdata(&pdev->dev)) {
|
||||
ret = i2c_mux_gpio_probe_dt(mux, pdev);
|
||||
@@ -180,27 +176,32 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
|
||||
if (!parent)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
mux->parent = parent;
|
||||
mux->gpio_base = gpio_base;
|
||||
|
||||
mux->adap = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*mux->adap) * mux->data.n_values,
|
||||
GFP_KERNEL);
|
||||
if (!mux->adap) {
|
||||
dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure");
|
||||
muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, 0, 0,
|
||||
i2c_mux_gpio_select, NULL);
|
||||
if (!muxc) {
|
||||
ret = -ENOMEM;
|
||||
goto alloc_failed;
|
||||
}
|
||||
muxc->priv = mux;
|
||||
|
||||
platform_set_drvdata(pdev, muxc);
|
||||
|
||||
root = i2c_root_adapter(&parent->dev);
|
||||
|
||||
muxc->mux_locked = true;
|
||||
mux->gpio_base = gpio_base;
|
||||
|
||||
if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) {
|
||||
initial_state = mux->data.idle;
|
||||
deselect = i2c_mux_gpio_deselect;
|
||||
muxc->deselect = i2c_mux_gpio_deselect;
|
||||
} else {
|
||||
initial_state = mux->data.values[0];
|
||||
deselect = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < mux->data.n_gpios; i++) {
|
||||
struct device *gpio_dev;
|
||||
struct gpio_desc *gpio_desc;
|
||||
|
||||
ret = gpio_request(gpio_base + mux->data.gpios[i], "i2c-mux-gpio");
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to request GPIO %d\n",
|
||||
@@ -217,17 +218,24 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
|
||||
i++; /* gpio_request above succeeded, so must free */
|
||||
goto err_request_gpio;
|
||||
}
|
||||
|
||||
if (!muxc->mux_locked)
|
||||
continue;
|
||||
|
||||
gpio_desc = gpio_to_desc(gpio_base + mux->data.gpios[i]);
|
||||
gpio_dev = &gpio_desc->gdev->dev;
|
||||
muxc->mux_locked = i2c_root_adapter(gpio_dev) == root;
|
||||
}
|
||||
|
||||
if (muxc->mux_locked)
|
||||
dev_info(&pdev->dev, "mux-locked i2c mux\n");
|
||||
|
||||
for (i = 0; i < mux->data.n_values; i++) {
|
||||
u32 nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0;
|
||||
unsigned int class = mux->data.classes ? mux->data.classes[i] : 0;
|
||||
|
||||
mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr,
|
||||
mux->data.values[i], class,
|
||||
i2c_mux_gpio_select, deselect);
|
||||
if (!mux->adap[i]) {
|
||||
ret = -ENODEV;
|
||||
ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
|
||||
goto add_adapter_failed;
|
||||
}
|
||||
@@ -239,8 +247,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
add_adapter_failed:
|
||||
for (; i > 0; i--)
|
||||
i2c_del_mux_adapter(mux->adap[i - 1]);
|
||||
i2c_mux_del_adapters(muxc);
|
||||
i = mux->data.n_gpios;
|
||||
err_request_gpio:
|
||||
for (; i > 0; i--)
|
||||
@@ -253,16 +260,16 @@ alloc_failed:
|
||||
|
||||
static int i2c_mux_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct gpiomux *mux = platform_get_drvdata(pdev);
|
||||
struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
|
||||
struct gpiomux *mux = i2c_mux_priv(muxc);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mux->data.n_values; i++)
|
||||
i2c_del_mux_adapter(mux->adap[i]);
|
||||
i2c_mux_del_adapters(muxc);
|
||||
|
||||
for (i = 0; i < mux->data.n_gpios; i++)
|
||||
gpio_free(mux->gpio_base + mux->data.gpios[i]);
|
||||
|
||||
i2c_put_adapter(mux->parent);
|
||||
i2c_put_adapter(muxc->parent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
#define SELECT_DELAY_LONG 1000
|
||||
|
||||
struct pca9541 {
|
||||
struct i2c_adapter *mux_adap;
|
||||
struct i2c_client *client;
|
||||
unsigned long select_timeout;
|
||||
unsigned long arb_timeout;
|
||||
};
|
||||
@@ -217,7 +217,8 @@ static const u8 pca9541_control[16] = {
|
||||
*/
|
||||
static int pca9541_arbitrate(struct i2c_client *client)
|
||||
{
|
||||
struct pca9541 *data = i2c_get_clientdata(client);
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct pca9541 *data = i2c_mux_priv(muxc);
|
||||
int reg;
|
||||
|
||||
reg = pca9541_reg_read(client, PCA9541_CONTROL);
|
||||
@@ -285,9 +286,10 @@ static int pca9541_arbitrate(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pca9541_select_chan(struct i2c_adapter *adap, void *client, u32 chan)
|
||||
static int pca9541_select_chan(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
struct pca9541 *data = i2c_get_clientdata(client);
|
||||
struct pca9541 *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = data->client;
|
||||
int ret;
|
||||
unsigned long timeout = jiffies + ARB2_TIMEOUT;
|
||||
/* give up after this time */
|
||||
@@ -309,9 +311,11 @@ static int pca9541_select_chan(struct i2c_adapter *adap, void *client, u32 chan)
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int pca9541_release_chan(struct i2c_adapter *adap,
|
||||
void *client, u32 chan)
|
||||
static int pca9541_release_chan(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
struct pca9541 *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
pca9541_release_bus(client);
|
||||
return 0;
|
||||
}
|
||||
@@ -324,20 +328,13 @@ static int pca9541_probe(struct i2c_client *client,
|
||||
{
|
||||
struct i2c_adapter *adap = client->adapter;
|
||||
struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||
struct i2c_mux_core *muxc;
|
||||
struct pca9541 *data;
|
||||
int force;
|
||||
int ret = -ENODEV;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
goto err;
|
||||
|
||||
data = kzalloc(sizeof(struct pca9541), GFP_KERNEL);
|
||||
if (!data) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* I2C accesses are unprotected here.
|
||||
@@ -352,34 +349,33 @@ static int pca9541_probe(struct i2c_client *client,
|
||||
force = 0;
|
||||
if (pdata)
|
||||
force = pdata->modes[0].adap_id;
|
||||
data->mux_adap = i2c_add_mux_adapter(adap, &client->dev, client,
|
||||
force, 0, 0,
|
||||
pca9541_select_chan,
|
||||
pca9541_release_chan);
|
||||
muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), 0,
|
||||
pca9541_select_chan, pca9541_release_chan);
|
||||
if (!muxc)
|
||||
return -ENOMEM;
|
||||
|
||||
if (data->mux_adap == NULL) {
|
||||
data = i2c_mux_priv(muxc);
|
||||
data->client = client;
|
||||
|
||||
i2c_set_clientdata(client, muxc);
|
||||
|
||||
ret = i2c_mux_add_adapter(muxc, force, 0, 0);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "failed to register master selector\n");
|
||||
goto exit_free;
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "registered master selector for I2C %s\n",
|
||||
client->name);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_free:
|
||||
kfree(data);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pca9541_remove(struct i2c_client *client)
|
||||
{
|
||||
struct pca9541 *data = i2c_get_clientdata(client);
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
|
||||
i2c_del_mux_adapter(data->mux_adap);
|
||||
|
||||
kfree(data);
|
||||
i2c_mux_del_adapters(muxc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,9 +60,10 @@ enum pca_type {
|
||||
|
||||
struct pca954x {
|
||||
enum pca_type type;
|
||||
struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS];
|
||||
|
||||
u8 last_chan; /* last register value */
|
||||
u8 deselect;
|
||||
struct i2c_client *client;
|
||||
};
|
||||
|
||||
struct chip_desc {
|
||||
@@ -146,10 +147,10 @@ static int pca954x_reg_write(struct i2c_adapter *adap,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pca954x_select_chan(struct i2c_adapter *adap,
|
||||
void *client, u32 chan)
|
||||
static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
struct pca954x *data = i2c_get_clientdata(client);
|
||||
struct pca954x *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = data->client;
|
||||
const struct chip_desc *chip = &chips[data->type];
|
||||
u8 regval;
|
||||
int ret = 0;
|
||||
@@ -162,21 +163,24 @@ static int pca954x_select_chan(struct i2c_adapter *adap,
|
||||
|
||||
/* Only select the channel if its different from the last channel */
|
||||
if (data->last_chan != regval) {
|
||||
ret = pca954x_reg_write(adap, client, regval);
|
||||
ret = pca954x_reg_write(muxc->parent, client, regval);
|
||||
data->last_chan = regval;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pca954x_deselect_mux(struct i2c_adapter *adap,
|
||||
void *client, u32 chan)
|
||||
static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
struct pca954x *data = i2c_get_clientdata(client);
|
||||
struct pca954x *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
if (!(data->deselect & (1 << chan)))
|
||||
return 0;
|
||||
|
||||
/* Deselect active channel */
|
||||
data->last_chan = 0;
|
||||
return pca954x_reg_write(adap, client, data->last_chan);
|
||||
return pca954x_reg_write(muxc->parent, client, data->last_chan);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -191,17 +195,22 @@ static int pca954x_probe(struct i2c_client *client,
|
||||
bool idle_disconnect_dt;
|
||||
struct gpio_desc *gpio;
|
||||
int num, force, class;
|
||||
struct i2c_mux_core *muxc;
|
||||
struct pca954x *data;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
|
||||
return -ENODEV;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct pca954x), GFP_KERNEL);
|
||||
if (!data)
|
||||
muxc = i2c_mux_alloc(adap, &client->dev,
|
||||
PCA954X_MAX_NCHANS, sizeof(*data), 0,
|
||||
pca954x_select_chan, pca954x_deselect_mux);
|
||||
if (!muxc)
|
||||
return -ENOMEM;
|
||||
data = i2c_mux_priv(muxc);
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
i2c_set_clientdata(client, muxc);
|
||||
data->client = client;
|
||||
|
||||
/* Get the mux out of reset if a reset GPIO is specified. */
|
||||
gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW);
|
||||
@@ -238,16 +247,13 @@ static int pca954x_probe(struct i2c_client *client,
|
||||
/* discard unconfigured channels */
|
||||
break;
|
||||
idle_disconnect_pd = pdata->modes[num].deselect_on_exit;
|
||||
data->deselect |= (idle_disconnect_pd
|
||||
|| idle_disconnect_dt) << num;
|
||||
}
|
||||
|
||||
data->virt_adaps[num] =
|
||||
i2c_add_mux_adapter(adap, &client->dev, client,
|
||||
force, num, class, pca954x_select_chan,
|
||||
(idle_disconnect_pd || idle_disconnect_dt)
|
||||
? pca954x_deselect_mux : NULL);
|
||||
ret = i2c_mux_add_adapter(muxc, force, num, class);
|
||||
|
||||
if (data->virt_adaps[num] == NULL) {
|
||||
ret = -ENODEV;
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"failed to register multiplexed adapter"
|
||||
" %d as bus %d\n", num, force);
|
||||
@@ -263,23 +269,15 @@ static int pca954x_probe(struct i2c_client *client,
|
||||
return 0;
|
||||
|
||||
virt_reg_failed:
|
||||
for (num--; num >= 0; num--)
|
||||
i2c_del_mux_adapter(data->virt_adaps[num]);
|
||||
i2c_mux_del_adapters(muxc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pca954x_remove(struct i2c_client *client)
|
||||
{
|
||||
struct pca954x *data = i2c_get_clientdata(client);
|
||||
const struct chip_desc *chip = &chips[data->type];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < chip->nchans; ++i)
|
||||
if (data->virt_adaps[i]) {
|
||||
i2c_del_mux_adapter(data->virt_adaps[i]);
|
||||
data->virt_adaps[i] = NULL;
|
||||
}
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
|
||||
i2c_mux_del_adapters(muxc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -287,7 +285,8 @@ static int pca954x_remove(struct i2c_client *client)
|
||||
static int pca954x_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct pca954x *data = i2c_get_clientdata(client);
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct pca954x *data = i2c_mux_priv(muxc);
|
||||
|
||||
data->last_chan = 0;
|
||||
return i2c_smbus_write_byte(client, 0);
|
||||
|
||||
@@ -24,36 +24,32 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include "../../pinctrl/core.h"
|
||||
|
||||
struct i2c_mux_pinctrl {
|
||||
struct device *dev;
|
||||
struct i2c_mux_pinctrl_platform_data *pdata;
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state **states;
|
||||
struct pinctrl_state *state_idle;
|
||||
struct i2c_adapter *parent;
|
||||
struct i2c_adapter **busses;
|
||||
};
|
||||
|
||||
static int i2c_mux_pinctrl_select(struct i2c_adapter *adap, void *data,
|
||||
u32 chan)
|
||||
static int i2c_mux_pinctrl_select(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
struct i2c_mux_pinctrl *mux = data;
|
||||
struct i2c_mux_pinctrl *mux = i2c_mux_priv(muxc);
|
||||
|
||||
return pinctrl_select_state(mux->pinctrl, mux->states[chan]);
|
||||
}
|
||||
|
||||
static int i2c_mux_pinctrl_deselect(struct i2c_adapter *adap, void *data,
|
||||
u32 chan)
|
||||
static int i2c_mux_pinctrl_deselect(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
struct i2c_mux_pinctrl *mux = data;
|
||||
struct i2c_mux_pinctrl *mux = i2c_mux_priv(muxc);
|
||||
|
||||
return pinctrl_select_state(mux->pinctrl, mux->state_idle);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
|
||||
struct platform_device *pdev)
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int num_names, i, ret;
|
||||
@@ -64,15 +60,12 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
|
||||
return 0;
|
||||
|
||||
mux->pdata = devm_kzalloc(&pdev->dev, sizeof(*mux->pdata), GFP_KERNEL);
|
||||
if (!mux->pdata) {
|
||||
dev_err(mux->dev,
|
||||
"Cannot allocate i2c_mux_pinctrl_platform_data\n");
|
||||
if (!mux->pdata)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
num_names = of_property_count_strings(np, "pinctrl-names");
|
||||
if (num_names < 0) {
|
||||
dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
|
||||
dev_err(&pdev->dev, "Cannot parse pinctrl-names: %d\n",
|
||||
num_names);
|
||||
return num_names;
|
||||
}
|
||||
@@ -80,23 +73,22 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
|
||||
mux->pdata->pinctrl_states = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*mux->pdata->pinctrl_states) * num_names,
|
||||
GFP_KERNEL);
|
||||
if (!mux->pdata->pinctrl_states) {
|
||||
dev_err(mux->dev, "Cannot allocate pinctrl_states\n");
|
||||
if (!mux->pdata->pinctrl_states)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_names; i++) {
|
||||
ret = of_property_read_string_index(np, "pinctrl-names", i,
|
||||
&mux->pdata->pinctrl_states[mux->pdata->bus_count]);
|
||||
if (ret < 0) {
|
||||
dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
|
||||
dev_err(&pdev->dev, "Cannot parse pinctrl-names: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
if (!strcmp(mux->pdata->pinctrl_states[mux->pdata->bus_count],
|
||||
"idle")) {
|
||||
if (i != num_names - 1) {
|
||||
dev_err(mux->dev, "idle state must be last\n");
|
||||
dev_err(&pdev->dev,
|
||||
"idle state must be last\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
mux->pdata->pinctrl_state_idle = "idle";
|
||||
@@ -107,13 +99,13 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
|
||||
|
||||
adapter_np = of_parse_phandle(np, "i2c-parent", 0);
|
||||
if (!adapter_np) {
|
||||
dev_err(mux->dev, "Cannot parse i2c-parent\n");
|
||||
dev_err(&pdev->dev, "Cannot parse i2c-parent\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
adapter = of_find_i2c_adapter_by_node(adapter_np);
|
||||
of_node_put(adapter_np);
|
||||
if (!adapter) {
|
||||
dev_err(mux->dev, "Cannot find parent bus\n");
|
||||
dev_err(&pdev->dev, "Cannot find parent bus\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
mux->pdata->parent_bus_num = i2c_adapter_id(adapter);
|
||||
@@ -129,21 +121,38 @@ static inline int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct i2c_adapter *i2c_mux_pinctrl_root_adapter(
|
||||
struct pinctrl_state *state)
|
||||
{
|
||||
struct i2c_adapter *root = NULL;
|
||||
struct pinctrl_setting *setting;
|
||||
struct i2c_adapter *pin_root;
|
||||
|
||||
list_for_each_entry(setting, &state->settings, node) {
|
||||
pin_root = i2c_root_adapter(setting->pctldev->dev);
|
||||
if (!pin_root)
|
||||
return NULL;
|
||||
if (!root)
|
||||
root = pin_root;
|
||||
else if (root != pin_root)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct i2c_mux_core *muxc;
|
||||
struct i2c_mux_pinctrl *mux;
|
||||
int (*deselect)(struct i2c_adapter *, void *, u32);
|
||||
struct i2c_adapter *root;
|
||||
int i, ret;
|
||||
|
||||
mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
|
||||
if (!mux) {
|
||||
dev_err(&pdev->dev, "Cannot allocate i2c_mux_pinctrl\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
platform_set_drvdata(pdev, mux);
|
||||
|
||||
mux->dev = &pdev->dev;
|
||||
|
||||
mux->pdata = dev_get_platdata(&pdev->dev);
|
||||
if (!mux->pdata) {
|
||||
@@ -166,14 +175,15 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
|
||||
goto err;
|
||||
}
|
||||
|
||||
mux->busses = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*mux->busses) * mux->pdata->bus_count,
|
||||
GFP_KERNEL);
|
||||
if (!mux->busses) {
|
||||
dev_err(&pdev->dev, "Cannot allocate busses\n");
|
||||
muxc = i2c_mux_alloc(NULL, &pdev->dev, mux->pdata->bus_count, 0, 0,
|
||||
i2c_mux_pinctrl_select, NULL);
|
||||
if (!muxc) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
muxc->priv = mux;
|
||||
|
||||
platform_set_drvdata(pdev, muxc);
|
||||
|
||||
mux->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
if (IS_ERR(mux->pinctrl)) {
|
||||
@@ -184,13 +194,13 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
|
||||
for (i = 0; i < mux->pdata->bus_count; i++) {
|
||||
mux->states[i] = pinctrl_lookup_state(mux->pinctrl,
|
||||
mux->pdata->pinctrl_states[i]);
|
||||
if (IS_ERR(mux->states[i])) {
|
||||
ret = PTR_ERR(mux->states[i]);
|
||||
dev_err(&pdev->dev,
|
||||
"Cannot look up pinctrl state %s: %d\n",
|
||||
mux->pdata->pinctrl_states[i], ret);
|
||||
goto err;
|
||||
}
|
||||
if (IS_ERR(mux->states[i])) {
|
||||
ret = PTR_ERR(mux->states[i]);
|
||||
dev_err(&pdev->dev,
|
||||
"Cannot look up pinctrl state %s: %d\n",
|
||||
mux->pdata->pinctrl_states[i], ret);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (mux->pdata->pinctrl_state_idle) {
|
||||
mux->state_idle = pinctrl_lookup_state(mux->pinctrl,
|
||||
@@ -203,29 +213,39 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
|
||||
goto err;
|
||||
}
|
||||
|
||||
deselect = i2c_mux_pinctrl_deselect;
|
||||
} else {
|
||||
deselect = NULL;
|
||||
muxc->deselect = i2c_mux_pinctrl_deselect;
|
||||
}
|
||||
|
||||
mux->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
|
||||
if (!mux->parent) {
|
||||
muxc->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
|
||||
if (!muxc->parent) {
|
||||
dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
|
||||
mux->pdata->parent_bus_num);
|
||||
ret = -EPROBE_DEFER;
|
||||
goto err;
|
||||
}
|
||||
|
||||
root = i2c_root_adapter(&muxc->parent->dev);
|
||||
|
||||
muxc->mux_locked = true;
|
||||
for (i = 0; i < mux->pdata->bus_count; i++) {
|
||||
if (root != i2c_mux_pinctrl_root_adapter(mux->states[i])) {
|
||||
muxc->mux_locked = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (muxc->mux_locked && mux->pdata->pinctrl_state_idle &&
|
||||
root != i2c_mux_pinctrl_root_adapter(mux->state_idle))
|
||||
muxc->mux_locked = false;
|
||||
|
||||
if (muxc->mux_locked)
|
||||
dev_info(&pdev->dev, "mux-locked i2c mux\n");
|
||||
|
||||
for (i = 0; i < mux->pdata->bus_count; i++) {
|
||||
u32 bus = mux->pdata->base_bus_num ?
|
||||
(mux->pdata->base_bus_num + i) : 0;
|
||||
|
||||
mux->busses[i] = i2c_add_mux_adapter(mux->parent, &pdev->dev,
|
||||
mux, bus, i, 0,
|
||||
i2c_mux_pinctrl_select,
|
||||
deselect);
|
||||
if (!mux->busses[i]) {
|
||||
ret = -ENODEV;
|
||||
ret = i2c_mux_add_adapter(muxc, bus, i, 0);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
|
||||
goto err_del_adapter;
|
||||
}
|
||||
@@ -234,23 +254,18 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
err_del_adapter:
|
||||
for (; i > 0; i--)
|
||||
i2c_del_mux_adapter(mux->busses[i - 1]);
|
||||
i2c_put_adapter(mux->parent);
|
||||
i2c_mux_del_adapters(muxc);
|
||||
i2c_put_adapter(muxc->parent);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int i2c_mux_pinctrl_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct i2c_mux_pinctrl *mux = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mux->pdata->bus_count; i++)
|
||||
i2c_del_mux_adapter(mux->busses[i]);
|
||||
|
||||
i2c_put_adapter(mux->parent);
|
||||
struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
|
||||
|
||||
i2c_mux_del_adapters(muxc);
|
||||
i2c_put_adapter(muxc->parent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct regmux {
|
||||
struct i2c_adapter *parent;
|
||||
struct i2c_adapter **adap; /* child busses */
|
||||
struct i2c_mux_reg_platform_data data;
|
||||
};
|
||||
|
||||
@@ -64,18 +62,16 @@ static int i2c_mux_reg_set(const struct regmux *mux, unsigned int chan_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_mux_reg_select(struct i2c_adapter *adap, void *data,
|
||||
unsigned int chan)
|
||||
static int i2c_mux_reg_select(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
struct regmux *mux = data;
|
||||
struct regmux *mux = i2c_mux_priv(muxc);
|
||||
|
||||
return i2c_mux_reg_set(mux, chan);
|
||||
}
|
||||
|
||||
static int i2c_mux_reg_deselect(struct i2c_adapter *adap, void *data,
|
||||
unsigned int chan)
|
||||
static int i2c_mux_reg_deselect(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
struct regmux *mux = data;
|
||||
struct regmux *mux = i2c_mux_priv(muxc);
|
||||
|
||||
if (mux->data.idle_in_use)
|
||||
return i2c_mux_reg_set(mux, mux->data.idle);
|
||||
@@ -85,7 +81,7 @@ static int i2c_mux_reg_deselect(struct i2c_adapter *adap, void *data,
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int i2c_mux_reg_probe_dt(struct regmux *mux,
|
||||
struct platform_device *pdev)
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device_node *adapter_np, *child;
|
||||
@@ -107,7 +103,6 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
|
||||
if (!adapter)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
mux->parent = adapter;
|
||||
mux->data.parent = i2c_adapter_id(adapter);
|
||||
put_device(&adapter->dev);
|
||||
|
||||
@@ -161,7 +156,7 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
|
||||
}
|
||||
#else
|
||||
static int i2c_mux_reg_probe_dt(struct regmux *mux,
|
||||
struct platform_device *pdev)
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -169,10 +164,10 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
|
||||
|
||||
static int i2c_mux_reg_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct i2c_mux_core *muxc;
|
||||
struct regmux *mux;
|
||||
struct i2c_adapter *parent;
|
||||
struct resource *res;
|
||||
int (*deselect)(struct i2c_adapter *, void *, u32);
|
||||
unsigned int class;
|
||||
int i, ret, nr;
|
||||
|
||||
@@ -180,17 +175,9 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
|
||||
if (!mux)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, mux);
|
||||
|
||||
if (dev_get_platdata(&pdev->dev)) {
|
||||
memcpy(&mux->data, dev_get_platdata(&pdev->dev),
|
||||
sizeof(mux->data));
|
||||
|
||||
parent = i2c_get_adapter(mux->data.parent);
|
||||
if (!parent)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
mux->parent = parent;
|
||||
} else {
|
||||
ret = i2c_mux_reg_probe_dt(mux, pdev);
|
||||
if (ret < 0) {
|
||||
@@ -199,6 +186,10 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
parent = i2c_get_adapter(mux->data.parent);
|
||||
if (!parent)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
if (!mux->data.reg) {
|
||||
dev_info(&pdev->dev,
|
||||
"Register not set, using platform resource\n");
|
||||
@@ -215,55 +206,45 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mux->adap = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*mux->adap) * mux->data.n_values,
|
||||
GFP_KERNEL);
|
||||
if (!mux->adap) {
|
||||
dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure");
|
||||
muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, 0, 0,
|
||||
i2c_mux_reg_select, NULL);
|
||||
if (!muxc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
muxc->priv = mux;
|
||||
|
||||
platform_set_drvdata(pdev, muxc);
|
||||
|
||||
if (mux->data.idle_in_use)
|
||||
deselect = i2c_mux_reg_deselect;
|
||||
else
|
||||
deselect = NULL;
|
||||
muxc->deselect = i2c_mux_reg_deselect;
|
||||
|
||||
for (i = 0; i < mux->data.n_values; i++) {
|
||||
nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0;
|
||||
class = mux->data.classes ? mux->data.classes[i] : 0;
|
||||
|
||||
mux->adap[i] = i2c_add_mux_adapter(mux->parent, &pdev->dev, mux,
|
||||
nr, mux->data.values[i],
|
||||
class, i2c_mux_reg_select,
|
||||
deselect);
|
||||
if (!mux->adap[i]) {
|
||||
ret = -ENODEV;
|
||||
ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
|
||||
goto add_adapter_failed;
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "%d port mux on %s adapter\n",
|
||||
mux->data.n_values, mux->parent->name);
|
||||
mux->data.n_values, muxc->parent->name);
|
||||
|
||||
return 0;
|
||||
|
||||
add_adapter_failed:
|
||||
for (; i > 0; i--)
|
||||
i2c_del_mux_adapter(mux->adap[i - 1]);
|
||||
i2c_mux_del_adapters(muxc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int i2c_mux_reg_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct regmux *mux = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
|
||||
|
||||
for (i = 0; i < mux->data.n_values; i++)
|
||||
i2c_del_mux_adapter(mux->adap[i]);
|
||||
|
||||
i2c_put_adapter(mux->parent);
|
||||
i2c_mux_del_adapters(muxc);
|
||||
i2c_put_adapter(muxc->parent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user