Commit 78975f23 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents feaa7cb5 73e8b052
...@@ -4,6 +4,12 @@ ...@@ -4,6 +4,12 @@
Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs.
or
compatible: "cavium,octeon-7890-twsi"
Compatibility with cn78XX SOCs.
- reg: The base address of the TWSI/I2C bus controller register bank. - reg: The base address of the TWSI/I2C bus controller register bank.
- #address-cells: Must be <1>. - #address-cells: Must be <1>.
......
...@@ -19,6 +19,9 @@ Optional properties: ...@@ -19,6 +19,9 @@ Optional properties:
- clock-frequency: desired I2C bus clock frequency in Hz. The absence of this - clock-frequency: desired I2C bus clock frequency in Hz. The absence of this
property indicates the default frequency 100 kHz. property indicates the default frequency 100 kHz.
- clocks: clock specifier. - clocks: clock specifier.
- dmas: Must contain a list of two references to DMA specifiers, one for
transmission, and one for reception.
- dma-names: Must contain a list of two DMA names, "tx" and "rx".
- i2c-scl-falling-time-ns: see i2c.txt - i2c-scl-falling-time-ns: see i2c.txt
- i2c-scl-internal-delay-ns: see i2c.txt - i2c-scl-internal-delay-ns: see i2c.txt
......
This diff is collapsed.
...@@ -5348,6 +5348,7 @@ I2C MUXES ...@@ -5348,6 +5348,7 @@ I2C MUXES
M: Peter Rosin <peda@axentia.se> M: Peter Rosin <peda@axentia.se>
L: linux-i2c@vger.kernel.org L: linux-i2c@vger.kernel.org
S: Maintained S: Maintained
F: Documentation/i2c/i2c-topology
F: Documentation/i2c/muxes/ F: Documentation/i2c/muxes/
F: Documentation/devicetree/bindings/i2c/i2c-mux* F: Documentation/devicetree/bindings/i2c/i2c-mux*
F: drivers/i2c/i2c-mux.c F: drivers/i2c/i2c-mux.c
......
...@@ -617,7 +617,7 @@ const struct i2c_algorithm i2c_bit_algo = { ...@@ -617,7 +617,7 @@ const struct i2c_algorithm i2c_bit_algo = {
}; };
EXPORT_SYMBOL(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, .flags = I2C_AQ_NO_CLK_STRETCH,
}; };
......
...@@ -663,7 +663,7 @@ config I2C_MT65XX ...@@ -663,7 +663,7 @@ config I2C_MT65XX
config I2C_MV64XXX config I2C_MV64XXX
tristate "Marvell mv64xxx I2C Controller" tristate "Marvell mv64xxx I2C Controller"
depends on MV64X60 || PLAT_ORION || ARCH_SUNXI depends on MV64X60 || PLAT_ORION || ARCH_SUNXI || ARCH_MVEBU
help help
If you say yes to this option, support will be included for the If you say yes to this option, support will be included for the
built-in I2C interface on the Marvell 64xxx line of host bridges. 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, ...@@ -267,7 +267,7 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
iproc_i2c->msg = msg; iproc_i2c->msg = msg;
/* format and load slave address into the TX FIFO */ /* 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); 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, ...@@ -501,10 +501,7 @@ static int bcm_kona_i2c_do_addr(struct bcm_kona_i2c_dev *dev,
return -EREMOTEIO; return -EREMOTEIO;
} }
} else { } else {
addr = msg->addr << 1; addr = i2c_8bit_addr_from_msg(msg);
if (msg->flags & I2C_M_RD)
addr |= 1;
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0) if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
return -EREMOTEIO; return -EREMOTEIO;
......
...@@ -446,9 +446,7 @@ static int brcmstb_i2c_do_addr(struct brcmstb_i2c_dev *dev, ...@@ -446,9 +446,7 @@ static int brcmstb_i2c_do_addr(struct brcmstb_i2c_dev *dev,
} }
} else { } else {
addr = msg->addr << 1; addr = i2c_8bit_addr_from_msg(msg);
if (msg->flags & I2C_M_RD)
addr |= 1;
bsc_writel(dev, addr, chip_address); bsc_writel(dev, addr, chip_address);
} }
......
...@@ -197,9 +197,7 @@ static void cpm_i2c_parse_message(struct i2c_adapter *adap, ...@@ -197,9 +197,7 @@ static void cpm_i2c_parse_message(struct i2c_adapter *adap,
tbdf = cpm->tbase + tx; tbdf = cpm->tbase + tx;
rbdf = cpm->rbase + rx; rbdf = cpm->rbase + rx;
addr = pmsg->addr << 1; addr = i2c_8bit_addr_from_msg(pmsg);
if (pmsg->flags & I2C_M_RD)
addr |= 1;
tb = cpm->txbuf[tx]; tb = cpm->txbuf[tx];
rb = cpm->rxbuf[rx]; rb = cpm->rxbuf[rx];
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mfd/dln2.h> #include <linux/mfd/dln2.h>
#include <linux/acpi.h>
#define DLN2_I2C_MODULE_ID 0x03 #define DLN2_I2C_MODULE_ID 0x03
#define DLN2_I2C_CMD(cmd) DLN2_CMD(cmd, DLN2_I2C_MODULE_ID) #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) ...@@ -210,6 +211,7 @@ static int dln2_i2c_probe(struct platform_device *pdev)
dln2->adapter.algo = &dln2_i2c_usb_algorithm; dln2->adapter.algo = &dln2_i2c_usb_algorithm;
dln2->adapter.quirks = &dln2_i2c_quirks; dln2->adapter.quirks = &dln2_i2c_quirks;
dln2->adapter.dev.parent = dev; dln2->adapter.dev.parent = dev;
ACPI_COMPANION_SET(&dln2->adapter.dev, ACPI_COMPANION(&pdev->dev));
dln2->adapter.dev.of_node = dev->of_node; dln2->adapter.dev.of_node = dev->of_node;
i2c_set_adapdata(&dln2->adapter, dln2); i2c_set_adapdata(&dln2->adapter, dln2);
snprintf(dln2->adapter.name, sizeof(dln2->adapter.name), "%s-%s-%d", snprintf(dln2->adapter.name, sizeof(dln2->adapter.name), "%s-%s-%d",
......
...@@ -861,14 +861,8 @@ static int exynos5_i2c_resume_noirq(struct device *dev) ...@@ -861,14 +861,8 @@ static int exynos5_i2c_resume_noirq(struct device *dev)
#endif #endif
static const struct dev_pm_ops exynos5_i2c_dev_pm_ops = { static const struct dev_pm_ops exynos5_i2c_dev_pm_ops = {
#ifdef CONFIG_PM_SLEEP SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos5_i2c_suspend_noirq,
.suspend_noirq = exynos5_i2c_suspend_noirq, exynos5_i2c_resume_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
}; };
static struct platform_driver exynos5_i2c_driver = { static struct platform_driver exynos5_i2c_driver = {
......
...@@ -94,6 +94,7 @@ ...@@ -94,6 +94,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/platform_data/itco_wdt.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) && \ #if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \
defined CONFIG_DMI defined CONFIG_DMI
...@@ -714,9 +715,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, ...@@ -714,9 +715,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
{ {
int hwpec; int hwpec;
int block = 0; int block = 0;
int ret, xact = 0; int ret = 0, xact = 0;
struct i801_priv *priv = i2c_get_adapdata(adap); 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) hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
&& size != I2C_SMBUS_QUICK && size != I2C_SMBUS_QUICK
&& size != I2C_SMBUS_I2C_BLOCK_DATA; && size != I2C_SMBUS_I2C_BLOCK_DATA;
...@@ -773,7 +776,8 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, ...@@ -773,7 +776,8 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
default: default:
dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n", dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n",
size); size);
return -EOPNOTSUPP; ret = -EOPNOTSUPP;
goto out;
} }
if (hwpec) /* enable/disable hardware PEC */ if (hwpec) /* enable/disable hardware PEC */
...@@ -796,11 +800,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, ...@@ -796,11 +800,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
if (block) if (block)
return ret; goto out;
if (ret) if (ret)
return ret; goto out;
if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK)) if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
return 0; goto out;
switch (xact & 0x7f) { switch (xact & 0x7f) {
case I801_BYTE: /* Result put in SMBHSTDAT0 */ case I801_BYTE: /* Result put in SMBHSTDAT0 */
...@@ -812,7 +816,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, ...@@ -812,7 +816,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
(inb_p(SMBHSTDAT1(priv)) << 8); (inb_p(SMBHSTDAT1(priv)) << 8);
break; 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) ...@@ -1413,6 +1421,11 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
pci_set_drvdata(dev, priv); 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; return 0;
} }
...@@ -1420,6 +1433,9 @@ static void i801_remove(struct pci_dev *dev) ...@@ -1420,6 +1433,9 @@ static void i801_remove(struct pci_dev *dev)
{ {
struct i801_priv *priv = pci_get_drvdata(dev); struct i801_priv *priv = pci_get_drvdata(dev);
pm_runtime_forbid(&dev->dev);
pm_runtime_get_noresume(&dev->dev);
i801_del_mux(priv); i801_del_mux(priv);
i2c_del_adapter(&priv->adapter); i2c_del_adapter(&priv->adapter);
pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
...@@ -1433,34 +1449,32 @@ static void i801_remove(struct pci_dev *dev) ...@@ -1433,34 +1449,32 @@ static void i801_remove(struct pci_dev *dev)
} }
#ifdef CONFIG_PM #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(pci_dev, SMBHSTCFG, priv->original_hstcfg);
pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
pci_set_power_state(dev, pci_choose_state(dev, mesg));
return 0; 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; return 0;
} }
#else
#define i801_suspend NULL
#define i801_resume NULL
#endif #endif
static UNIVERSAL_DEV_PM_OPS(i801_pm_ops, i801_suspend,
i801_resume, NULL);
static struct pci_driver i801_driver = { static struct pci_driver i801_driver = {
.name = "i801_smbus", .name = "i801_smbus",
.id_table = i801_ids, .id_table = i801_ids,
.probe = i801_probe, .probe = i801_probe,
.remove = i801_remove, .remove = i801_remove,
.suspend = i801_suspend, .driver = {
.resume = i801_resume, .pm = &i801_pm_ops,
},
}; };
static int __init i2c_i801_init(void) 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) ...@@ -269,7 +269,7 @@ static int iic_smbus_quick(struct ibm_iic_private* dev, const struct i2c_msg* p)
ndelay(t->hd_sta); ndelay(t->hd_sta);
/* Send address */ /* 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){ for (i = 0, mask = 0x80; i < 8; ++i, mask >>= 1){
out_8(&iic->directcntl, sda); out_8(&iic->directcntl, sda);
ndelay(t->low / 2); ndelay(t->low / 2);
......
...@@ -751,9 +751,7 @@ static unsigned int img_i2c_atomic(struct img_i2c *i2c, ...@@ -751,9 +751,7 @@ static unsigned int img_i2c_atomic(struct img_i2c *i2c,
switch (i2c->at_cur_cmd) { switch (i2c->at_cur_cmd) {
case CMD_GEN_START: case CMD_GEN_START:
next_cmd = CMD_GEN_DATA; next_cmd = CMD_GEN_DATA;
next_data = (i2c->msg.addr << 1); next_data = i2c_8bit_addr_from_msg(&i2c->msg);
if (i2c->msg.flags & I2C_M_RD)
next_data |= 0x1;
break; break;
case CMD_GEN_DATA: case CMD_GEN_DATA:
if (i2c->line_status & LINESTAT_INPUT_HELD_V) if (i2c->line_status & LINESTAT_INPUT_HELD_V)
......
...@@ -525,7 +525,7 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) ...@@ -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); imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx, IMX_I2C_I2CR);
/* Wait controller to be stable */ /* Wait controller to be stable */
udelay(50); usleep_range(50, 150);
/* Start I2C transaction */ /* Start I2C transaction */
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
......
...@@ -50,10 +50,7 @@ iic_cook_addr(struct i2c_msg *msg) ...@@ -50,10 +50,7 @@ iic_cook_addr(struct i2c_msg *msg)
{ {
unsigned char addr; unsigned char addr;
addr = (msg->addr << 1); addr = i2c_8bit_addr_from_msg(msg);
if (msg->flags & I2C_M_RD)
addr |= 1;
return addr; return addr;
} }
......
...@@ -133,9 +133,7 @@ static void i2c_lpc2k_pump_msg(struct lpc2k_i2c *i2c) ...@@ -133,9 +133,7 @@ static void i2c_lpc2k_pump_msg(struct lpc2k_i2c *i2c)
case M_START: case M_START:
case M_REPSTART: case M_REPSTART:
/* Start bit was just sent out, send out addr and dir */ /* Start bit was just sent out, send out addr and dir */
data = i2c->msg->addr << 1; data = i2c_8bit_addr_from_msg(i2c->msg);
if (i2c->msg->flags & I2C_M_RD)
data |= 1;
writel(data, i2c->base + LPC24XX_I2DAT); writel(data, i2c->base + LPC24XX_I2DAT);
writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONCLR); 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, ...@@ -413,10 +413,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
else else
writew(I2C_FS_START_CON, i2c->base + OFFSET_EXT_CONF); writew(I2C_FS_START_CON, i2c->base + OFFSET_EXT_CONF);
addr_reg = msgs->addr << 1; addr_reg = i2c_8bit_addr_from_msg(msgs);
if (i2c->op == I2C_MASTER_RD)
addr_reg |= 0x1;
writew(addr_reg, i2c->base + OFFSET_SLAVE_ADDR); writew(addr_reg, i2c->base + OFFSET_SLAVE_ADDR);
/* Clear interrupt status */ /* Clear interrupt status */
......
...@@ -134,9 +134,7 @@ struct mv64xxx_i2c_data { ...@@ -134,9 +134,7 @@ struct mv64xxx_i2c_data {
int rc; int rc;
u32 freq_m; u32 freq_m;
u32 freq_n; u32 freq_n;
#if defined(CONFIG_HAVE_CLK)
struct clk *clk; struct clk *clk;
#endif
wait_queue_head_t waitq; wait_queue_head_t waitq;
spinlock_t lock; spinlock_t lock;
struct i2c_msg *msg; struct i2c_msg *msg;
...@@ -757,7 +755,6 @@ static const struct of_device_id mv64xxx_i2c_of_match_table[] = { ...@@ -757,7 +755,6 @@ static const struct of_device_id mv64xxx_i2c_of_match_table[] = {
MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table); MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
#ifdef CONFIG_OF #ifdef CONFIG_OF
#ifdef CONFIG_HAVE_CLK
static int static int
mv64xxx_calc_freq(struct mv64xxx_i2c_data *drv_data, mv64xxx_calc_freq(struct mv64xxx_i2c_data *drv_data,
const int tclk, const int n, const int m) const int tclk, const int n, const int m)
...@@ -791,25 +788,20 @@ mv64xxx_find_baud_factors(struct mv64xxx_i2c_data *drv_data, ...@@ -791,25 +788,20 @@ mv64xxx_find_baud_factors(struct mv64xxx_i2c_data *drv_data,
return false; return false;
return true; return true;
} }
#endif /* CONFIG_HAVE_CLK */
static int static int
mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
struct device *dev) 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; const struct of_device_id *device;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
u32 bus_freq, tclk; u32 bus_freq, tclk;
int rc = 0; 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)) { if (IS_ERR(drv_data->clk)) {
rc = -ENODEV; rc = -ENODEV;
goto out; goto out;
...@@ -869,7 +861,6 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, ...@@ -869,7 +861,6 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
out: out:
return rc; return rc;
#endif
} }
#else /* CONFIG_OF */ #else /* CONFIG_OF */
static int static int
...@@ -907,14 +898,13 @@ mv64xxx_i2c_probe(struct platform_device *pd) ...@@ -907,14 +898,13 @@ mv64xxx_i2c_probe(struct platform_device *pd)
init_waitqueue_head(&drv_data->waitq); init_waitqueue_head(&drv_data->waitq);
spin_lock_init(&drv_data->lock); spin_lock_init(&drv_data->lock);
#if defined(CONFIG_HAVE_CLK)
/* Not all platforms have a clk */ /* Not all platforms have a clk */
drv_data->clk = devm_clk_get(&pd->dev, NULL); drv_data->clk = devm_clk_get(&pd->dev, NULL);
if (!IS_ERR(drv_data->clk)) { if (IS_ERR(drv_data->clk) && PTR_ERR(drv_data->clk) == -EPROBE_DEFER)
clk_prepare(drv_data->clk); return -EPROBE_DEFER;
clk_enable(drv_data->clk); if (!IS_ERR(drv_data->clk))
} clk_prepare_enable(drv_data->clk);
#endif
if (pdata) { if (pdata) {
drv_data->freq_m = pdata->freq_m; drv_data->freq_m = pdata->freq_m;
drv_data->freq_n = pdata->freq_n; drv_data->freq_n = pdata->freq_n;
...@@ -964,13 +954,10 @@ mv64xxx_i2c_probe(struct platform_device *pd) ...@@ -964,13 +954,10 @@ mv64xxx_i2c_probe(struct platform_device *pd)
if (!IS_ERR_OR_NULL(drv_data->rstc)) if (!IS_ERR_OR_NULL(drv_data->rstc))
reset_control_assert(drv_data->rstc); reset_control_assert(drv_data->rstc);
exit_clk: exit_clk:
#if defined(CONFIG_HAVE_CLK)
/* Not all platforms have a clk */ /* Not all platforms have a clk */
if (!IS_ERR(drv_data->clk)) { if (!IS_ERR(drv_data->clk))
clk_disable(drv_data->clk); clk_disable_unprepare(drv_data->clk);
clk_unprepare(drv_data->clk);
}
#endif
return rc; return rc;
} }
...@@ -983,13 +970,9 @@ mv64xxx_i2c_remove(struct platform_device *dev) ...@@ -983,13 +970,9 @@ mv64xxx_i2c_remove(struct platform_device *dev)
free_irq(drv_data->irq, drv_data); free_irq(drv_data->irq, drv_data);
if (!IS_ERR_OR_NULL(drv_data->rstc)) if (!IS_ERR_OR_NULL(drv_data->rstc))
reset_control_assert(drv_data->rstc); reset_control_assert(drv_data->rstc);
#if defined(CONFIG_HAVE_CLK)
/* Not all platforms have a clk */ /* Not all platforms have a clk */
if (!IS_ERR(drv_data->clk)) { if (!IS_ERR(drv_data->clk))
clk_disable(drv_data->clk); clk_disable_unprepare(drv_data->clk);
clk_unprepare(drv_data->clk);
}
#endif
return 0; return 0;
} }
......
...@@ -127,7 +127,7 @@ static struct pci_driver nforce2_driver; ...@@ -127,7 +127,7 @@ static struct pci_driver nforce2_driver;
/* For multiplexing support, we need a global reference to the 1st /* For multiplexing support, we need a global reference to the 1st
SMBus channel */ 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; struct i2c_adapter *nforce2_smbus;
EXPORT_SYMBOL_GPL(nforce2_smbus); EXPORT_SYMBOL_GPL(nforce2_smbus);
......
...@@ -178,10 +178,7 @@ static void ocores_process(struct ocores_i2c *i2c) ...@@ -178,10 +178,7 @@ static void ocores_process(struct ocores_i2c *i2c)
if (i2c->nmsgs) { /* end? */ if (i2c->nmsgs) { /* end? */
/* send start? */ /* send start? */
if (!(msg->flags & I2C_M_NOSTART)) { if (!(msg->flags & I2C_M_NOSTART)) {
u8 addr = (msg->addr << 1); u8 addr = i2c_8bit_addr_from_msg(msg);
if (msg->flags & I2C_M_RD)
addr |= 1;
i2c->state = STATE_START; i2c->state = STATE_START;
......
This diff is collapsed.
...@@ -185,7 +185,6 @@ enum { ...@@ -185,7 +185,6 @@ enum {
#define OMAP_I2C_IP_V2_INTERRUPTS_MASK 0x6FFF #define OMAP_I2C_IP_V2_INTERRUPTS_MASK 0x6FFF
struct omap_i2c_dev { struct omap_i2c_dev {
spinlock_t lock; /* IRQ synchronization */
struct device *dev; struct device *dev;
void __iomem *base; /* virtual */ void __iomem *base; /* virtual */
int irq; int irq;
...@@ -995,15 +994,12 @@ omap_i2c_isr(int irq, void *dev_id) ...@@ -995,15 +994,12 @@ omap_i2c_isr(int irq, void *dev_id)
u16 mask; u16 mask;
u16 stat; 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); stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
if (stat & mask) if (stat & mask)
ret = IRQ_WAKE_THREAD; ret = IRQ_WAKE_THREAD;
spin_unlock(&omap->lock);
return ret; return ret;
} }
...@@ -1011,12 +1007,10 @@ static irqreturn_t ...@@ -1011,12 +1007,10 @@ static irqreturn_t
omap_i2c_isr_thread(int this_irq, void *dev_id) omap_i2c_isr_thread(int this_irq, void *dev_id)
{ {
struct omap_i2c_dev *omap = dev_id; struct omap_i2c_dev *omap = dev_id;
unsigned long flags;
u16 bits; u16 bits;
u16 stat; u16 stat;
int err = 0, count = 0; int err = 0, count = 0;
spin_lock_irqsave(&omap->lock, flags);
do { do {
bits = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG); bits = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_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) ...@@ -1142,8 +1136,6 @@ omap_i2c_isr_thread(int this_irq, void *dev_id)
omap_i2c_complete_cmd(omap, err); omap_i2c_complete_cmd(omap, err);
out: out:
spin_unlock_irqrestore(&omap->lock, flags);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -1330,8 +1322,6 @@ omap_i2c_probe(struct platform_device *pdev) ...@@ -1330,8 +1322,6 @@ omap_i2c_probe(struct platform_device *pdev)
omap->dev = &pdev->dev; omap->dev = &pdev->dev;
omap->irq = irq; omap->irq = irq;
spin_lock_init(&omap->lock);
platform_set_drvdata(pdev, omap); platform_set_drvdata(pdev, omap);
init_completion(&omap->cmd_complete); init_completion(&omap->cmd_complete);
......
...@@ -150,13 +150,11 @@ static int i2c_powermac_master_xfer( struct i2c_adapter *adap, ...@@ -150,13 +150,11 @@ static int i2c_powermac_master_xfer( struct i2c_adapter *adap,
{ {
struct pmac_i2c_bus *bus = i2c_get_adapdata(adap); struct pmac_i2c_bus *bus = i2c_get_adapdata(adap);
int rc = 0; int rc = 0;
int read;
int addrdir; int addrdir;
if (msgs->flags & I2C_M_TEN) if (msgs->flags & I2C_M_TEN)
return -EINVAL; return -EINVAL;
read = (msgs->flags & I2C_M_RD) != 0; addrdir = i2c_8bit_addr_from_msg(msgs);
addrdir = (msgs->addr << 1) | read;
rc = pmac_i2c_open(bus, 0); rc = pmac_i2c_open(bus, 0);
if (rc) { if (rc) {
......
...@@ -515,7 +515,7 @@ static int qup_i2c_get_data_len(struct qup_i2c_dev *qup) ...@@ -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, static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
struct i2c_msg *msg, int is_dma) 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 len = 0;
int data_len; int data_len;
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -43,6 +45,8 @@ ...@@ -43,6 +45,8 @@
#define ICSAR 0x1C /* slave address */ #define ICSAR 0x1C /* slave address */
#define ICMAR 0x20 /* master address */ #define ICMAR 0x20 /* master address */
#define ICRXTX 0x24 /* data port */ #define ICRXTX 0x24 /* data port */
#define ICDMAER 0x3c /* DMA enable */
#define ICFBSCR 0x38 /* first bit setup cycle */
/* ICSCR */ /* ICSCR */
#define SDBS (1 << 3) /* slave data buffer select */ #define SDBS (1 << 3) /* slave data buffer select */
...@@ -78,6 +82,16 @@ ...@@ -78,6 +82,16 @@
#define MDR (1 << 1) #define MDR (1 << 1)
#define MAT (1 << 0) /* slave addr xfer done */ #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_START (MDBS | MIE | ESG)
#define RCAR_BUS_PHASE_DATA (MDBS | MIE) #define RCAR_BUS_PHASE_DATA (MDBS | MIE)
...@@ -120,6 +134,12 @@ struct rcar_i2c_priv { ...@@ -120,6 +134,12 @@ struct rcar_i2c_priv {
u32 flags; u32 flags;
enum rcar_i2c_type devtype; enum rcar_i2c_type devtype;
struct i2c_client *slave; 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) #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) ...@@ -287,6 +307,118 @@ static void rcar_i2c_next_msg(struct rcar_i2c_priv *priv)
/* /*
* interrupt functions * 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) static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
{ {
struct i2c_msg *msg = priv->msg; struct i2c_msg *msg = priv->msg;
...@@ -306,6 +438,12 @@ static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) ...@@ -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]); rcar_i2c_write(priv, ICRXTX, msg->buf[priv->pos]);
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 { } else {
/* /*
* The last data was pushed to ICRXTX on _PREV_ empty irq. * 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) ...@@ -340,7 +478,11 @@ static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
return; return;
if (msr & MAT) { 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) { } else if (priv->pos < msg->len) {
/* get received data */ /* get received data */
msg->buf[priv->pos] = rcar_i2c_read(priv, ICRXTX); msg->buf[priv->pos] = rcar_i2c_read(priv, ICRXTX);
...@@ -472,6 +614,81 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) ...@@ -472,6 +614,81 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
return IRQ_HANDLED; 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, static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, struct i2c_msg *msgs,
int num) int num)
...@@ -493,6 +710,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, ...@@ -493,6 +710,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
goto out; goto out;
} }
rcar_i2c_request_dma(priv, msgs + i);
} }
/* init first message */ /* init first message */
...@@ -504,6 +722,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, ...@@ -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, time_left = wait_event_timeout(priv->wait, priv->flags & ID_DONE,
num * adap->timeout); num * adap->timeout);
if (!time_left) { if (!time_left) {
rcar_i2c_cleanup_dma(priv);
rcar_i2c_init(priv); rcar_i2c_init(priv);
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
} else if (priv->flags & ID_NACK) { } else if (priv->flags & ID_NACK) {
...@@ -591,7 +810,6 @@ static int rcar_i2c_probe(struct platform_device *pdev) ...@@ -591,7 +810,6 @@ static int rcar_i2c_probe(struct platform_device *pdev)
{ {
struct rcar_i2c_priv *priv; struct rcar_i2c_priv *priv;
struct i2c_adapter *adap; struct i2c_adapter *adap;
struct resource *res;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct i2c_timings i2c_t; struct i2c_timings i2c_t;
int irq, ret; int irq, ret;
...@@ -606,8 +824,9 @@ static int rcar_i2c_probe(struct platform_device *pdev) ...@@ -606,8 +824,9 @@ static int rcar_i2c_probe(struct platform_device *pdev)
return PTR_ERR(priv->clk); return PTR_ERR(priv->clk);
} }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->io = devm_ioremap_resource(dev, res);
priv->io = devm_ioremap_resource(dev, priv->res);
if (IS_ERR(priv->io)) if (IS_ERR(priv->io))
return PTR_ERR(priv->io); return PTR_ERR(priv->io);
...@@ -626,6 +845,11 @@ static int rcar_i2c_probe(struct platform_device *pdev) ...@@ -626,6 +845,11 @@ static int rcar_i2c_probe(struct platform_device *pdev)
i2c_parse_fw_timings(dev, &i2c_t, false); 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_enable(dev);
pm_runtime_get_sync(dev); pm_runtime_get_sync(dev);
ret = rcar_i2c_clock_calculate(priv, &i2c_t); ret = rcar_i2c_clock_calculate(priv, &i2c_t);
...@@ -673,6 +897,7 @@ static int rcar_i2c_remove(struct platform_device *pdev) ...@@ -673,6 +897,7 @@ static int rcar_i2c_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
i2c_del_adapter(&priv->adap); i2c_del_adapter(&priv->adap);
rcar_i2c_release_dma(priv);
if (priv->flags & ID_P_PM_BLOCKED) if (priv->flags & ID_P_PM_BLOCKED)
pm_runtime_put(dev); pm_runtime_put(dev);
pm_runtime_disable(dev); pm_runtime_disable(dev);
......
...@@ -101,10 +101,7 @@ struct rk3x_i2c { ...@@ -101,10 +101,7 @@ struct rk3x_i2c {
struct notifier_block clk_rate_nb; struct notifier_block clk_rate_nb;
/* Settings */ /* Settings */
unsigned int scl_frequency; struct i2c_timings t;
unsigned int scl_rise_ns;
unsigned int scl_fall_ns;
unsigned int sda_fall_ns;
/* Synchronization & notification */ /* Synchronization & notification */
spinlock_t lock; spinlock_t lock;
...@@ -437,10 +434,7 @@ static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id) ...@@ -437,10 +434,7 @@ static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id)
* Calculate divider values for desired SCL frequency * Calculate divider values for desired SCL frequency
* *
* @clk_rate: I2C input clock rate * @clk_rate: I2C input clock rate
* @scl_rate: Desired SCL rate * @t: Known I2C timing information.
* @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.
* @div_low: Divider output for low * @div_low: Divider output for low
* @div_high: Divider output for high * @div_high: Divider output for high
* *
...@@ -448,11 +442,10 @@ static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id) ...@@ -448,11 +442,10 @@ static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id)
* a best-effort divider value is returned in divs. If the target rate is * a best-effort divider value is returned in divs. If the target rate is
* too high, we silently use the highest possible rate. * too high, we silently use the highest possible rate.
*/ */
static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate, static int rk3x_i2c_calc_divs(unsigned long clk_rate,
unsigned long scl_rise_ns, struct i2c_timings *t,
unsigned long scl_fall_ns, unsigned long *div_low,
unsigned long sda_fall_ns, unsigned long *div_high)
unsigned long *div_low, unsigned long *div_high)
{ {
unsigned long spec_min_low_ns, spec_min_high_ns; unsigned long spec_min_low_ns, spec_min_high_ns;
unsigned long spec_setup_start, spec_max_data_hold_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, ...@@ -472,12 +465,12 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
int ret = 0; int ret = 0;
/* Only support standard-mode and fast-mode */ /* Only support standard-mode and fast-mode */
if (WARN_ON(scl_rate > 400000)) if (WARN_ON(t->bus_freq_hz > 400000))
scl_rate = 400000; t->bus_freq_hz = 400000;
/* prevent scl_rate_khz from becoming 0 */ /* prevent scl_rate_khz from becoming 0 */
if (WARN_ON(scl_rate < 1000)) if (WARN_ON(t->bus_freq_hz < 1000))
scl_rate = 1000; t->bus_freq_hz = 1000;
/* /*
* min_low_ns: The minimum number of ns we need to hold low to * 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, ...@@ -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 * This is because the i2c host on Rockchip holds the data line
* for half the low time. * for half the low time.
*/ */
if (scl_rate <= 100000) { if (t->bus_freq_hz <= 100000) {
/* Standard-mode */ /* Standard-mode */
spec_min_low_ns = 4700; spec_min_low_ns = 4700;
spec_setup_start = 4700; spec_setup_start = 4700;
...@@ -506,7 +499,7 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate, ...@@ -506,7 +499,7 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
spec_max_data_hold_ns = 900; spec_max_data_hold_ns = 900;
data_hold_buffer_ns = 50; 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: * Timings for repeated start:
...@@ -517,18 +510,18 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate, ...@@ -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. * we meet tSU;STA and tHD;STA times.
*/ */
min_high_ns = max(min_high_ns, min_high_ns = max(min_high_ns,
DIV_ROUND_UP((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, min_high_ns = max(min_high_ns,
DIV_ROUND_UP((scl_rise_ns + spec_setup_start + DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start +
sda_fall_ns + spec_min_high_ns), 2)); 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; max_low_ns = spec_max_data_hold_ns * 2 - data_hold_buffer_ns;
min_total_ns = min_low_ns + min_high_ns; min_total_ns = min_low_ns + min_high_ns;
/* Adjust to avoid overflow */ /* Adjust to avoid overflow */
clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000); 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 * 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, ...@@ -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) 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; unsigned long div_low, div_high;
u64 t_low_ns, t_high_ns; u64 t_low_ns, t_high_ns;
int ret; int ret;
ret = rk3x_i2c_calc_divs(clk_rate, i2c->scl_frequency, i2c->scl_rise_ns, ret = rk3x_i2c_calc_divs(clk_rate, t, &div_low, &div_high);
i2c->scl_fall_ns, i2c->sda_fall_ns, WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
&div_low, &div_high);
WARN_ONCE(ret != 0, "Could not reach SCL freq %u", i2c->scl_frequency);
clk_enable(i2c->clk); clk_enable(i2c->clk);
i2c_writel(i2c, (div_high << 16) | (div_low & 0xffff), REG_CLKDIV); 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) ...@@ -634,7 +626,7 @@ static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
dev_dbg(i2c->dev, dev_dbg(i2c->dev,
"CLK %lukhz, Req %uns, Act low %lluns high %lluns\n", "CLK %lukhz, Req %uns, Act low %lluns high %lluns\n",
clk_rate / 1000, clk_rate / 1000,
1000000000 / i2c->scl_frequency, 1000000000 / t->bus_freq_hz,
t_low_ns, t_high_ns); t_low_ns, t_high_ns);
} }
...@@ -664,9 +656,7 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long ...@@ -664,9 +656,7 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
switch (event) { switch (event) {
case PRE_RATE_CHANGE: case PRE_RATE_CHANGE:
if (rk3x_i2c_calc_divs(ndata->new_rate, i2c->scl_frequency, if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t,
i2c->scl_rise_ns, i2c->scl_fall_ns,
i2c->sda_fall_ns,
&div_low, &div_high) != 0) &div_low, &div_high) != 0)
return NOTIFY_STOP; return NOTIFY_STOP;
...@@ -880,37 +870,8 @@ static int rk3x_i2c_probe(struct platform_device *pdev) ...@@ -880,37 +870,8 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
match = of_match_node(rk3x_i2c_match, np); match = of_match_node(rk3x_i2c_match, np);
i2c->soc_data = (struct rk3x_i2c_soc_data *)match->data; i2c->soc_data = (struct rk3x_i2c_soc_data *)match->data;
if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", /* use common interface to get I2C timing properties */
&i2c->scl_frequency)) { i2c_parse_fw_timings(&pdev->dev, &i2c->t, true);
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;
strlcpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name)); strlcpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name));
i2c->adap.owner = THIS_MODULE; i2c->adap.owner = THIS_MODULE;
......
This diff is collapsed.
...@@ -398,8 +398,7 @@ static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd, ...@@ -398,8 +398,7 @@ static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd,
{ {
switch (pd->pos) { switch (pd->pos) {
case -1: case -1:
*buf = (pd->msg->addr & 0x7f) << 1; *buf = i2c_8bit_addr_from_msg(pd->msg);
*buf |= (pd->msg->flags & I2C_M_RD) ? 1 : 0;
break; break;
default: default:
*buf = pd->msg->buf[pd->pos]; *buf = pd->msg->buf[pd->pos];
......
...@@ -190,9 +190,7 @@ static void i2c_sirfsoc_set_address(struct sirfsoc_i2c *siic, ...@@ -190,9 +190,7 @@ static void i2c_sirfsoc_set_address(struct sirfsoc_i2c *siic,
writel(regval, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++)); writel(regval, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
addr = msg->addr << 1; /* Generate address */ addr = i2c_8bit_addr_from_msg(msg);
if (msg->flags & I2C_M_RD)
addr |= 1;
/* Reverse direction bit */ /* Reverse direction bit */
if (msg->flags & I2C_M_REV_DIR_ADDR) if (msg->flags & I2C_M_REV_DIR_ADDR)
......
...@@ -337,10 +337,42 @@ static void st_i2c_hw_config(struct st_i2c_dev *i2c_dev) ...@@ -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); 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) static int st_i2c_wait_free_bus(struct st_i2c_dev *i2c_dev)
{ {
u32 sta; u32 sta;
int i; int i, ret;
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
sta = readl_relaxed(i2c_dev->base + SSC_STA); 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) ...@@ -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); 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; return -EBUSY;
} }
...@@ -614,8 +652,7 @@ static int st_i2c_xfer_msg(struct st_i2c_dev *i2c_dev, struct i2c_msg *msg, ...@@ -614,8 +652,7 @@ static int st_i2c_xfer_msg(struct st_i2c_dev *i2c_dev, struct i2c_msg *msg,
unsigned long timeout; unsigned long timeout;
int ret; int ret;
c->addr = (u8)(msg->addr << 1); c->addr = i2c_8bit_addr_from_msg(msg);
c->addr |= (msg->flags & I2C_M_RD);
c->buf = msg->buf; c->buf = msg->buf;
c->count = msg->len; c->count = msg->len;
c->xfered = 0; c->xfered = 0;
...@@ -744,6 +781,10 @@ static struct i2c_algorithm st_i2c_algo = { ...@@ -744,6 +781,10 @@ static struct i2c_algorithm st_i2c_algo = {
.functionality = st_i2c_func, .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, static int st_i2c_of_get_deglitch(struct device_node *np,
struct st_i2c_dev *i2c_dev) struct st_i2c_dev *i2c_dev)
{ {
...@@ -826,6 +867,7 @@ static int st_i2c_probe(struct platform_device *pdev) ...@@ -826,6 +867,7 @@ static int st_i2c_probe(struct platform_device *pdev)
adap->timeout = 2 * HZ; adap->timeout = 2 * HZ;
adap->retries = 0; adap->retries = 0;
adap->algo = &st_i2c_algo; adap->algo = &st_i2c_algo;
adap->bus_recovery_info = &st_i2c_recovery_info;
adap->dev.parent = &pdev->dev; adap->dev.parent = &pdev->dev;
adap->dev.of_node = pdev->dev.of_node; adap->dev.of_node = pdev->dev.of_node;
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12 #define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12
#define I2C_CNFG_PACKET_MODE_EN (1<<10) #define I2C_CNFG_PACKET_MODE_EN (1<<10)
#define I2C_CNFG_NEW_MASTER_FSM (1<<11) #define I2C_CNFG_NEW_MASTER_FSM (1<<11)
#define I2C_CNFG_MULTI_MASTER_MODE (1<<17)
#define I2C_STATUS 0x01C #define I2C_STATUS 0x01C
#define I2C_SL_CNFG 0x020 #define I2C_SL_CNFG 0x020
#define I2C_SL_CNFG_NACK (1<<1) #define I2C_SL_CNFG_NACK (1<<1)
...@@ -106,6 +107,9 @@ ...@@ -106,6 +107,9 @@
#define I2C_SLV_CONFIG_LOAD (1 << 1) #define I2C_SLV_CONFIG_LOAD (1 << 1)
#define I2C_TIMEOUT_CONFIG_LOAD (1 << 2) #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_type: The bus control which need to be send at end of transfer.
* @MSG_END_STOP: Send stop pulse at end of transfer. * @MSG_END_STOP: Send stop pulse at end of transfer.
...@@ -143,6 +147,8 @@ struct tegra_i2c_hw_feature { ...@@ -143,6 +147,8 @@ struct tegra_i2c_hw_feature {
int clk_divisor_hs_mode; int clk_divisor_hs_mode;
int clk_divisor_std_fast_mode; int clk_divisor_std_fast_mode;
u16 clk_divisor_fast_plus_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 { ...@@ -184,6 +190,7 @@ struct tegra_i2c_dev {
u32 bus_clk_rate; u32 bus_clk_rate;
u16 clk_divisor_non_hs_mode; u16 clk_divisor_non_hs_mode;
bool is_suspended; bool is_suspended;
bool is_multimaster_mode;
}; };
static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned long reg) 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) ...@@ -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 | val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN |
(0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); (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, val, I2C_CNFG);
i2c_writel(i2c_dev, 0, I2C_INT_MASK); i2c_writel(i2c_dev, 0, I2C_INT_MASK);
...@@ -463,25 +474,29 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) ...@@ -463,25 +474,29 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
if (tegra_i2c_flush_fifos(i2c_dev)) if (tegra_i2c_flush_fifos(i2c_dev))
err = -ETIMEDOUT; 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) { if (i2c_dev->hw->has_config_load_reg) {
i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD); i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD);
while (i2c_readl(i2c_dev, I2C_CONFIG_LOAD) != 0) { while (i2c_readl(i2c_dev, I2C_CONFIG_LOAD) != 0) {
if (time_after(jiffies, timeout)) { if (time_after(jiffies, timeout)) {
dev_warn(i2c_dev->dev, dev_warn(i2c_dev->dev,
"timeout waiting for config load\n"); "timeout waiting for config load\n");
return -ETIMEDOUT; err = -ETIMEDOUT;
goto err;
} }
msleep(1); msleep(1);
} }
} }
tegra_i2c_clock_disable(i2c_dev);
if (i2c_dev->irq_disabled) { if (i2c_dev->irq_disabled) {
i2c_dev->irq_disabled = 0; i2c_dev->irq_disabled = 0;
enable_irq(i2c_dev->irq); enable_irq(i2c_dev->irq);
} }
err:
tegra_i2c_clock_disable(i2c_dev);
return err; return err;
} }
...@@ -688,6 +703,20 @@ static u32 tegra_i2c_func(struct i2c_adapter *adap) ...@@ -688,6 +703,20 @@ static u32 tegra_i2c_func(struct i2c_adapter *adap)
return ret; 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 = { static const struct i2c_algorithm tegra_i2c_algo = {
.master_xfer = tegra_i2c_xfer, .master_xfer = tegra_i2c_xfer,
.functionality = tegra_i2c_func, .functionality = tegra_i2c_func,
...@@ -707,6 +736,8 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { ...@@ -707,6 +736,8 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
.clk_divisor_std_fast_mode = 0, .clk_divisor_std_fast_mode = 0,
.clk_divisor_fast_plus_mode = 0, .clk_divisor_fast_plus_mode = 0,
.has_config_load_reg = false, .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 = { static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
...@@ -717,6 +748,8 @@ 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_std_fast_mode = 0,
.clk_divisor_fast_plus_mode = 0, .clk_divisor_fast_plus_mode = 0,
.has_config_load_reg = false, .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 = { static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
...@@ -727,6 +760,8 @@ 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_std_fast_mode = 0x19,
.clk_divisor_fast_plus_mode = 0x10, .clk_divisor_fast_plus_mode = 0x10,
.has_config_load_reg = false, .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 = { static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
...@@ -737,10 +772,25 @@ 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_std_fast_mode = 0x19,
.clk_divisor_fast_plus_mode = 0x10, .clk_divisor_fast_plus_mode = 0x10,
.has_config_load_reg = true, .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 */ /* Match table for of_platform binding */
static const struct of_device_id tegra_i2c_of_match[] = { 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,tegra124-i2c", .data = &tegra124_i2c_hw, },
{ .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, }, { .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, },
{ .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, }, { .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, },
...@@ -797,10 +847,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) ...@@ -797,10 +847,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
return PTR_ERR(i2c_dev->rst); return PTR_ERR(i2c_dev->rst);
} }
ret = of_property_read_u32(i2c_dev->dev->of_node, "clock-frequency", tegra_i2c_parse_dt(i2c_dev);
&i2c_dev->bus_clk_rate);
if (ret)
i2c_dev->bus_clk_rate = 100000; /* default clock rate */
i2c_dev->hw = &tegra20_i2c_hw; i2c_dev->hw = &tegra20_i2c_hw;
...@@ -853,6 +900,15 @@ static int tegra_i2c_probe(struct platform_device *pdev) ...@@ -853,6 +900,15 @@ static int tegra_i2c_probe(struct platform_device *pdev)
goto unprepare_fast_clk; 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); ret = tegra_i2c_init(i2c_dev);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to initialize i2c controller"); dev_err(&pdev->dev, "Failed to initialize i2c controller");
...@@ -863,7 +919,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) ...@@ -863,7 +919,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev); tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq); 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); i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
...@@ -878,11 +934,15 @@ static int tegra_i2c_probe(struct platform_device *pdev) ...@@ -878,11 +934,15 @@ static int tegra_i2c_probe(struct platform_device *pdev)
ret = i2c_add_numbered_adapter(&i2c_dev->adapter); ret = i2c_add_numbered_adapter(&i2c_dev->adapter);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to add I2C adapter\n"); dev_err(&pdev->dev, "Failed to add I2C adapter\n");
goto unprepare_div_clk; goto disable_div_clk;
} }
return 0; return 0;
disable_div_clk:
if (i2c_dev->is_multimaster_mode)
clk_disable(i2c_dev->div_clk);
unprepare_div_clk: unprepare_div_clk:
clk_unprepare(i2c_dev->div_clk); clk_unprepare(i2c_dev->div_clk);
...@@ -898,6 +958,9 @@ static int tegra_i2c_remove(struct platform_device *pdev) ...@@ -898,6 +958,9 @@ static int tegra_i2c_remove(struct platform_device *pdev)
struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev); struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
i2c_del_adapter(&i2c_dev->adapter); i2c_del_adapter(&i2c_dev->adapter);
if (i2c_dev->is_multimaster_mode)
clk_disable(i2c_dev->div_clk);
clk_unprepare(i2c_dev->div_clk); clk_unprepare(i2c_dev->div_clk);
if (!i2c_dev->hw->has_single_clk_source) if (!i2c_dev->hw->has_single_clk_source)
clk_unprepare(i2c_dev->fast_clk); clk_unprepare(i2c_dev->fast_clk);
......
...@@ -524,7 +524,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev) ...@@ -524,7 +524,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0) {
dev_err(dev, "failed to get IRQ number"); dev_err(dev, "failed to get IRQ number\n");
return irq; return irq;
} }
......
...@@ -381,7 +381,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev) ...@@ -381,7 +381,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0) {
dev_err(dev, "failed to get IRQ number"); dev_err(dev, "failed to get IRQ number\n");
return irq; return irq;
} }
......
...@@ -954,48 +954,40 @@ static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr) ...@@ -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 * @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); 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 * i2c_adapter_trylock_bus - Try to get exclusive access to an I2C bus segment
* @adapter: Target 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
*/ */
static int i2c_trylock_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)
return i2c_trylock_adapter(parent);
else
return rt_mutex_trylock(&adapter->bus_lock); return rt_mutex_trylock(&adapter->bus_lock);
} }
/** /**
* i2c_unlock_adapter - Release exclusive access to an I2C bus segment * i2c_adapter_unlock_bus - Release exclusive access to an I2C bus segment
* @adapter: Target 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
*/ */
void i2c_unlock_adapter(struct i2c_adapter *adapter) static void i2c_adapter_unlock_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); rt_mutex_unlock(&adapter->bus_lock);
} }
EXPORT_SYMBOL_GPL(i2c_unlock_adapter);
static void i2c_dev_set_name(struct i2c_adapter *adap, static void i2c_dev_set_name(struct i2c_adapter *adap,
struct i2c_client *client) struct i2c_client *client)
...@@ -1541,7 +1533,14 @@ static int i2c_register_adapter(struct i2c_adapter *adap) ...@@ -1541,7 +1533,14 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
return -EINVAL; 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->bus_lock);
rt_mutex_init(&adap->mux_lock);
mutex_init(&adap->userspace_clients_lock); mutex_init(&adap->userspace_clients_lock);
INIT_LIST_HEAD(&adap->userspace_clients); INIT_LIST_HEAD(&adap->userspace_clients);
...@@ -1559,6 +1558,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) ...@@ -1559,6 +1558,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
pm_runtime_no_callbacks(&adap->dev); pm_runtime_no_callbacks(&adap->dev);
pm_suspend_ignore_children(&adap->dev, true);
pm_runtime_enable(&adap->dev); pm_runtime_enable(&adap->dev);
#ifdef CONFIG_I2C_COMPAT #ifdef CONFIG_I2C_COMPAT
...@@ -1594,12 +1594,14 @@ static int i2c_register_adapter(struct i2c_adapter *adap) ...@@ -1594,12 +1594,14 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
bri->get_scl = get_scl_gpio_value; bri->get_scl = get_scl_gpio_value;
bri->set_scl = set_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 */ /* Generic SCL recovery */
dev_err(&adap->dev, "No {get|set}_gpio() found, not using recovery\n"); 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; adap->bus_recovery_info = NULL;
} }
} }
}
exit_recovery: exit_recovery:
/* create pre-declared device nodes */ /* create pre-declared device nodes */
...@@ -2309,16 +2311,16 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) ...@@ -2309,16 +2311,16 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
#endif #endif
if (in_atomic() || irqs_disabled()) { if (in_atomic() || irqs_disabled()) {
ret = i2c_trylock_adapter(adap); ret = adap->trylock_bus(adap, I2C_LOCK_SEGMENT);
if (!ret) if (!ret)
/* I2C activity is ongoing. */ /* I2C activity is ongoing. */
return -EAGAIN; return -EAGAIN;
} else { } else {
i2c_lock_adapter(adap); i2c_lock_bus(adap, I2C_LOCK_SEGMENT);
} }
ret = __i2c_transfer(adap, msgs, num); ret = __i2c_transfer(adap, msgs, num);
i2c_unlock_adapter(adap); i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);
return ret; return ret;
} else { } else {
...@@ -2646,7 +2648,7 @@ static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count) ...@@ -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) static u8 i2c_smbus_msg_pec(u8 pec, struct i2c_msg *msg)
{ {
/* The address will be sent first */ /* 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); pec = i2c_smbus_pec(pec, &addr, 1);
/* The data buffer follows */ /* The data buffer follows */
...@@ -3093,7 +3095,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, ...@@ -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; flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB;
if (adapter->algo->smbus_xfer) { if (adapter->algo->smbus_xfer) {
i2c_lock_adapter(adapter); i2c_lock_bus(adapter, I2C_LOCK_SEGMENT);
/* Retry automatically on arbitration loss */ /* Retry automatically on arbitration loss */
orig_jiffies = jiffies; orig_jiffies = jiffies;
...@@ -3107,7 +3109,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, ...@@ -3107,7 +3109,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
orig_jiffies + adapter->timeout)) orig_jiffies + adapter->timeout))
break; break;
} }
i2c_unlock_adapter(adapter); i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT);
if (res != -EOPNOTSUPP || !adapter->algo->master_xfer) if (res != -EOPNOTSUPP || !adapter->algo->master_xfer)
goto trace; goto trace;
......
This diff is collapsed.
...@@ -28,8 +28,6 @@ ...@@ -28,8 +28,6 @@
/** /**
* struct i2c_arbitrator_data - Driver data for I2C arbitrator * 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: GPIO we'll use to claim.
* @our_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO == * @our_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO ==
* this then consider it released. * this then consider it released.
...@@ -42,8 +40,6 @@ ...@@ -42,8 +40,6 @@
*/ */
struct i2c_arbitrator_data { struct i2c_arbitrator_data {
struct i2c_adapter *parent;
struct i2c_adapter *child;
int our_gpio; int our_gpio;
int our_gpio_release; int our_gpio_release;
int their_gpio; int their_gpio;
...@@ -59,9 +55,9 @@ struct i2c_arbitrator_data { ...@@ -59,9 +55,9 @@ struct i2c_arbitrator_data {
* *
* Use the GPIO-based signalling protocol; return -EBUSY if we fail. * 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; unsigned long stop_retry, stop_time;
/* Start a round of trying to claim the bus */ /* 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) ...@@ -93,7 +89,7 @@ static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan)
/* Give up, release our claim */ /* Give up, release our claim */
gpio_set_value(arb->our_gpio, arb->our_gpio_release); gpio_set_value(arb->our_gpio, arb->our_gpio_release);
udelay(arb->slew_delay_us); 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; return -EBUSY;
} }
...@@ -102,10 +98,9 @@ static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan) ...@@ -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. * Release the I2C bus using the GPIO-based signalling protocol.
*/ */
static int i2c_arbitrator_deselect(struct i2c_adapter *adap, void *data, static int i2c_arbitrator_deselect(struct i2c_mux_core *muxc, u32 chan)
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 */ /* Release the bus and wait for the other master to notice */
gpio_set_value(arb->our_gpio, arb->our_gpio_release); gpio_set_value(arb->our_gpio, arb->our_gpio_release);
...@@ -119,6 +114,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev) ...@@ -119,6 +114,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
struct device_node *parent_np; struct device_node *parent_np;
struct i2c_mux_core *muxc;
struct i2c_arbitrator_data *arb; struct i2c_arbitrator_data *arb;
enum of_gpio_flags gpio_flags; enum of_gpio_flags gpio_flags;
unsigned long out_init; unsigned long out_init;
...@@ -134,12 +130,13 @@ static int i2c_arbitrator_probe(struct platform_device *pdev) ...@@ -134,12 +130,13 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL); muxc = i2c_mux_alloc(NULL, dev, 1, sizeof(*arb), 0,
if (!arb) { i2c_arbitrator_select, i2c_arbitrator_deselect);
dev_err(dev, "Cannot allocate i2c_arbitrator_data\n"); if (!muxc)
return -ENOMEM; return -ENOMEM;
} arb = i2c_mux_priv(muxc);
platform_set_drvdata(pdev, arb);
platform_set_drvdata(pdev, muxc);
/* Request GPIOs */ /* Request GPIOs */
ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags); 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) ...@@ -196,21 +193,18 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
dev_err(dev, "Cannot parse i2c-parent\n"); dev_err(dev, "Cannot parse i2c-parent\n");
return -EINVAL; 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); of_node_put(parent_np);
if (!arb->parent) { if (!muxc->parent) {
dev_err(dev, "Cannot find parent bus\n"); dev_err(dev, "Cannot find parent bus\n");
return -EPROBE_DEFER; return -EPROBE_DEFER;
} }
/* Actually add the mux adapter */ /* Actually add the mux adapter */
arb->child = i2c_add_mux_adapter(arb->parent, dev, arb, 0, 0, 0, ret = i2c_mux_add_adapter(muxc, 0, 0, 0);
i2c_arbitrator_select, if (ret) {
i2c_arbitrator_deselect);
if (!arb->child) {
dev_err(dev, "Failed to add adapter\n"); dev_err(dev, "Failed to add adapter\n");
ret = -ENODEV; i2c_put_adapter(muxc->parent);
i2c_put_adapter(arb->parent);
} }
return ret; return ret;
...@@ -218,11 +212,10 @@ static int i2c_arbitrator_probe(struct platform_device *pdev) ...@@ -218,11 +212,10 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
static int i2c_arbitrator_remove(struct platform_device *pdev) static int i2c_arbitrator_remove(struct platform_device *pdev)
{ {
struct i2c_arbitrator_data *arb = platform_get_drvdata(pdev); struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
i2c_del_mux_adapter(arb->child);
i2c_put_adapter(arb->parent);
i2c_mux_del_adapters(muxc);
i2c_put_adapter(muxc->parent);
return 0; return 0;
} }
......
...@@ -15,11 +15,10 @@ ...@@ -15,11 +15,10 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include "../../gpio/gpiolib.h"
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
struct gpiomux { struct gpiomux {
struct i2c_adapter *parent;
struct i2c_adapter **adap; /* child busses */
struct i2c_mux_gpio_platform_data data; struct i2c_mux_gpio_platform_data data;
unsigned gpio_base; unsigned gpio_base;
}; };
...@@ -33,18 +32,18 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val) ...@@ -33,18 +32,18 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val)
val & (1 << i)); 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); i2c_mux_gpio_set(mux, chan);
return 0; 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); i2c_mux_gpio_set(mux, mux->data.idle);
...@@ -136,19 +135,16 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux, ...@@ -136,19 +135,16 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
static int i2c_mux_gpio_probe(struct platform_device *pdev) static int i2c_mux_gpio_probe(struct platform_device *pdev)
{ {
struct i2c_mux_core *muxc;
struct gpiomux *mux; struct gpiomux *mux;
struct i2c_adapter *parent; struct i2c_adapter *parent;
int (*deselect) (struct i2c_adapter *, void *, u32); struct i2c_adapter *root;
unsigned initial_state, gpio_base; unsigned initial_state, gpio_base;
int i, ret; int i, ret;
mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
if (!mux) { if (!mux)
dev_err(&pdev->dev, "Cannot allocate gpiomux structure");
return -ENOMEM; return -ENOMEM;
}
platform_set_drvdata(pdev, mux);
if (!dev_get_platdata(&pdev->dev)) { if (!dev_get_platdata(&pdev->dev)) {
ret = i2c_mux_gpio_probe_dt(mux, pdev); ret = i2c_mux_gpio_probe_dt(mux, pdev);
...@@ -180,27 +176,32 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) ...@@ -180,27 +176,32 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
if (!parent) if (!parent)
return -EPROBE_DEFER; return -EPROBE_DEFER;
mux->parent = parent; muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, 0, 0,
mux->gpio_base = gpio_base; i2c_mux_gpio_select, NULL);
if (!muxc) {
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");
ret = -ENOMEM; ret = -ENOMEM;
goto alloc_failed; 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) { if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) {
initial_state = mux->data.idle; initial_state = mux->data.idle;
deselect = i2c_mux_gpio_deselect; muxc->deselect = i2c_mux_gpio_deselect;
} else { } else {
initial_state = mux->data.values[0]; initial_state = mux->data.values[0];
deselect = NULL;
} }
for (i = 0; i < mux->data.n_gpios; i++) { 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"); ret = gpio_request(gpio_base + mux->data.gpios[i], "i2c-mux-gpio");
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to request GPIO %d\n", dev_err(&pdev->dev, "Failed to request GPIO %d\n",
...@@ -217,17 +218,24 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) ...@@ -217,17 +218,24 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
i++; /* gpio_request above succeeded, so must free */ i++; /* gpio_request above succeeded, so must free */
goto err_request_gpio; 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++) { for (i = 0; i < mux->data.n_values; i++) {
u32 nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0; u32 nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0;
unsigned int class = mux->data.classes ? mux->data.classes[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, ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class);
mux->data.values[i], class, if (ret) {
i2c_mux_gpio_select, deselect);
if (!mux->adap[i]) {
ret = -ENODEV;
dev_err(&pdev->dev, "Failed to add adapter %d\n", i); dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
goto add_adapter_failed; goto add_adapter_failed;
} }
...@@ -239,8 +247,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) ...@@ -239,8 +247,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
return 0; return 0;
add_adapter_failed: add_adapter_failed:
for (; i > 0; i--) i2c_mux_del_adapters(muxc);
i2c_del_mux_adapter(mux->adap[i - 1]);
i = mux->data.n_gpios; i = mux->data.n_gpios;
err_request_gpio: err_request_gpio:
for (; i > 0; i--) for (; i > 0; i--)
...@@ -253,16 +260,16 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) ...@@ -253,16 +260,16 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
static int i2c_mux_gpio_remove(struct platform_device *pdev) 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; int i;
for (i = 0; i < mux->data.n_values; i++) i2c_mux_del_adapters(muxc);
i2c_del_mux_adapter(mux->adap[i]);
for (i = 0; i < mux->data.n_gpios; i++) for (i = 0; i < mux->data.n_gpios; i++)
gpio_free(mux->gpio_base + mux->data.gpios[i]); gpio_free(mux->gpio_base + mux->data.gpios[i]);
i2c_put_adapter(mux->parent); i2c_put_adapter(muxc->parent);
return 0; return 0;
} }
......
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
#define SELECT_DELAY_LONG 1000 #define SELECT_DELAY_LONG 1000
struct pca9541 { struct pca9541 {
struct i2c_adapter *mux_adap; struct i2c_client *client;
unsigned long select_timeout; unsigned long select_timeout;
unsigned long arb_timeout; unsigned long arb_timeout;
}; };
...@@ -217,7 +217,8 @@ static const u8 pca9541_control[16] = { ...@@ -217,7 +217,8 @@ static const u8 pca9541_control[16] = {
*/ */
static int pca9541_arbitrate(struct i2c_client *client) 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; int reg;
reg = pca9541_reg_read(client, PCA9541_CONTROL); reg = pca9541_reg_read(client, PCA9541_CONTROL);
...@@ -285,9 +286,10 @@ static int pca9541_arbitrate(struct i2c_client *client) ...@@ -285,9 +286,10 @@ static int pca9541_arbitrate(struct i2c_client *client)
return 0; 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; int ret;
unsigned long timeout = jiffies + ARB2_TIMEOUT; unsigned long timeout = jiffies + ARB2_TIMEOUT;
/* give up after this time */ /* give up after this time */
...@@ -309,9 +311,11 @@ static int pca9541_select_chan(struct i2c_adapter *adap, void *client, u32 chan) ...@@ -309,9 +311,11 @@ static int pca9541_select_chan(struct i2c_adapter *adap, void *client, u32 chan)
return -ETIMEDOUT; return -ETIMEDOUT;
} }
static int pca9541_release_chan(struct i2c_adapter *adap, static int pca9541_release_chan(struct i2c_mux_core *muxc, u32 chan)
void *client, u32 chan)
{ {
struct pca9541 *data = i2c_mux_priv(muxc);
struct i2c_client *client = data->client;
pca9541_release_bus(client); pca9541_release_bus(client);
return 0; return 0;
} }
...@@ -324,20 +328,13 @@ static int pca9541_probe(struct i2c_client *client, ...@@ -324,20 +328,13 @@ static int pca9541_probe(struct i2c_client *client,
{ {
struct i2c_adapter *adap = client->adapter; struct i2c_adapter *adap = client->adapter;
struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev); struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
struct i2c_mux_core *muxc;
struct pca9541 *data; struct pca9541 *data;
int force; int force;
int ret = -ENODEV; int ret;
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA)) if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA))
goto err; return -ENODEV;
data = kzalloc(sizeof(struct pca9541), GFP_KERNEL);
if (!data) {
ret = -ENOMEM;
goto err;
}
i2c_set_clientdata(client, data);
/* /*
* I2C accesses are unprotected here. * I2C accesses are unprotected here.
...@@ -352,34 +349,33 @@ static int pca9541_probe(struct i2c_client *client, ...@@ -352,34 +349,33 @@ static int pca9541_probe(struct i2c_client *client,
force = 0; force = 0;
if (pdata) if (pdata)
force = pdata->modes[0].adap_id; force = pdata->modes[0].adap_id;
data->mux_adap = i2c_add_mux_adapter(adap, &client->dev, client, muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), 0,
force, 0, 0, pca9541_select_chan, pca9541_release_chan);
pca9541_select_chan, if (!muxc)
pca9541_release_chan); return -ENOMEM;
data = i2c_mux_priv(muxc);
data->client = client;
if (data->mux_adap == NULL) { 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"); 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", dev_info(&client->dev, "registered master selector for I2C %s\n",
client->name); client->name);
return 0; return 0;
exit_free:
kfree(data);
err:
return ret;
} }
static int pca9541_remove(struct i2c_client *client) 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; return 0;
} }
......
...@@ -60,9 +60,10 @@ enum pca_type { ...@@ -60,9 +60,10 @@ enum pca_type {
struct pca954x { struct pca954x {
enum pca_type type; enum pca_type type;
struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS];
u8 last_chan; /* last register value */ u8 last_chan; /* last register value */
u8 deselect;
struct i2c_client *client;
}; };
struct chip_desc { struct chip_desc {
...@@ -146,10 +147,10 @@ static int pca954x_reg_write(struct i2c_adapter *adap, ...@@ -146,10 +147,10 @@ static int pca954x_reg_write(struct i2c_adapter *adap,
return ret; return ret;
} }
static int pca954x_select_chan(struct i2c_adapter *adap, static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
void *client, 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]; const struct chip_desc *chip = &chips[data->type];
u8 regval; u8 regval;
int ret = 0; int ret = 0;
...@@ -162,21 +163,24 @@ static int pca954x_select_chan(struct i2c_adapter *adap, ...@@ -162,21 +163,24 @@ static int pca954x_select_chan(struct i2c_adapter *adap,
/* Only select the channel if its different from the last channel */ /* Only select the channel if its different from the last channel */
if (data->last_chan != regval) { if (data->last_chan != regval) {
ret = pca954x_reg_write(adap, client, regval); ret = pca954x_reg_write(muxc->parent, client, regval);
data->last_chan = regval; data->last_chan = regval;
} }
return ret; return ret;
} }
static int pca954x_deselect_mux(struct i2c_adapter *adap, static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
void *client, 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 */ /* Deselect active channel */
data->last_chan = 0; 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, ...@@ -191,17 +195,22 @@ static int pca954x_probe(struct i2c_client *client,
bool idle_disconnect_dt; bool idle_disconnect_dt;
struct gpio_desc *gpio; struct gpio_desc *gpio;
int num, force, class; int num, force, class;
struct i2c_mux_core *muxc;
struct pca954x *data; struct pca954x *data;
int ret; int ret;
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
return -ENODEV; return -ENODEV;
data = devm_kzalloc(&client->dev, sizeof(struct pca954x), GFP_KERNEL); muxc = i2c_mux_alloc(adap, &client->dev,
if (!data) PCA954X_MAX_NCHANS, sizeof(*data), 0,
pca954x_select_chan, pca954x_deselect_mux);
if (!muxc)
return -ENOMEM; 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. */ /* Get the mux out of reset if a reset GPIO is specified. */
gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW); gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW);
...@@ -238,16 +247,13 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -238,16 +247,13 @@ static int pca954x_probe(struct i2c_client *client,
/* discard unconfigured channels */ /* discard unconfigured channels */
break; break;
idle_disconnect_pd = pdata->modes[num].deselect_on_exit; idle_disconnect_pd = pdata->modes[num].deselect_on_exit;
data->deselect |= (idle_disconnect_pd
|| idle_disconnect_dt) << num;
} }
data->virt_adaps[num] = ret = i2c_mux_add_adapter(muxc, force, num, class);
i2c_add_mux_adapter(adap, &client->dev, client,
force, num, class, pca954x_select_chan,
(idle_disconnect_pd || idle_disconnect_dt)
? pca954x_deselect_mux : NULL);
if (data->virt_adaps[num] == NULL) { if (ret) {
ret = -ENODEV;
dev_err(&client->dev, dev_err(&client->dev,
"failed to register multiplexed adapter" "failed to register multiplexed adapter"
" %d as bus %d\n", num, force); " %d as bus %d\n", num, force);
...@@ -263,23 +269,15 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -263,23 +269,15 @@ static int pca954x_probe(struct i2c_client *client,
return 0; return 0;
virt_reg_failed: virt_reg_failed:
for (num--; num >= 0; num--) i2c_mux_del_adapters(muxc);
i2c_del_mux_adapter(data->virt_adaps[num]);
return ret; return ret;
} }
static int pca954x_remove(struct i2c_client *client) static int pca954x_remove(struct i2c_client *client)
{ {
struct pca954x *data = i2c_get_clientdata(client); struct i2c_mux_core *muxc = 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;
}
i2c_mux_del_adapters(muxc);
return 0; return 0;
} }
...@@ -287,7 +285,8 @@ static int pca954x_remove(struct i2c_client *client) ...@@ -287,7 +285,8 @@ static int pca954x_remove(struct i2c_client *client)
static int pca954x_resume(struct device *dev) static int pca954x_resume(struct device *dev)
{ {
struct i2c_client *client = to_i2c_client(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; data->last_chan = 0;
return i2c_smbus_write_byte(client, 0); return i2c_smbus_write_byte(client, 0);
......
...@@ -24,29 +24,25 @@ ...@@ -24,29 +24,25 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of.h> #include <linux/of.h>
#include "../../pinctrl/core.h"
struct i2c_mux_pinctrl { struct i2c_mux_pinctrl {
struct device *dev;
struct i2c_mux_pinctrl_platform_data *pdata; struct i2c_mux_pinctrl_platform_data *pdata;
struct pinctrl *pinctrl; struct pinctrl *pinctrl;
struct pinctrl_state **states; struct pinctrl_state **states;
struct pinctrl_state *state_idle; 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, static int i2c_mux_pinctrl_select(struct i2c_mux_core *muxc, u32 chan)
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]); return pinctrl_select_state(mux->pinctrl, mux->states[chan]);
} }
static int i2c_mux_pinctrl_deselect(struct i2c_adapter *adap, void *data, static int i2c_mux_pinctrl_deselect(struct i2c_mux_core *muxc, u32 chan)
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); return pinctrl_select_state(mux->pinctrl, mux->state_idle);
} }
...@@ -64,15 +60,12 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux, ...@@ -64,15 +60,12 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
return 0; return 0;
mux->pdata = devm_kzalloc(&pdev->dev, sizeof(*mux->pdata), GFP_KERNEL); mux->pdata = devm_kzalloc(&pdev->dev, sizeof(*mux->pdata), GFP_KERNEL);
if (!mux->pdata) { if (!mux->pdata)
dev_err(mux->dev,
"Cannot allocate i2c_mux_pinctrl_platform_data\n");
return -ENOMEM; return -ENOMEM;
}
num_names = of_property_count_strings(np, "pinctrl-names"); num_names = of_property_count_strings(np, "pinctrl-names");
if (num_names < 0) { 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); num_names);
return num_names; return num_names;
} }
...@@ -80,23 +73,22 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux, ...@@ -80,23 +73,22 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
mux->pdata->pinctrl_states = devm_kzalloc(&pdev->dev, mux->pdata->pinctrl_states = devm_kzalloc(&pdev->dev,
sizeof(*mux->pdata->pinctrl_states) * num_names, sizeof(*mux->pdata->pinctrl_states) * num_names,
GFP_KERNEL); GFP_KERNEL);
if (!mux->pdata->pinctrl_states) { if (!mux->pdata->pinctrl_states)
dev_err(mux->dev, "Cannot allocate pinctrl_states\n");
return -ENOMEM; return -ENOMEM;
}
for (i = 0; i < num_names; i++) { for (i = 0; i < num_names; i++) {
ret = of_property_read_string_index(np, "pinctrl-names", i, ret = of_property_read_string_index(np, "pinctrl-names", i,
&mux->pdata->pinctrl_states[mux->pdata->bus_count]); &mux->pdata->pinctrl_states[mux->pdata->bus_count]);
if (ret < 0) { if (ret < 0) {
dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n", dev_err(&pdev->dev, "Cannot parse pinctrl-names: %d\n",
ret); ret);
return ret; return ret;
} }
if (!strcmp(mux->pdata->pinctrl_states[mux->pdata->bus_count], if (!strcmp(mux->pdata->pinctrl_states[mux->pdata->bus_count],
"idle")) { "idle")) {
if (i != num_names - 1) { 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; return -EINVAL;
} }
mux->pdata->pinctrl_state_idle = "idle"; mux->pdata->pinctrl_state_idle = "idle";
...@@ -107,13 +99,13 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux, ...@@ -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); adapter_np = of_parse_phandle(np, "i2c-parent", 0);
if (!adapter_np) { if (!adapter_np) {
dev_err(mux->dev, "Cannot parse i2c-parent\n"); dev_err(&pdev->dev, "Cannot parse i2c-parent\n");
return -ENODEV; return -ENODEV;
} }
adapter = of_find_i2c_adapter_by_node(adapter_np); adapter = of_find_i2c_adapter_by_node(adapter_np);
of_node_put(adapter_np); of_node_put(adapter_np);
if (!adapter) { if (!adapter) {
dev_err(mux->dev, "Cannot find parent bus\n"); dev_err(&pdev->dev, "Cannot find parent bus\n");
return -EPROBE_DEFER; return -EPROBE_DEFER;
} }
mux->pdata->parent_bus_num = i2c_adapter_id(adapter); 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, ...@@ -129,21 +121,38 @@ static inline int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
} }
#endif #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) static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
{ {
struct i2c_mux_core *muxc;
struct i2c_mux_pinctrl *mux; struct i2c_mux_pinctrl *mux;
int (*deselect)(struct i2c_adapter *, void *, u32); struct i2c_adapter *root;
int i, ret; int i, ret;
mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
if (!mux) { if (!mux) {
dev_err(&pdev->dev, "Cannot allocate i2c_mux_pinctrl\n");
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;
} }
platform_set_drvdata(pdev, mux);
mux->dev = &pdev->dev;
mux->pdata = dev_get_platdata(&pdev->dev); mux->pdata = dev_get_platdata(&pdev->dev);
if (!mux->pdata) { if (!mux->pdata) {
...@@ -166,14 +175,15 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev) ...@@ -166,14 +175,15 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
goto err; goto err;
} }
mux->busses = devm_kzalloc(&pdev->dev, muxc = i2c_mux_alloc(NULL, &pdev->dev, mux->pdata->bus_count, 0, 0,
sizeof(*mux->busses) * mux->pdata->bus_count, i2c_mux_pinctrl_select, NULL);
GFP_KERNEL); if (!muxc) {
if (!mux->busses) {
dev_err(&pdev->dev, "Cannot allocate busses\n");
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;
} }
muxc->priv = mux;
platform_set_drvdata(pdev, muxc);
mux->pinctrl = devm_pinctrl_get(&pdev->dev); mux->pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(mux->pinctrl)) { if (IS_ERR(mux->pinctrl)) {
...@@ -203,29 +213,39 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev) ...@@ -203,29 +213,39 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
goto err; goto err;
} }
deselect = i2c_mux_pinctrl_deselect; muxc->deselect = i2c_mux_pinctrl_deselect;
} else {
deselect = NULL;
} }
mux->parent = i2c_get_adapter(mux->pdata->parent_bus_num); muxc->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
if (!mux->parent) { if (!muxc->parent) {
dev_err(&pdev->dev, "Parent adapter (%d) not found\n", dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
mux->pdata->parent_bus_num); mux->pdata->parent_bus_num);
ret = -EPROBE_DEFER; ret = -EPROBE_DEFER;
goto err; 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++) { for (i = 0; i < mux->pdata->bus_count; i++) {
u32 bus = mux->pdata->base_bus_num ? u32 bus = mux->pdata->base_bus_num ?
(mux->pdata->base_bus_num + i) : 0; (mux->pdata->base_bus_num + i) : 0;
mux->busses[i] = i2c_add_mux_adapter(mux->parent, &pdev->dev, ret = i2c_mux_add_adapter(muxc, bus, i, 0);
mux, bus, i, 0, if (ret) {
i2c_mux_pinctrl_select,
deselect);
if (!mux->busses[i]) {
ret = -ENODEV;
dev_err(&pdev->dev, "Failed to add adapter %d\n", i); dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
goto err_del_adapter; goto err_del_adapter;
} }
...@@ -234,23 +254,18 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev) ...@@ -234,23 +254,18 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
return 0; return 0;
err_del_adapter: err_del_adapter:
for (; i > 0; i--) i2c_mux_del_adapters(muxc);
i2c_del_mux_adapter(mux->busses[i - 1]); i2c_put_adapter(muxc->parent);
i2c_put_adapter(mux->parent);
err: err:
return ret; return ret;
} }
static int i2c_mux_pinctrl_remove(struct platform_device *pdev) static int i2c_mux_pinctrl_remove(struct platform_device *pdev)
{ {
struct i2c_mux_pinctrl *mux = platform_get_drvdata(pdev); struct i2c_mux_core *muxc = 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);
i2c_mux_del_adapters(muxc);
i2c_put_adapter(muxc->parent);
return 0; return 0;
} }
......
...@@ -21,8 +21,6 @@ ...@@ -21,8 +21,6 @@
#include <linux/slab.h> #include <linux/slab.h>
struct regmux { struct regmux {
struct i2c_adapter *parent;
struct i2c_adapter **adap; /* child busses */
struct i2c_mux_reg_platform_data data; 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) ...@@ -64,18 +62,16 @@ static int i2c_mux_reg_set(const struct regmux *mux, unsigned int chan_id)
return 0; return 0;
} }
static int i2c_mux_reg_select(struct i2c_adapter *adap, void *data, static int i2c_mux_reg_select(struct i2c_mux_core *muxc, u32 chan)
unsigned int chan)
{ {
struct regmux *mux = data; struct regmux *mux = i2c_mux_priv(muxc);
return i2c_mux_reg_set(mux, chan); return i2c_mux_reg_set(mux, chan);
} }
static int i2c_mux_reg_deselect(struct i2c_adapter *adap, void *data, static int i2c_mux_reg_deselect(struct i2c_mux_core *muxc, u32 chan)
unsigned int chan)
{ {
struct regmux *mux = data; struct regmux *mux = i2c_mux_priv(muxc);
if (mux->data.idle_in_use) if (mux->data.idle_in_use)
return i2c_mux_reg_set(mux, mux->data.idle); return i2c_mux_reg_set(mux, mux->data.idle);
...@@ -107,7 +103,6 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux, ...@@ -107,7 +103,6 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
if (!adapter) if (!adapter)
return -EPROBE_DEFER; return -EPROBE_DEFER;
mux->parent = adapter;
mux->data.parent = i2c_adapter_id(adapter); mux->data.parent = i2c_adapter_id(adapter);
put_device(&adapter->dev); put_device(&adapter->dev);
...@@ -169,10 +164,10 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux, ...@@ -169,10 +164,10 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
static int i2c_mux_reg_probe(struct platform_device *pdev) static int i2c_mux_reg_probe(struct platform_device *pdev)
{ {
struct i2c_mux_core *muxc;
struct regmux *mux; struct regmux *mux;
struct i2c_adapter *parent; struct i2c_adapter *parent;
struct resource *res; struct resource *res;
int (*deselect)(struct i2c_adapter *, void *, u32);
unsigned int class; unsigned int class;
int i, ret, nr; int i, ret, nr;
...@@ -180,17 +175,9 @@ static int i2c_mux_reg_probe(struct platform_device *pdev) ...@@ -180,17 +175,9 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
if (!mux) if (!mux)
return -ENOMEM; return -ENOMEM;
platform_set_drvdata(pdev, mux);
if (dev_get_platdata(&pdev->dev)) { if (dev_get_platdata(&pdev->dev)) {
memcpy(&mux->data, dev_get_platdata(&pdev->dev), memcpy(&mux->data, dev_get_platdata(&pdev->dev),
sizeof(mux->data)); sizeof(mux->data));
parent = i2c_get_adapter(mux->data.parent);
if (!parent)
return -EPROBE_DEFER;
mux->parent = parent;
} else { } else {
ret = i2c_mux_reg_probe_dt(mux, pdev); ret = i2c_mux_reg_probe_dt(mux, pdev);
if (ret < 0) { if (ret < 0) {
...@@ -199,6 +186,10 @@ static int i2c_mux_reg_probe(struct platform_device *pdev) ...@@ -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) { if (!mux->data.reg) {
dev_info(&pdev->dev, dev_info(&pdev->dev,
"Register not set, using platform resource\n"); "Register not set, using platform resource\n");
...@@ -215,55 +206,45 @@ static int i2c_mux_reg_probe(struct platform_device *pdev) ...@@ -215,55 +206,45 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
mux->adap = devm_kzalloc(&pdev->dev, muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, 0, 0,
sizeof(*mux->adap) * mux->data.n_values, i2c_mux_reg_select, NULL);
GFP_KERNEL); if (!muxc)
if (!mux->adap) {
dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure");
return -ENOMEM; return -ENOMEM;
} muxc->priv = mux;
platform_set_drvdata(pdev, muxc);
if (mux->data.idle_in_use) if (mux->data.idle_in_use)
deselect = i2c_mux_reg_deselect; muxc->deselect = i2c_mux_reg_deselect;
else
deselect = NULL;
for (i = 0; i < mux->data.n_values; i++) { for (i = 0; i < mux->data.n_values; i++) {
nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0; nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0;
class = mux->data.classes ? mux->data.classes[i] : 0; class = mux->data.classes ? mux->data.classes[i] : 0;
mux->adap[i] = i2c_add_mux_adapter(mux->parent, &pdev->dev, mux, ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class);
nr, mux->data.values[i], if (ret) {
class, i2c_mux_reg_select,
deselect);
if (!mux->adap[i]) {
ret = -ENODEV;
dev_err(&pdev->dev, "Failed to add adapter %d\n", i); dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
goto add_adapter_failed; goto add_adapter_failed;
} }
} }
dev_dbg(&pdev->dev, "%d port mux on %s adapter\n", 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; return 0;
add_adapter_failed: add_adapter_failed:
for (; i > 0; i--) i2c_mux_del_adapters(muxc);
i2c_del_mux_adapter(mux->adap[i - 1]);
return ret; return ret;
} }
static int i2c_mux_reg_remove(struct platform_device *pdev) static int i2c_mux_reg_remove(struct platform_device *pdev)
{ {
struct regmux *mux = platform_get_drvdata(pdev); struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
int i;
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; return 0;
} }
......
...@@ -183,7 +183,7 @@ int inv_mpu_acpi_create_mux_client(struct i2c_client *client) ...@@ -183,7 +183,7 @@ int inv_mpu_acpi_create_mux_client(struct i2c_client *client)
} else } else
return 0; /* no secondary addr, which is OK */ return 0; /* no secondary addr, which is OK */
} }
st->mux_client = i2c_new_device(st->mux_adapter, &info); st->mux_client = i2c_new_device(st->muxc->adapter[0], &info);
if (!st->mux_client) if (!st->mux_client)
return -ENODEV; return -ENODEV;
} }
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include <linux/kfifo.h> #include <linux/kfifo.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/i2c-mux.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include "inv_mpu_iio.h" #include "inv_mpu_iio.h"
......
This diff is collapsed.
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/kfifo.h> #include <linux/kfifo.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
...@@ -127,7 +128,7 @@ struct inv_mpu6050_state { ...@@ -127,7 +128,7 @@ struct inv_mpu6050_state {
const struct inv_mpu6050_hw *hw; const struct inv_mpu6050_hw *hw;
enum inv_devices chip_type; enum inv_devices chip_type;
spinlock_t time_stamp_lock; spinlock_t time_stamp_lock;
struct i2c_adapter *mux_adapter; struct i2c_mux_core *muxc;
struct i2c_client *mux_client; struct i2c_client *mux_client;
unsigned int powerup_count; unsigned int powerup_count;
struct inv_mpu6050_platform_data plat_data; struct inv_mpu6050_platform_data plat_data;
......
...@@ -1251,9 +1251,9 @@ static void m88ds3103_release(struct dvb_frontend *fe) ...@@ -1251,9 +1251,9 @@ static void m88ds3103_release(struct dvb_frontend *fe)
i2c_unregister_device(client); i2c_unregister_device(client);
} }
static int m88ds3103_select(struct i2c_adapter *adap, void *mux_priv, u32 chan) static int m88ds3103_select(struct i2c_mux_core *muxc, u32 chan)
{ {
struct m88ds3103_dev *dev = mux_priv; struct m88ds3103_dev *dev = i2c_mux_priv(muxc);
struct i2c_client *client = dev->client; struct i2c_client *client = dev->client;
int ret; int ret;
struct i2c_msg msg = { struct i2c_msg msg = {
...@@ -1374,7 +1374,7 @@ static struct i2c_adapter *m88ds3103_get_i2c_adapter(struct i2c_client *client) ...@@ -1374,7 +1374,7 @@ static struct i2c_adapter *m88ds3103_get_i2c_adapter(struct i2c_client *client)
dev_dbg(&client->dev, "\n"); dev_dbg(&client->dev, "\n");
return dev->i2c_adapter; return dev->muxc->adapter[0];
} }
static int m88ds3103_probe(struct i2c_client *client, static int m88ds3103_probe(struct i2c_client *client,
...@@ -1467,13 +1467,16 @@ static int m88ds3103_probe(struct i2c_client *client, ...@@ -1467,13 +1467,16 @@ static int m88ds3103_probe(struct i2c_client *client,
goto err_kfree; goto err_kfree;
/* create mux i2c adapter for tuner */ /* create mux i2c adapter for tuner */
dev->i2c_adapter = i2c_add_mux_adapter(client->adapter, &client->dev, dev->muxc = i2c_mux_alloc(client->adapter, &client->dev, 1, 0, 0,
dev, 0, 0, 0, m88ds3103_select, m88ds3103_select, NULL);
NULL); if (!dev->muxc) {
if (dev->i2c_adapter == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_kfree; goto err_kfree;
} }
dev->muxc->priv = dev;
ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0);
if (ret)
goto err_kfree;
/* create dvb_frontend */ /* create dvb_frontend */
memcpy(&dev->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops)); memcpy(&dev->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops));
...@@ -1502,7 +1505,7 @@ static int m88ds3103_remove(struct i2c_client *client) ...@@ -1502,7 +1505,7 @@ static int m88ds3103_remove(struct i2c_client *client)
dev_dbg(&client->dev, "\n"); dev_dbg(&client->dev, "\n");
i2c_del_mux_adapter(dev->i2c_adapter); i2c_mux_del_adapters(dev->muxc);
kfree(dev); kfree(dev);
return 0; return 0;
......
...@@ -42,7 +42,7 @@ struct m88ds3103_dev { ...@@ -42,7 +42,7 @@ struct m88ds3103_dev {
enum fe_status fe_status; enum fe_status fe_status;
u32 dvbv3_ber; /* for old DVBv3 API read_ber */ u32 dvbv3_ber; /* for old DVBv3 API read_ber */
bool warm; /* FW running */ bool warm; /* FW running */
struct i2c_adapter *i2c_adapter; struct i2c_mux_core *muxc;
/* auto detect chip id to do different config */ /* auto detect chip id to do different config */
u8 chip_id; u8 chip_id;
/* main mclk is calculated for M88RS6000 dynamically */ /* main mclk is calculated for M88RS6000 dynamically */
......
This diff is collapsed.
...@@ -29,7 +29,7 @@ struct rtl2830_dev { ...@@ -29,7 +29,7 @@ struct rtl2830_dev {
struct rtl2830_platform_data *pdata; struct rtl2830_platform_data *pdata;
struct i2c_client *client; struct i2c_client *client;
struct regmap *regmap; struct regmap *regmap;
struct i2c_adapter *adapter; struct i2c_mux_core *muxc;
struct dvb_frontend fe; struct dvb_frontend fe;
bool sleeping; bool sleeping;
unsigned long filters; unsigned long filters;
......
This diff is collapsed.
...@@ -57,9 +57,7 @@ struct rtl2832_platform_data { ...@@ -57,9 +57,7 @@ struct rtl2832_platform_data {
int (*pid_filter)(struct dvb_frontend *, u8, u16, int); int (*pid_filter)(struct dvb_frontend *, u8, u16, int);
int (*pid_filter_ctrl)(struct dvb_frontend *, int); int (*pid_filter_ctrl)(struct dvb_frontend *, int);
/* private: Register access for SDR module use only */ /* private: Register access for SDR module use only */
int (*bulk_read)(struct i2c_client *, unsigned int, void *, size_t); struct regmap *regmap;
int (*bulk_write)(struct i2c_client *, unsigned int, const void *, size_t);
int (*update_bits)(struct i2c_client *, unsigned int, unsigned int, unsigned int);
}; };
#endif /* RTL2832_H */ #endif /* RTL2832_H */
...@@ -33,10 +33,9 @@ ...@@ -33,10 +33,9 @@
struct rtl2832_dev { struct rtl2832_dev {
struct rtl2832_platform_data *pdata; struct rtl2832_platform_data *pdata;
struct i2c_client *client; struct i2c_client *client;
struct mutex regmap_mutex;
struct regmap_config regmap_config; struct regmap_config regmap_config;
struct regmap *regmap; struct regmap *regmap;
struct i2c_adapter *i2c_adapter_tuner; struct i2c_mux_core *muxc;
struct dvb_frontend fe; struct dvb_frontend fe;
enum fe_status fe_status; enum fe_status fe_status;
u64 post_bit_error_prev; /* for old DVBv3 read_ber() calculation */ u64 post_bit_error_prev; /* for old DVBv3 read_ber() calculation */
......
This diff is collapsed.
...@@ -56,10 +56,7 @@ struct rtl2832_sdr_platform_data { ...@@ -56,10 +56,7 @@ struct rtl2832_sdr_platform_data {
#define RTL2832_SDR_TUNER_R828D 0x2b #define RTL2832_SDR_TUNER_R828D 0x2b
u8 tuner; u8 tuner;
struct i2c_client *i2c_client; struct regmap *regmap;
int (*bulk_read)(struct i2c_client *, unsigned int, void *, size_t);
int (*bulk_write)(struct i2c_client *, unsigned int, const void *, size_t);
int (*update_bits)(struct i2c_client *, unsigned int, unsigned int, unsigned int);
struct dvb_frontend *dvb_frontend; struct dvb_frontend *dvb_frontend;
struct v4l2_subdev *v4l2_subdev; struct v4l2_subdev *v4l2_subdev;
struct dvb_usb_device *dvb_usb_device; struct dvb_usb_device *dvb_usb_device;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment