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

Pull i2c updates from Wolfram Sang:

 - Peter Rosin did some major rework on the locking of i2c muxes by
   seperating parent-locked muxes and mux-locked muxes.

   This avoids deadlocks/workarounds when the mux itself needs i2c
   commands for muxing.  And as a side-effect, other workarounds in the
   media layer could be eliminated.  Also, Peter stepped up as the i2c
   mux maintainer and will keep an eye on these changes.

 - major updates to the octeon driver

 - add a helper to the core to generate the address+rw_bit octal and
   make drivers use it

 - quite a bunch of driver updates

* 'i2c/for-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (84 commits)
  i2c: rcar: add DMA support
  i2c: st: Implement bus clear
  i2c: only check scl functions when using generic recovery
  i2c: algo-bit: declare i2c_bit_quirk_no_clk_stretch as static
  i2c: tegra: disable clock before returning error
  [media] rtl2832: regmap is aware of lockdep, drop local locking hack
  [media] rtl2832_sdr: get rid of empty regmap wrappers
  [media] rtl2832: change the i2c gate to be mux-locked
  [media] si2168: change the i2c gate to be mux-locked
  iio: imu: inv_mpu6050: change the i2c gate to be mux-locked
  i2c: mux: document i2c muxes and elaborate on parent-/mux-locked muxes
  i2c: mux: relax locking of the top i2c adapter during mux-locked muxing
  i2c: muxes always lock the parent adapter
  i2c: allow adapter drivers to override the adapter locking
  i2c: uniphier: add "\n" at the end of error log
  i2c: mv64xxx: remove CONFIG_HAVE_CLK conditionals
  i2c: mv64xxx: use clk_{prepare_enable,disable_unprepare}
  i2c: mv64xxx: handle probe deferral for the clock
  i2c: mv64xxx: enable the driver on ARCH_MVEBU
  i2c: octeon: Add workaround for broken irqs on CN3860
  ...
This commit is contained in:
Linus Torvalds 2016-05-19 17:48:12 -07:00
commit 78975f23cb
67 changed files with 2709 additions and 1506 deletions

View File

@ -4,6 +4,12 @@
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.
- #address-cells: Must be <1>.

View File

@ -19,6 +19,9 @@ Optional properties:
- clock-frequency: desired I2C bus clock frequency in Hz. The absence of this
property indicates the default frequency 100 kHz.
- 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-internal-delay-ns: see i2c.txt

View File

@ -0,0 +1,370 @@
I2C topology
============
There are a couple of reasons for building more complex i2c topologies
than a straight-forward i2c bus with one adapter and one or more devices.
1. A mux may be needed on the bus to prevent address collisions.
2. The bus may be accessible from some external bus master, and arbitration
may be needed to determine if it is ok to access the bus.
3. A device (particularly RF tuners) may want to avoid the digital noise
from the i2c bus, at least most of the time, and sits behind a gate
that has to be operated before the device can be accessed.
Etc
These constructs are represented as i2c adapter trees by Linux, where
each adapter has a parent adapter (except the root adapter) and zero or
more child adapters. The root adapter is the actual adapter that issues
i2c transfers, and all adapters with a parent are part of an "i2c-mux"
object (quoted, since it can also be an arbitrator or a gate).
Depending of the particular mux driver, something happens when there is
an i2c transfer on one of its child adapters. The mux driver can
obviously operate a mux, but it can also do arbitration with an external
bus master or open a gate. The mux driver has two operations for this,
select and deselect. select is called before the transfer and (the
optional) deselect is called after the transfer.
Locking
=======
There are two variants of locking available to i2c muxes, they can be
mux-locked or parent-locked muxes. As is evident from below, it can be
useful to know if a mux is mux-locked or if it is parent-locked. The
following list was correct at the time of writing:
In drivers/i2c/muxes/
i2c-arb-gpio-challenge Parent-locked
i2c-mux-gpio Normally parent-locked, mux-locked iff
all involved gpio pins are controlled by the
same i2c root adapter that they mux.
i2c-mux-pca9541 Parent-locked
i2c-mux-pca954x Parent-locked
i2c-mux-pinctrl Normally parent-locked, mux-locked iff
all involved pinctrl devices are controlled
by the same i2c root adapter that they mux.
i2c-mux-reg Parent-locked
In drivers/iio/
imu/inv_mpu6050/ Mux-locked
In drivers/media/
dvb-frontends/m88ds3103 Parent-locked
dvb-frontends/rtl2830 Parent-locked
dvb-frontends/rtl2832 Mux-locked
dvb-frontends/si2168 Mux-locked
usb/cx231xx/ Parent-locked
Mux-locked muxes
----------------
Mux-locked muxes does not lock the entire parent adapter during the
full select-transfer-deselect transaction, only the muxes on the parent
adapter are locked. Mux-locked muxes are mostly interesting if the
select and/or deselect operations must use i2c transfers to complete
their tasks. Since the parent adapter is not fully locked during the
full transaction, unrelated i2c transfers may interleave the different
stages of the transaction. This has the benefit that the mux driver
may be easier and cleaner to implement, but it has some caveats.
ML1. If you build a topology with a mux-locked mux being the parent
of a parent-locked mux, this might break the expectation from the
parent-locked mux that the root adapter is locked during the
transaction.
ML2. It is not safe to build arbitrary topologies with two (or more)
mux-locked muxes that are not siblings, when there are address
collisions between the devices on the child adapters of these
non-sibling muxes.
I.e. the select-transfer-deselect transaction targeting e.g. device
address 0x42 behind mux-one may be interleaved with a similar
operation targeting device address 0x42 behind mux-two. The
intension with such a topology would in this hypothetical example
be that mux-one and mux-two should not be selected simultaneously,
but mux-locked muxes do not guarantee that in all topologies.
ML3. A mux-locked mux cannot be used by a driver for auto-closing
gates/muxes, i.e. something that closes automatically after a given
number (one, in most cases) of i2c transfers. Unrelated i2c transfers
may creep in and close prematurely.
ML4. If any non-i2c operation in the mux driver changes the i2c mux state,
the driver has to lock the root adapter during that operation.
Otherwise garbage may appear on the bus as seen from devices
behind the mux, when an unrelated i2c transfer is in flight during
the non-i2c mux-changing operation.
Mux-locked Example
------------------
.----------. .--------.
.--------. | mux- |-----| dev D1 |
| root |--+--| locked | '--------'
'--------' | | mux M1 |--. .--------.
| '----------' '--| dev D2 |
| .--------. '--------'
'--| dev D3 |
'--------'
When there is an access to D1, this happens:
1. Someone issues an i2c-transfer to D1.
2. M1 locks muxes on its parent (the root adapter in this case).
3. M1 calls ->select to ready the mux.
4. M1 (presumably) does some i2c-transfers as part of its select.
These transfers are normal i2c-transfers that locks the parent
adapter.
5. M1 feeds the i2c-transfer from step 1 to its parent adapter as a
normal i2c-transfer that locks the parent adapter.
6. M1 calls ->deselect, if it has one.
7. Same rules as in step 4, but for ->deselect.
8. M1 unlocks muxes on its parent.
This means that accesses to D2 are lockout out for the full duration
of the entire operation. But accesses to D3 are possibly interleaved
at any point.
Parent-locked muxes
-------------------
Parent-locked muxes lock the parent adapter during the full select-
transfer-deselect transaction. The implication is that the mux driver
has to ensure that any and all i2c transfers through that parent
adapter during the transaction are unlocked i2c transfers (using e.g.
__i2c_transfer), or a deadlock will follow. There are a couple of
caveats.
PL1. If you build a topology with a parent-locked mux being the child
of another mux, this might break a possible assumption from the
child mux that the root adapter is unused between its select op
and the actual transfer (e.g. if the child mux is auto-closing
and the parent mux issus i2c-transfers as part of its select).
This is especially the case if the parent mux is mux-locked, but
it may also happen if the parent mux is parent-locked.
PL2. If select/deselect calls out to other subsystems such as gpio,
pinctrl, regmap or iio, it is essential that any i2c transfers
caused by these subsystems are unlocked. This can be convoluted to
accomplish, maybe even impossible if an acceptably clean solution
is sought.
Parent-locked Example
---------------------
.----------. .--------.
.--------. | parent- |-----| dev D1 |
| root |--+--| locked | '--------'
'--------' | | mux M1 |--. .--------.
| '----------' '--| dev D2 |
| .--------. '--------'
'--| dev D3 |
'--------'
When there is an access to D1, this happens:
1. Someone issues an i2c-transfer to D1.
2. M1 locks muxes on its parent (the root adapter in this case).
3. M1 locks its parent adapter.
4. M1 calls ->select to ready the mux.
5. If M1 does any i2c-transfers (on this root adapter) as part of
its select, those transfers must be unlocked i2c-transfers so
that they do not deadlock the root adapter.
6. M1 feeds the i2c-transfer from step 1 to the root adapter as an
unlocked i2c-transfer, so that it does not deadlock the parent
adapter.
7. M1 calls ->deselect, if it has one.
8. Same rules as in step 5, but for ->deselect.
9. M1 unlocks its parent adapter.
10. M1 unlocks muxes on its parent.
This means that accesses to both D2 and D3 are locked out for the full
duration of the entire operation.
Complex Examples
================
Parent-locked mux as parent of parent-locked mux
------------------------------------------------
This is a useful topology, but it can be bad.
.----------. .----------. .--------.
.--------. | parent- |-----| parent- |-----| dev D1 |
| root |--+--| locked | | locked | '--------'
'--------' | | mux M1 |--. | mux M2 |--. .--------.
| '----------' | '----------' '--| dev D2 |
| .--------. | .--------. '--------'
'--| dev D4 | '--| dev D3 |
'--------' '--------'
When any device is accessed, all other devices are locked out for
the full duration of the operation (both muxes lock their parent,
and specifically when M2 requests its parent to lock, M1 passes
the buck to the root adapter).
This topology is bad if M2 is an auto-closing mux and M1->select
issues any unlocked i2c transfers on the root adapter that may leak
through and be seen by the M2 adapter, thus closing M2 prematurely.
Mux-locked mux as parent of mux-locked mux
------------------------------------------
This is a good topology.
.----------. .----------. .--------.
.--------. | mux- |-----| mux- |-----| dev D1 |
| root |--+--| locked | | locked | '--------'
'--------' | | mux M1 |--. | mux M2 |--. .--------.
| '----------' | '----------' '--| dev D2 |
| .--------. | .--------. '--------'
'--| dev D4 | '--| dev D3 |
'--------' '--------'
When device D1 is accessed, accesses to D2 are locked out for the
full duration of the operation (muxes on the top child adapter of M1
are locked). But accesses to D3 and D4 are possibly interleaved at
any point. Accesses to D3 locks out D1 and D2, but accesses to D4
are still possibly interleaved.
Mux-locked mux as parent of parent-locked mux
---------------------------------------------
This is probably a bad topology.
.----------. .----------. .--------.
.--------. | mux- |-----| parent- |-----| dev D1 |
| root |--+--| locked | | locked | '--------'
'--------' | | mux M1 |--. | mux M2 |--. .--------.
| '----------' | '----------' '--| dev D2 |
| .--------. | .--------. '--------'
'--| dev D4 | '--| dev D3 |
'--------' '--------'
When device D1 is accessed, accesses to D2 and D3 are locked out
for the full duration of the operation (M1 locks child muxes on the
root adapter). But accesses to D4 are possibly interleaved at any
point.
This kind of topology is generally not suitable and should probably
be avoided. The reason is that M2 probably assumes that there will
be no i2c transfers during its calls to ->select and ->deselect, and
if there are, any such transfers might appear on the slave side of M2
as partial i2c transfers, i.e. garbage or worse. This might cause
device lockups and/or other problems.
The topology is especially troublesome if M2 is an auto-closing
mux. In that case, any interleaved accesses to D4 might close M2
prematurely, as might any i2c-transfers part of M1->select.
But if M2 is not making the above stated assumption, and if M2 is not
auto-closing, the topology is fine.
Parent-locked mux as parent of mux-locked mux
---------------------------------------------
This is a good topology.
.----------. .----------. .--------.
.--------. | parent- |-----| mux- |-----| dev D1 |
| root |--+--| locked | | locked | '--------'
'--------' | | mux M1 |--. | mux M2 |--. .--------.
| '----------' | '----------' '--| dev D2 |
| .--------. | .--------. '--------'
'--| dev D4 | '--| dev D3 |
'--------' '--------'
When D1 is accessed, accesses to D2 are locked out for the full
duration of the operation (muxes on the top child adapter of M1
are locked). Accesses to D3 and D4 are possibly interleaved at
any point, just as is expected for mux-locked muxes.
When D3 or D4 are accessed, everything else is locked out. For D3
accesses, M1 locks the root adapter. For D4 accesses, the root
adapter is locked directly.
Two mux-locked sibling muxes
----------------------------
This is a good topology.
.--------.
.----------. .--| dev D1 |
| mux- |--' '--------'
.--| locked | .--------.
| | mux M1 |-----| dev D2 |
| '----------' '--------'
| .----------. .--------.
.--------. | | mux- |-----| dev D3 |
| root |--+--| locked | '--------'
'--------' | | mux M2 |--. .--------.
| '----------' '--| dev D4 |
| .--------. '--------'
'--| dev D5 |
'--------'
When D1 is accessed, accesses to D2, D3 and D4 are locked out. But
accesses to D5 may be interleaved at any time.
Two parent-locked sibling muxes
-------------------------------
This is a good topology.
.--------.
.----------. .--| dev D1 |
| parent- |--' '--------'
.--| locked | .--------.
| | mux M1 |-----| dev D2 |
| '----------' '--------'
| .----------. .--------.
.--------. | | parent- |-----| dev D3 |
| root |--+--| locked | '--------'
'--------' | | mux M2 |--. .--------.
| '----------' '--| dev D4 |
| .--------. '--------'
'--| dev D5 |
'--------'
When any device is accessed, accesses to all other devices are locked
out.
Mux-locked and parent-locked sibling muxes
------------------------------------------
This is a good topology.
.--------.
.----------. .--| dev D1 |
| mux- |--' '--------'
.--| locked | .--------.
| | mux M1 |-----| dev D2 |
| '----------' '--------'
| .----------. .--------.
.--------. | | parent- |-----| dev D3 |
| root |--+--| locked | '--------'
'--------' | | mux M2 |--. .--------.
| '----------' '--| dev D4 |
| .--------. '--------'
'--| dev D5 |
'--------'
When D1 or D2 are accessed, accesses to D3 and D4 are locked out while
accesses to D5 may interleave. When D3 or D4 are accessed, accesses to
all other devices are locked out.

View File

@ -5348,6 +5348,7 @@ I2C MUXES
M: Peter Rosin <peda@axentia.se>
L: linux-i2c@vger.kernel.org
S: Maintained
F: Documentation/i2c/i2c-topology
F: Documentation/i2c/muxes/
F: Documentation/devicetree/bindings/i2c/i2c-mux*
F: drivers/i2c/i2c-mux.c

View File

@ -617,7 +617,7 @@ const struct i2c_algorithm i2c_bit_algo = {
};
EXPORT_SYMBOL(i2c_bit_algo);
const struct i2c_adapter_quirks i2c_bit_quirk_no_clk_stretch = {
static const struct i2c_adapter_quirks i2c_bit_quirk_no_clk_stretch = {
.flags = I2C_AQ_NO_CLK_STRETCH,
};

View File

@ -663,7 +663,7 @@ config I2C_MT65XX
config I2C_MV64XXX
tristate "Marvell mv64xxx I2C Controller"
depends on MV64X60 || PLAT_ORION || ARCH_SUNXI
depends on MV64X60 || PLAT_ORION || ARCH_SUNXI || ARCH_MVEBU
help
If you say yes to this option, support will be included for the
built-in I2C interface on the Marvell 64xxx line of host bridges.

View File

@ -267,7 +267,7 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
iproc_i2c->msg = msg;
/* format and load slave address into the TX FIFO */
addr = msg->addr << 1 | (msg->flags & I2C_M_RD ? 1 : 0);
addr = i2c_8bit_addr_from_msg(msg);
writel(addr, iproc_i2c->base + M_TX_OFFSET);
/*

View File

@ -501,10 +501,7 @@ static int bcm_kona_i2c_do_addr(struct bcm_kona_i2c_dev *dev,
return -EREMOTEIO;
}
} else {
addr = msg->addr << 1;
if (msg->flags & I2C_M_RD)
addr |= 1;
addr = i2c_8bit_addr_from_msg(msg);
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
return -EREMOTEIO;

View File

@ -446,9 +446,7 @@ static int brcmstb_i2c_do_addr(struct brcmstb_i2c_dev *dev,
}
} else {
addr = msg->addr << 1;
if (msg->flags & I2C_M_RD)
addr |= 1;
addr = i2c_8bit_addr_from_msg(msg);
bsc_writel(dev, addr, chip_address);
}

View File

@ -197,9 +197,7 @@ static void cpm_i2c_parse_message(struct i2c_adapter *adap,
tbdf = cpm->tbase + tx;
rbdf = cpm->rbase + rx;
addr = pmsg->addr << 1;
if (pmsg->flags & I2C_M_RD)
addr |= 1;
addr = i2c_8bit_addr_from_msg(pmsg);
tb = cpm->txbuf[tx];
rb = cpm->rxbuf[rx];

View File

@ -19,6 +19,7 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/mfd/dln2.h>
#include <linux/acpi.h>
#define DLN2_I2C_MODULE_ID 0x03
#define DLN2_I2C_CMD(cmd) DLN2_CMD(cmd, DLN2_I2C_MODULE_ID)
@ -210,6 +211,7 @@ static int dln2_i2c_probe(struct platform_device *pdev)
dln2->adapter.algo = &dln2_i2c_usb_algorithm;
dln2->adapter.quirks = &dln2_i2c_quirks;
dln2->adapter.dev.parent = dev;
ACPI_COMPANION_SET(&dln2->adapter.dev, ACPI_COMPANION(&pdev->dev));
dln2->adapter.dev.of_node = dev->of_node;
i2c_set_adapdata(&dln2->adapter, dln2);
snprintf(dln2->adapter.name, sizeof(dln2->adapter.name), "%s-%s-%d",

View File

@ -861,14 +861,8 @@ static int exynos5_i2c_resume_noirq(struct device *dev)
#endif
static const struct dev_pm_ops exynos5_i2c_dev_pm_ops = {
#ifdef CONFIG_PM_SLEEP
.suspend_noirq = exynos5_i2c_suspend_noirq,
.resume_noirq = exynos5_i2c_resume_noirq,
.freeze_noirq = exynos5_i2c_suspend_noirq,
.thaw_noirq = exynos5_i2c_resume_noirq,
.poweroff_noirq = exynos5_i2c_suspend_noirq,
.restore_noirq = exynos5_i2c_resume_noirq,
#endif
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos5_i2c_suspend_noirq,
exynos5_i2c_resume_noirq)
};
static struct platform_driver exynos5_i2c_driver = {

View File

@ -94,6 +94,7 @@
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/platform_data/itco_wdt.h>
#include <linux/pm_runtime.h>
#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \
defined CONFIG_DMI
@ -714,9 +715,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
{
int hwpec;
int block = 0;
int ret, xact = 0;
int ret = 0, xact = 0;
struct i801_priv *priv = i2c_get_adapdata(adap);
pm_runtime_get_sync(&priv->pci_dev->dev);
hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
&& size != I2C_SMBUS_QUICK
&& size != I2C_SMBUS_I2C_BLOCK_DATA;
@ -773,7 +776,8 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
default:
dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n",
size);
return -EOPNOTSUPP;
ret = -EOPNOTSUPP;
goto out;
}
if (hwpec) /* enable/disable hardware PEC */
@ -796,11 +800,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
if (block)
return ret;
goto out;
if (ret)
return ret;
goto out;
if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
return 0;
goto out;
switch (xact & 0x7f) {
case I801_BYTE: /* Result put in SMBHSTDAT0 */
@ -812,7 +816,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
(inb_p(SMBHSTDAT1(priv)) << 8);
break;
}
return 0;
out:
pm_runtime_mark_last_busy(&priv->pci_dev->dev);
pm_runtime_put_autosuspend(&priv->pci_dev->dev);
return ret;
}
@ -1413,6 +1421,11 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
pci_set_drvdata(dev, priv);
pm_runtime_set_autosuspend_delay(&dev->dev, 1000);
pm_runtime_use_autosuspend(&dev->dev);
pm_runtime_put_autosuspend(&dev->dev);
pm_runtime_allow(&dev->dev);
return 0;
}
@ -1420,6 +1433,9 @@ static void i801_remove(struct pci_dev *dev)
{
struct i801_priv *priv = pci_get_drvdata(dev);
pm_runtime_forbid(&dev->dev);
pm_runtime_get_noresume(&dev->dev);
i801_del_mux(priv);
i2c_del_adapter(&priv->adapter);
pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
@ -1433,34 +1449,32 @@ static void i801_remove(struct pci_dev *dev)
}
#ifdef CONFIG_PM
static int i801_suspend(struct pci_dev *dev, pm_message_t mesg)
static int i801_suspend(struct device *dev)
{
struct i801_priv *priv = pci_get_drvdata(dev);
struct pci_dev *pci_dev = to_pci_dev(dev);
struct i801_priv *priv = pci_get_drvdata(pci_dev);
pci_save_state(dev);
pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
pci_set_power_state(dev, pci_choose_state(dev, mesg));
pci_write_config_byte(pci_dev, SMBHSTCFG, priv->original_hstcfg);
return 0;
}
static int i801_resume(struct pci_dev *dev)
static int i801_resume(struct device *dev)
{
pci_set_power_state(dev, PCI_D0);
pci_restore_state(dev);
return 0;
}
#else
#define i801_suspend NULL
#define i801_resume NULL
#endif
static UNIVERSAL_DEV_PM_OPS(i801_pm_ops, i801_suspend,
i801_resume, NULL);
static struct pci_driver i801_driver = {
.name = "i801_smbus",
.id_table = i801_ids,
.probe = i801_probe,
.remove = i801_remove,
.suspend = i801_suspend,
.resume = i801_resume,
.driver = {
.pm = &i801_pm_ops,
},
};
static int __init i2c_i801_init(void)

View File

@ -269,7 +269,7 @@ static int iic_smbus_quick(struct ibm_iic_private* dev, const struct i2c_msg* p)
ndelay(t->hd_sta);
/* Send address */
v = (u8)((p->addr << 1) | ((p->flags & I2C_M_RD) ? 1 : 0));
v = i2c_8bit_addr_from_msg(p);
for (i = 0, mask = 0x80; i < 8; ++i, mask >>= 1){
out_8(&iic->directcntl, sda);
ndelay(t->low / 2);

View File

@ -751,9 +751,7 @@ static unsigned int img_i2c_atomic(struct img_i2c *i2c,
switch (i2c->at_cur_cmd) {
case CMD_GEN_START:
next_cmd = CMD_GEN_DATA;
next_data = (i2c->msg.addr << 1);
if (i2c->msg.flags & I2C_M_RD)
next_data |= 0x1;
next_data = i2c_8bit_addr_from_msg(&i2c->msg);
break;
case CMD_GEN_DATA:
if (i2c->line_status & LINESTAT_INPUT_HELD_V)

View File

@ -525,7 +525,7 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx, IMX_I2C_I2CR);
/* Wait controller to be stable */
udelay(50);
usleep_range(50, 150);
/* Start I2C transaction */
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);

View File

@ -50,10 +50,7 @@ iic_cook_addr(struct i2c_msg *msg)
{
unsigned char addr;
addr = (msg->addr << 1);
if (msg->flags & I2C_M_RD)
addr |= 1;
addr = i2c_8bit_addr_from_msg(msg);
return addr;
}

View File

@ -133,9 +133,7 @@ static void i2c_lpc2k_pump_msg(struct lpc2k_i2c *i2c)
case M_START:
case M_REPSTART:
/* Start bit was just sent out, send out addr and dir */
data = i2c->msg->addr << 1;
if (i2c->msg->flags & I2C_M_RD)
data |= 1;
data = i2c_8bit_addr_from_msg(i2c->msg);
writel(data, i2c->base + LPC24XX_I2DAT);
writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONCLR);

View File

@ -413,10 +413,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
else
writew(I2C_FS_START_CON, i2c->base + OFFSET_EXT_CONF);
addr_reg = msgs->addr << 1;
if (i2c->op == I2C_MASTER_RD)
addr_reg |= 0x1;
addr_reg = i2c_8bit_addr_from_msg(msgs);
writew(addr_reg, i2c->base + OFFSET_SLAVE_ADDR);
/* Clear interrupt status */

View File

@ -134,9 +134,7 @@ struct mv64xxx_i2c_data {
int rc;
u32 freq_m;
u32 freq_n;
#if defined(CONFIG_HAVE_CLK)
struct clk *clk;
#endif
wait_queue_head_t waitq;
spinlock_t lock;
struct i2c_msg *msg;
@ -757,7 +755,6 @@ static const struct of_device_id mv64xxx_i2c_of_match_table[] = {
MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
#ifdef CONFIG_OF
#ifdef CONFIG_HAVE_CLK
static int
mv64xxx_calc_freq(struct mv64xxx_i2c_data *drv_data,
const int tclk, const int n, const int m)
@ -791,25 +788,20 @@ mv64xxx_find_baud_factors(struct mv64xxx_i2c_data *drv_data,
return false;
return true;
}
#endif /* CONFIG_HAVE_CLK */
static int
mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
struct device *dev)
{
/* CLK is mandatory when using DT to describe the i2c bus. We
* need to know tclk in order to calculate bus clock
* factors.
*/
#if !defined(CONFIG_HAVE_CLK)
/* Have OF but no CLK */
return -ENODEV;
#else
const struct of_device_id *device;
struct device_node *np = dev->of_node;
u32 bus_freq, tclk;
int rc = 0;
/* CLK is mandatory when using DT to describe the i2c bus. We
* need to know tclk in order to calculate bus clock
* factors.
*/
if (IS_ERR(drv_data->clk)) {
rc = -ENODEV;
goto out;
@ -869,7 +861,6 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
out:
return rc;
#endif
}
#else /* CONFIG_OF */
static int
@ -907,14 +898,13 @@ mv64xxx_i2c_probe(struct platform_device *pd)
init_waitqueue_head(&drv_data->waitq);
spin_lock_init(&drv_data->lock);
#if defined(CONFIG_HAVE_CLK)
/* Not all platforms have a clk */
drv_data->clk = devm_clk_get(&pd->dev, NULL);
if (!IS_ERR(drv_data->clk)) {
clk_prepare(drv_data->clk);
clk_enable(drv_data->clk);
}
#endif
if (IS_ERR(drv_data->clk) && PTR_ERR(drv_data->clk) == -EPROBE_DEFER)
return -EPROBE_DEFER;
if (!IS_ERR(drv_data->clk))
clk_prepare_enable(drv_data->clk);
if (pdata) {
drv_data->freq_m = pdata->freq_m;
drv_data->freq_n = pdata->freq_n;
@ -964,13 +954,10 @@ exit_reset:
if (!IS_ERR_OR_NULL(drv_data->rstc))
reset_control_assert(drv_data->rstc);
exit_clk:
#if defined(CONFIG_HAVE_CLK)
/* Not all platforms have a clk */
if (!IS_ERR(drv_data->clk)) {
clk_disable(drv_data->clk);
clk_unprepare(drv_data->clk);
}
#endif
if (!IS_ERR(drv_data->clk))
clk_disable_unprepare(drv_data->clk);
return rc;
}
@ -983,13 +970,9 @@ mv64xxx_i2c_remove(struct platform_device *dev)
free_irq(drv_data->irq, drv_data);
if (!IS_ERR_OR_NULL(drv_data->rstc))
reset_control_assert(drv_data->rstc);
#if defined(CONFIG_HAVE_CLK)
/* Not all platforms have a clk */
if (!IS_ERR(drv_data->clk)) {
clk_disable(drv_data->clk);
clk_unprepare(drv_data->clk);
}
#endif
if (!IS_ERR(drv_data->clk))
clk_disable_unprepare(drv_data->clk);
return 0;
}

View File

@ -127,7 +127,7 @@ static struct pci_driver nforce2_driver;
/* For multiplexing support, we need a global reference to the 1st
SMBus channel */
#if defined CONFIG_I2C_NFORCE2_S4985 || defined CONFIG_I2C_NFORCE2_S4985_MODULE
#if IS_ENABLED(CONFIG_I2C_NFORCE2_S4985)
struct i2c_adapter *nforce2_smbus;
EXPORT_SYMBOL_GPL(nforce2_smbus);

View File

@ -178,10 +178,7 @@ static void ocores_process(struct ocores_i2c *i2c)
if (i2c->nmsgs) { /* end? */
/* send start? */
if (!(msg->flags & I2C_M_NOSTART)) {
u8 addr = (msg->addr << 1);
if (msg->flags & I2C_M_RD)
addr |= 1;
u8 addr = i2c_8bit_addr_from_msg(msg);
i2c->state = STATE_START;

File diff suppressed because it is too large Load Diff

View File

@ -185,7 +185,6 @@ enum {
#define OMAP_I2C_IP_V2_INTERRUPTS_MASK 0x6FFF
struct omap_i2c_dev {
spinlock_t lock; /* IRQ synchronization */
struct device *dev;
void __iomem *base; /* virtual */
int irq;
@ -995,15 +994,12 @@ omap_i2c_isr(int irq, void *dev_id)
u16 mask;
u16 stat;
spin_lock(&omap->lock);
mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
if (stat & mask)
ret = IRQ_WAKE_THREAD;
spin_unlock(&omap->lock);
return ret;
}
@ -1011,12 +1007,10 @@ static irqreturn_t
omap_i2c_isr_thread(int this_irq, void *dev_id)
{
struct omap_i2c_dev *omap = dev_id;
unsigned long flags;
u16 bits;
u16 stat;
int err = 0, count = 0;
spin_lock_irqsave(&omap->lock, flags);
do {
bits = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG);
stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG);
@ -1142,8 +1136,6 @@ omap_i2c_isr_thread(int this_irq, void *dev_id)
omap_i2c_complete_cmd(omap, err);
out:
spin_unlock_irqrestore(&omap->lock, flags);
return IRQ_HANDLED;
}
@ -1330,8 +1322,6 @@ omap_i2c_probe(struct platform_device *pdev)
omap->dev = &pdev->dev;
omap->irq = irq;
spin_lock_init(&omap->lock);
platform_set_drvdata(pdev, omap);
init_completion(&omap->cmd_complete);

View File

@ -150,13 +150,11 @@ static int i2c_powermac_master_xfer( struct i2c_adapter *adap,
{
struct pmac_i2c_bus *bus = i2c_get_adapdata(adap);
int rc = 0;
int read;
int addrdir;
if (msgs->flags & I2C_M_TEN)
return -EINVAL;
read = (msgs->flags & I2C_M_RD) != 0;
addrdir = (msgs->addr << 1) | read;
addrdir = i2c_8bit_addr_from_msg(msgs);
rc = pmac_i2c_open(bus, 0);
if (rc) {

View File

@ -515,7 +515,7 @@ static int qup_i2c_get_data_len(struct qup_i2c_dev *qup)
static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup,
struct i2c_msg *msg, int is_dma)
{
u16 addr = (msg->addr << 1) | ((msg->flags & I2C_M_RD) == I2C_M_RD);
u16 addr = i2c_8bit_addr_from_msg(msg);
int len = 0;
int data_len;

View File

@ -21,6 +21,8 @@
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@ -43,6 +45,8 @@
#define ICSAR 0x1C /* slave address */
#define ICMAR 0x20 /* master address */
#define ICRXTX 0x24 /* data port */
#define ICDMAER 0x3c /* DMA enable */
#define ICFBSCR 0x38 /* first bit setup cycle */
/* ICSCR */
#define SDBS (1 << 3) /* slave data buffer select */
@ -78,6 +82,16 @@
#define MDR (1 << 1)
#define MAT (1 << 0) /* slave addr xfer done */
/* ICDMAER */
#define RSDMAE (1 << 3) /* DMA Slave Received Enable */
#define TSDMAE (1 << 2) /* DMA Slave Transmitted Enable */
#define RMDMAE (1 << 1) /* DMA Master Received Enable */
#define TMDMAE (1 << 0) /* DMA Master Transmitted Enable */
/* ICFBSCR */
#define TCYC06 0x04 /* 6*Tcyc delay 1st bit between SDA and SCL */
#define TCYC17 0x0f /* 17*Tcyc delay 1st bit between SDA and SCL */
#define RCAR_BUS_PHASE_START (MDBS | MIE | ESG)
#define RCAR_BUS_PHASE_DATA (MDBS | MIE)
@ -120,6 +134,12 @@ struct rcar_i2c_priv {
u32 flags;
enum rcar_i2c_type devtype;
struct i2c_client *slave;
struct resource *res;
struct dma_chan *dma_tx;
struct dma_chan *dma_rx;
struct scatterlist sg;
enum dma_data_direction dma_direction;
};
#define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent)
@ -287,6 +307,118 @@ static void rcar_i2c_next_msg(struct rcar_i2c_priv *priv)
/*
* interrupt functions
*/
static void rcar_i2c_dma_unmap(struct rcar_i2c_priv *priv)
{
struct dma_chan *chan = priv->dma_direction == DMA_FROM_DEVICE
? priv->dma_rx : priv->dma_tx;
/* Disable DMA Master Received/Transmitted */
rcar_i2c_write(priv, ICDMAER, 0);
/* Reset default delay */
rcar_i2c_write(priv, ICFBSCR, TCYC06);
dma_unmap_single(chan->device->dev, sg_dma_address(&priv->sg),
priv->msg->len, priv->dma_direction);
priv->dma_direction = DMA_NONE;
}
static void rcar_i2c_cleanup_dma(struct rcar_i2c_priv *priv)
{
if (priv->dma_direction == DMA_NONE)
return;
else if (priv->dma_direction == DMA_FROM_DEVICE)
dmaengine_terminate_all(priv->dma_rx);
else if (priv->dma_direction == DMA_TO_DEVICE)
dmaengine_terminate_all(priv->dma_tx);
rcar_i2c_dma_unmap(priv);
}
static void rcar_i2c_dma_callback(void *data)
{
struct rcar_i2c_priv *priv = data;
priv->pos += sg_dma_len(&priv->sg);
rcar_i2c_dma_unmap(priv);
}
static void rcar_i2c_dma(struct rcar_i2c_priv *priv)
{
struct device *dev = rcar_i2c_priv_to_dev(priv);
struct i2c_msg *msg = priv->msg;
bool read = msg->flags & I2C_M_RD;
enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
struct dma_chan *chan = read ? priv->dma_rx : priv->dma_tx;
struct dma_async_tx_descriptor *txdesc;
dma_addr_t dma_addr;
dma_cookie_t cookie;
unsigned char *buf;
int len;
/* Do not use DMA if it's not available or for messages < 8 bytes */
if (IS_ERR(chan) || msg->len < 8)
return;
if (read) {
/*
* The last two bytes needs to be fetched using PIO in
* order for the STOP phase to work.
*/
buf = priv->msg->buf;
len = priv->msg->len - 2;
} else {
/*
* First byte in message was sent using PIO.
*/
buf = priv->msg->buf + 1;
len = priv->msg->len - 1;
}
dma_addr = dma_map_single(chan->device->dev, buf, len, dir);
if (dma_mapping_error(dev, dma_addr)) {
dev_dbg(dev, "dma map failed, using PIO\n");
return;
}
sg_dma_len(&priv->sg) = len;
sg_dma_address(&priv->sg) = dma_addr;
priv->dma_direction = dir;
txdesc = dmaengine_prep_slave_sg(chan, &priv->sg, 1,
read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!txdesc) {
dev_dbg(dev, "dma prep slave sg failed, using PIO\n");
rcar_i2c_cleanup_dma(priv);
return;
}
txdesc->callback = rcar_i2c_dma_callback;
txdesc->callback_param = priv;
cookie = dmaengine_submit(txdesc);
if (dma_submit_error(cookie)) {
dev_dbg(dev, "submitting dma failed, using PIO\n");
rcar_i2c_cleanup_dma(priv);
return;
}
/* Set delay for DMA operations */
rcar_i2c_write(priv, ICFBSCR, TCYC17);
/* Enable DMA Master Received/Transmitted */
if (read)
rcar_i2c_write(priv, ICDMAER, RMDMAE);
else
rcar_i2c_write(priv, ICDMAER, TMDMAE);
dma_async_issue_pending(chan);
}
static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
{
struct i2c_msg *msg = priv->msg;
@ -306,6 +438,12 @@ static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
rcar_i2c_write(priv, ICRXTX, msg->buf[priv->pos]);
priv->pos++;
/*
* Try to use DMA to transmit the rest of the data if
* address transfer pashe just finished.
*/
if (msr & MAT)
rcar_i2c_dma(priv);
} else {
/*
* The last data was pushed to ICRXTX on _PREV_ empty irq.
@ -340,7 +478,11 @@ static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
return;
if (msr & MAT) {
/* Address transfer phase finished, but no data at this point. */
/*
* Address transfer phase finished, but no data at this point.
* Try to use DMA to receive data.
*/
rcar_i2c_dma(priv);
} else if (priv->pos < msg->len) {
/* get received data */
msg->buf[priv->pos] = rcar_i2c_read(priv, ICRXTX);
@ -472,6 +614,81 @@ out:
return IRQ_HANDLED;
}
static struct dma_chan *rcar_i2c_request_dma_chan(struct device *dev,
enum dma_transfer_direction dir,
dma_addr_t port_addr)
{
struct dma_chan *chan;
struct dma_slave_config cfg;
char *chan_name = dir == DMA_MEM_TO_DEV ? "tx" : "rx";
int ret;
chan = dma_request_slave_channel_reason(dev, chan_name);
if (IS_ERR(chan)) {
ret = PTR_ERR(chan);
dev_dbg(dev, "request_channel failed for %s (%d)\n",
chan_name, ret);
return chan;
}
memset(&cfg, 0, sizeof(cfg));
cfg.direction = dir;
if (dir == DMA_MEM_TO_DEV) {
cfg.dst_addr = port_addr;
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
} else {
cfg.src_addr = port_addr;
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
}
ret = dmaengine_slave_config(chan, &cfg);
if (ret) {
dev_dbg(dev, "slave_config failed for %s (%d)\n",
chan_name, ret);
dma_release_channel(chan);
return ERR_PTR(ret);
}
dev_dbg(dev, "got DMA channel for %s\n", chan_name);
return chan;
}
static void rcar_i2c_request_dma(struct rcar_i2c_priv *priv,
struct i2c_msg *msg)
{
struct device *dev = rcar_i2c_priv_to_dev(priv);
bool read;
struct dma_chan *chan;
enum dma_transfer_direction dir;
read = msg->flags & I2C_M_RD;
chan = read ? priv->dma_rx : priv->dma_tx;
if (PTR_ERR(chan) != -EPROBE_DEFER)
return;
dir = read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
chan = rcar_i2c_request_dma_chan(dev, dir, priv->res->start + ICRXTX);
if (read)
priv->dma_rx = chan;
else
priv->dma_tx = chan;
}
static void rcar_i2c_release_dma(struct rcar_i2c_priv *priv)
{
if (!IS_ERR(priv->dma_tx)) {
dma_release_channel(priv->dma_tx);
priv->dma_tx = ERR_PTR(-EPROBE_DEFER);
}
if (!IS_ERR(priv->dma_rx)) {
dma_release_channel(priv->dma_rx);
priv->dma_rx = ERR_PTR(-EPROBE_DEFER);
}
}
static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs,
int num)
@ -493,6 +710,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
ret = -EOPNOTSUPP;
goto out;
}
rcar_i2c_request_dma(priv, msgs + i);
}
/* init first message */
@ -504,6 +722,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
time_left = wait_event_timeout(priv->wait, priv->flags & ID_DONE,
num * adap->timeout);
if (!time_left) {
rcar_i2c_cleanup_dma(priv);
rcar_i2c_init(priv);
ret = -ETIMEDOUT;
} else if (priv->flags & ID_NACK) {
@ -591,7 +810,6 @@ static int rcar_i2c_probe(struct platform_device *pdev)
{
struct rcar_i2c_priv *priv;
struct i2c_adapter *adap;
struct resource *res;
struct device *dev = &pdev->dev;
struct i2c_timings i2c_t;
int irq, ret;
@ -606,8 +824,9 @@ static int rcar_i2c_probe(struct platform_device *pdev)
return PTR_ERR(priv->clk);
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->io = devm_ioremap_resource(dev, res);
priv->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->io = devm_ioremap_resource(dev, priv->res);
if (IS_ERR(priv->io))
return PTR_ERR(priv->io);
@ -626,6 +845,11 @@ static int rcar_i2c_probe(struct platform_device *pdev)
i2c_parse_fw_timings(dev, &i2c_t, false);
/* Init DMA */
sg_init_table(&priv->sg, 1);
priv->dma_direction = DMA_NONE;
priv->dma_rx = priv->dma_tx = ERR_PTR(-EPROBE_DEFER);
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
ret = rcar_i2c_clock_calculate(priv, &i2c_t);
@ -673,6 +897,7 @@ static int rcar_i2c_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev;
i2c_del_adapter(&priv->adap);
rcar_i2c_release_dma(priv);
if (priv->flags & ID_P_PM_BLOCKED)
pm_runtime_put(dev);
pm_runtime_disable(dev);

View File

@ -101,10 +101,7 @@ struct rk3x_i2c {
struct notifier_block clk_rate_nb;
/* Settings */
unsigned int scl_frequency;
unsigned int scl_rise_ns;
unsigned int scl_fall_ns;
unsigned int sda_fall_ns;
struct i2c_timings t;
/* Synchronization & notification */
spinlock_t lock;
@ -437,10 +434,7 @@ out:
* Calculate divider values for desired SCL frequency
*
* @clk_rate: I2C input clock rate
* @scl_rate: Desired SCL rate
* @scl_rise_ns: How many ns it takes for SCL to rise.
* @scl_fall_ns: How many ns it takes for SCL to fall.
* @sda_fall_ns: How many ns it takes for SDA to fall.
* @t: Known I2C timing information.
* @div_low: Divider output for low
* @div_high: Divider output for high
*
@ -448,11 +442,10 @@ out:
* a best-effort divider value is returned in divs. If the target rate is
* too high, we silently use the highest possible rate.
*/
static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
unsigned long scl_rise_ns,
unsigned long scl_fall_ns,
unsigned long sda_fall_ns,
unsigned long *div_low, unsigned long *div_high)
static int rk3x_i2c_calc_divs(unsigned long clk_rate,
struct i2c_timings *t,
unsigned long *div_low,
unsigned long *div_high)
{
unsigned long spec_min_low_ns, spec_min_high_ns;
unsigned long spec_setup_start, spec_max_data_hold_ns;
@ -472,12 +465,12 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
int ret = 0;
/* Only support standard-mode and fast-mode */
if (WARN_ON(scl_rate > 400000))
scl_rate = 400000;
if (WARN_ON(t->bus_freq_hz > 400000))
t->bus_freq_hz = 400000;
/* prevent scl_rate_khz from becoming 0 */
if (WARN_ON(scl_rate < 1000))
scl_rate = 1000;
if (WARN_ON(t->bus_freq_hz < 1000))
t->bus_freq_hz = 1000;
/*
* min_low_ns: The minimum number of ns we need to hold low to
@ -491,7 +484,7 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
* This is because the i2c host on Rockchip holds the data line
* for half the low time.
*/
if (scl_rate <= 100000) {
if (t->bus_freq_hz <= 100000) {
/* Standard-mode */
spec_min_low_ns = 4700;
spec_setup_start = 4700;
@ -506,7 +499,7 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
spec_max_data_hold_ns = 900;
data_hold_buffer_ns = 50;
}
min_high_ns = scl_rise_ns + spec_min_high_ns;
min_high_ns = t->scl_rise_ns + spec_min_high_ns;
/*
* Timings for repeated start:
@ -517,18 +510,18 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
* we meet tSU;STA and tHD;STA times.
*/
min_high_ns = max(min_high_ns,
DIV_ROUND_UP((scl_rise_ns + spec_setup_start) * 1000, 875));
DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start) * 1000, 875));
min_high_ns = max(min_high_ns,
DIV_ROUND_UP((scl_rise_ns + spec_setup_start +
sda_fall_ns + spec_min_high_ns), 2));
DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start +
t->sda_fall_ns + spec_min_high_ns), 2));
min_low_ns = scl_fall_ns + spec_min_low_ns;
min_low_ns = t->scl_fall_ns + spec_min_low_ns;
max_low_ns = spec_max_data_hold_ns * 2 - data_hold_buffer_ns;
min_total_ns = min_low_ns + min_high_ns;
/* Adjust to avoid overflow */
clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000);
scl_rate_khz = scl_rate / 1000;
scl_rate_khz = t->bus_freq_hz / 1000;
/*
* We need the total div to be >= this number
@ -616,14 +609,13 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
{
struct i2c_timings *t = &i2c->t;
unsigned long div_low, div_high;
u64 t_low_ns, t_high_ns;
int ret;
ret = rk3x_i2c_calc_divs(clk_rate, i2c->scl_frequency, i2c->scl_rise_ns,
i2c->scl_fall_ns, i2c->sda_fall_ns,
&div_low, &div_high);
WARN_ONCE(ret != 0, "Could not reach SCL freq %u", i2c->scl_frequency);
ret = rk3x_i2c_calc_divs(clk_rate, t, &div_low, &div_high);
WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
clk_enable(i2c->clk);
i2c_writel(i2c, (div_high << 16) | (div_low & 0xffff), REG_CLKDIV);
@ -634,7 +626,7 @@ static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
dev_dbg(i2c->dev,
"CLK %lukhz, Req %uns, Act low %lluns high %lluns\n",
clk_rate / 1000,
1000000000 / i2c->scl_frequency,
1000000000 / t->bus_freq_hz,
t_low_ns, t_high_ns);
}
@ -664,9 +656,7 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
switch (event) {
case PRE_RATE_CHANGE:
if (rk3x_i2c_calc_divs(ndata->new_rate, i2c->scl_frequency,
i2c->scl_rise_ns, i2c->scl_fall_ns,
i2c->sda_fall_ns,
if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t,
&div_low, &div_high) != 0)
return NOTIFY_STOP;
@ -880,37 +870,8 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
match = of_match_node(rk3x_i2c_match, np);
i2c->soc_data = (struct rk3x_i2c_soc_data *)match->data;
if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
&i2c->scl_frequency)) {
dev_info(&pdev->dev, "using default SCL frequency: %d\n",
DEFAULT_SCL_RATE);
i2c->scl_frequency = DEFAULT_SCL_RATE;
}
if (i2c->scl_frequency == 0 || i2c->scl_frequency > 400 * 1000) {
dev_warn(&pdev->dev, "invalid SCL frequency specified.\n");
dev_warn(&pdev->dev, "using default SCL frequency: %d\n",
DEFAULT_SCL_RATE);
i2c->scl_frequency = DEFAULT_SCL_RATE;
}
/*
* Read rise and fall time from device tree. If not available use
* the default maximum timing from the specification.
*/
if (of_property_read_u32(pdev->dev.of_node, "i2c-scl-rising-time-ns",
&i2c->scl_rise_ns)) {
if (i2c->scl_frequency <= 100000)
i2c->scl_rise_ns = 1000;
else
i2c->scl_rise_ns = 300;
}
if (of_property_read_u32(pdev->dev.of_node, "i2c-scl-falling-time-ns",
&i2c->scl_fall_ns))
i2c->scl_fall_ns = 300;
if (of_property_read_u32(pdev->dev.of_node, "i2c-sda-falling-time-ns",
&i2c->sda_fall_ns))
i2c->sda_fall_ns = i2c->scl_fall_ns;
/* use common interface to get I2C timing properties */
i2c_parse_fw_timings(&pdev->dev, &i2c->t, true);
strlcpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name));
i2c->adap.owner = THIS_MODULE;

View File

@ -163,15 +163,14 @@ static const struct of_device_id s3c24xx_i2c_match[] = {
MODULE_DEVICE_TABLE(of, s3c24xx_i2c_match);
#endif
/* s3c24xx_get_device_quirks
*
/*
* Get controller type either from device tree or platform device variant.
*/
*/
static inline kernel_ulong_t s3c24xx_get_device_quirks(struct platform_device *pdev)
{
if (pdev->dev.of_node) {
const struct of_device_id *match;
match = of_match_node(s3c24xx_i2c_match, pdev->dev.of_node);
return (kernel_ulong_t)match->data;
}
@ -179,12 +178,10 @@ static inline kernel_ulong_t s3c24xx_get_device_quirks(struct platform_device *p
return platform_get_device_id(pdev)->driver_data;
}
/* s3c24xx_i2c_master_complete
*
* complete the message and wake up the caller, using the given return code,
/*
* Complete the message and wake up the caller, using the given return code,
* or zero to mean ok.
*/
*/
static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret)
{
dev_dbg(i2c->dev, "master_complete %d\n", ret);
@ -217,7 +214,6 @@ static inline void s3c24xx_i2c_enable_ack(struct s3c24xx_i2c *i2c)
}
/* irq enable/disable functions */
static inline void s3c24xx_i2c_disable_irq(struct s3c24xx_i2c *i2c)
{
unsigned long tmp;
@ -251,11 +247,9 @@ static bool is_ack(struct s3c24xx_i2c *i2c)
return false;
}
/* s3c24xx_i2c_message_start
*
/*
* put the start of a message onto the bus
*/
*/
static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
struct i2c_msg *msg)
{
@ -284,9 +278,10 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);
writeb(addr, i2c->regs + S3C2410_IICDS);
/* delay here to ensure the data byte has gotten onto the bus
* before the transaction is started */
/*
* delay here to ensure the data byte has gotten onto the bus
* before the transaction is started
*/
ndelay(i2c->tx_setup);
dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon);
@ -361,50 +356,46 @@ static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
s3c24xx_i2c_disable_irq(i2c);
}
/* helper functions to determine the current state in the set of
* messages we are sending */
/*
* helper functions to determine the current state in the set of
* messages we are sending
*/
/* is_lastmsg()
*
/*
* returns TRUE if the current message is the last in the set
*/
*/
static inline int is_lastmsg(struct s3c24xx_i2c *i2c)
{
return i2c->msg_idx >= (i2c->msg_num - 1);
}
/* is_msglast
*
/*
* returns TRUE if we this is the last byte in the current message
*/
*/
static inline int is_msglast(struct s3c24xx_i2c *i2c)
{
/* msg->len is always 1 for the first byte of smbus block read.
/*
* msg->len is always 1 for the first byte of smbus block read.
* Actual length will be read from slave. More bytes will be
* read according to the length then. */
* read according to the length then.
*/
if (i2c->msg->flags & I2C_M_RECV_LEN && i2c->msg->len == 1)
return 0;
return i2c->msg_ptr == i2c->msg->len-1;
}
/* is_msgend
*
/*
* returns TRUE if we reached the end of the current message
*/
*/
static inline int is_msgend(struct s3c24xx_i2c *i2c)
{
return i2c->msg_ptr >= i2c->msg->len;
}
/* i2c_s3c_irq_nextbyte
*
/*
* process an interrupt and work out what to do
*/
static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
{
unsigned long tmp;
@ -423,14 +414,13 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
goto out_ack;
case STATE_START:
/* last thing we did was send a start condition on the
/*
* last thing we did was send a start condition on the
* bus, or started a new i2c message
*/
if (iicstat & S3C2410_IICSTAT_LASTBIT &&
!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
/* ack was not received... */
dev_dbg(i2c->dev, "ack was not received\n");
s3c24xx_i2c_stop(i2c, -ENXIO);
goto out_ack;
@ -441,9 +431,10 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
else
i2c->state = STATE_WRITE;
/* terminate the transfer if there is nothing to do
* as this is used by the i2c probe to find devices. */
/*
* Terminate the transfer if there is nothing to do
* as this is used by the i2c probe to find devices.
*/
if (is_lastmsg(i2c) && i2c->msg->len == 0) {
s3c24xx_i2c_stop(i2c, 0);
goto out_ack;
@ -452,14 +443,16 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
if (i2c->state == STATE_READ)
goto prepare_read;
/* fall through to the write state, as we will need to
* send a byte as well */
case STATE_WRITE:
/* we are writing data to the device... check for the
* end of the message, and if so, work out what to do
/*
* fall through to the write state, as we will need to
* send a byte as well
*/
case STATE_WRITE:
/*
* we are writing data to the device... check for the
* end of the message, and if so, work out what to do
*/
if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
if (iicstat & S3C2410_IICSTAT_LASTBIT) {
dev_dbg(i2c->dev, "WRITE: No Ack\n");
@ -475,12 +468,13 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
byte = i2c->msg->buf[i2c->msg_ptr++];
writeb(byte, i2c->regs + S3C2410_IICDS);
/* delay after writing the byte to allow the
/*
* delay after writing the byte to allow the
* data setup time on the bus, as writing the
* data to the register causes the first bit
* to appear on SDA, and SCL will change as
* soon as the interrupt is acknowledged */
* soon as the interrupt is acknowledged
*/
ndelay(i2c->tx_setup);
} else if (!is_lastmsg(i2c)) {
@ -496,10 +490,11 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
if (i2c->msg->flags & I2C_M_NOSTART) {
if (i2c->msg->flags & I2C_M_RD) {
/* cannot do this, the controller
/*
* cannot do this, the controller
* forces us to send a new START
* when we change direction */
* when we change direction
*/
s3c24xx_i2c_stop(i2c, -EINVAL);
}
@ -512,17 +507,16 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
} else {
/* send stop */
s3c24xx_i2c_stop(i2c, 0);
}
break;
case STATE_READ:
/* we have a byte of data in the data register, do
/*
* we have a byte of data in the data register, do
* something with it, and then work out whether we are
* going to do any more read/write
*/
byte = readb(i2c->regs + S3C2410_IICDS);
i2c->msg->buf[i2c->msg_ptr++] = byte;
@ -537,9 +531,10 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
s3c24xx_i2c_disable_ack(i2c);
} else if (is_msgend(i2c)) {
/* ok, we've read the entire buffer, see if there
* is anything else we need to do */
/*
* ok, we've read the entire buffer, see if there
* is anything else we need to do
*/
if (is_lastmsg(i2c)) {
/* last message, send stop and complete */
dev_dbg(i2c->dev, "READ: Send Stop\n");
@ -568,11 +563,9 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
return ret;
}
/* s3c24xx_i2c_irq
*
/*
* top level IRQ servicing routine
*/
*/
static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
{
struct s3c24xx_i2c *i2c = dev_id;
@ -595,9 +588,10 @@ static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
goto out;
}
/* pretty much this leaves us with the fact that we've
* transmitted or received whatever byte we last sent */
/*
* pretty much this leaves us with the fact that we've
* transmitted or received whatever byte we last sent
*/
i2c_s3c_irq_nextbyte(i2c, status);
out:
@ -630,11 +624,9 @@ static inline void s3c24xx_i2c_disable_bus(struct s3c24xx_i2c *i2c)
}
/* s3c24xx_i2c_set_master
*
/*
* get the i2c bus for a master transaction
*/
*/
static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
{
unsigned long iicstat;
@ -652,11 +644,9 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
return -ETIMEDOUT;
}
/* s3c24xx_i2c_wait_idle
*
/*
* wait for the i2c bus to become idle.
*/
*/
static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c)
{
unsigned long iicstat;
@ -706,11 +696,9 @@ static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c)
dev_warn(i2c->dev, "timeout waiting for bus idle\n");
}
/* s3c24xx_i2c_doxfer
*
/*
* this starts an i2c transfer
*/
*/
static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
struct i2c_msg *msgs, int num)
{
@ -749,9 +737,10 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
ret = i2c->msg_idx;
/* having these next two as dev_err() makes life very
* noisy when doing an i2cdetect */
/*
* Having these next two as dev_err() makes life very
* noisy when doing an i2cdetect
*/
if (timeout == 0)
dev_dbg(i2c->dev, "timeout\n");
else if (ret != num)
@ -771,12 +760,10 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
return ret;
}
/* s3c24xx_i2c_xfer
*
/*
* first port of call from the i2c bus code when an message needs
* transferring across the i2c bus.
*/
*/
static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
@ -814,17 +801,14 @@ static u32 s3c24xx_i2c_func(struct i2c_adapter *adap)
}
/* i2c bus registration info */
static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
.master_xfer = s3c24xx_i2c_xfer,
.functionality = s3c24xx_i2c_func,
};
/* s3c24xx_i2c_calcdivisor
*
/*
* return the divisor settings for a given frequency
*/
*/
static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted,
unsigned int *div1, unsigned int *divs)
{
@ -850,13 +834,11 @@ static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted,
return clkin / (calc_divs * calc_div1);
}
/* s3c24xx_i2c_clockrate
*
/*
* work out a divisor for the user requested frequency setting,
* either by the requested frequency, or scanning the acceptable
* range of frequencies until something is found
*/
*/
static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)
{
struct s3c2410_platform_i2c *pdata = i2c->pdata;
@ -944,7 +926,7 @@ static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb,
i2c_unlock_adapter(&i2c->adap);
if (ret < 0)
dev_err(i2c->dev, "cannot find frequency\n");
dev_err(i2c->dev, "cannot find frequency (%d)\n", ret);
else
dev_info(i2c->dev, "setting freq %d\n", got);
}
@ -995,7 +977,8 @@ static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c)
ret = gpio_request(gpio, "i2c-bus");
if (ret) {
dev_err(i2c->dev, "gpio [%d] request failed\n", gpio);
dev_err(i2c->dev, "gpio [%d] request failed (%d)\n",
gpio, ret);
goto free_gpio;
}
}
@ -1028,11 +1011,9 @@ static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c)
}
#endif
/* s3c24xx_i2c_init
*
/*
* initialise the controller, set the IO lines and frequency
*/
*/
static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
{
struct s3c2410_platform_i2c *pdata;
@ -1068,11 +1049,9 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
}
#ifdef CONFIG_OF
/* s3c24xx_i2c_parse_dt
*
/*
* Parse the device tree node and retreive the platform data.
*/
*/
static void
s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
{
@ -1105,17 +1084,9 @@ s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
}
#else
static void
s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
{
return;
}
s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c) { }
#endif
/* s3c24xx_i2c_probe
*
* called by the bus driver when a suitable device is found
*/
static int s3c24xx_i2c_probe(struct platform_device *pdev)
{
struct s3c24xx_i2c *i2c;
@ -1156,7 +1127,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
init_waitqueue_head(&i2c->wait);
/* find the clock and enable it */
i2c->dev = &pdev->dev;
i2c->clk = devm_clk_get(&pdev->dev, "i2c");
if (IS_ERR(i2c->clk)) {
@ -1166,9 +1136,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
/* map the registers */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i2c->regs = devm_ioremap_resource(&pdev->dev, res);
@ -1179,33 +1147,35 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
i2c->regs, res);
/* setup info block for the i2c core */
i2c->adap.algo_data = i2c;
i2c->adap.dev.parent = &pdev->dev;
i2c->pctrl = devm_pinctrl_get_select_default(i2c->dev);
/* inititalise the i2c gpio lines */
if (i2c->pdata->cfg_gpio) {
if (i2c->pdata->cfg_gpio)
i2c->pdata->cfg_gpio(to_platform_device(i2c->dev));
} else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c)) {
else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c))
return -EINVAL;
}
/* initialise the i2c controller */
ret = clk_prepare_enable(i2c->clk);
if (ret) {
dev_err(&pdev->dev, "I2C clock enable failed\n");
return ret;
}
clk_prepare_enable(i2c->clk);
ret = s3c24xx_i2c_init(i2c);
clk_disable(i2c->clk);
if (ret != 0) {
dev_err(&pdev->dev, "I2C controller init failed\n");
clk_unprepare(i2c->clk);
return ret;
}
/* find the IRQ for this unit (note, this relies on the init call to
/*
* find the IRQ for this unit (note, this relies on the init call to
* ensure no current IRQs pending
*/
if (!(i2c->quirks & QUIRK_POLL)) {
i2c->irq = ret = platform_get_irq(pdev, 0);
if (ret <= 0) {
@ -1214,9 +1184,8 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
return ret;
}
ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq, 0,
dev_name(&pdev->dev), i2c);
ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq,
0, dev_name(&pdev->dev), i2c);
if (ret != 0) {
dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
clk_unprepare(i2c->clk);
@ -1231,12 +1200,12 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
return ret;
}
/* Note, previous versions of the driver used i2c_add_adapter()
/*
* Note, previous versions of the driver used i2c_add_adapter()
* to add the bus at any number. We now pass the bus number via
* the platform data, so if unset it will now default to always
* being bus 0.
*/
i2c->adap.nr = i2c->pdata->bus_num;
i2c->adap.dev.of_node = pdev->dev.of_node;
@ -1257,11 +1226,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
return 0;
}
/* s3c24xx_i2c_remove
*
* called when device is removed from the bus
*/
static int s3c24xx_i2c_remove(struct platform_device *pdev)
{
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
@ -1316,14 +1280,8 @@ static int s3c24xx_i2c_resume_noirq(struct device *dev)
#ifdef CONFIG_PM
static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = {
#ifdef CONFIG_PM_SLEEP
.suspend_noirq = s3c24xx_i2c_suspend_noirq,
.resume_noirq = s3c24xx_i2c_resume_noirq,
.freeze_noirq = s3c24xx_i2c_suspend_noirq,
.thaw_noirq = s3c24xx_i2c_resume_noirq,
.poweroff_noirq = s3c24xx_i2c_suspend_noirq,
.restore_noirq = s3c24xx_i2c_resume_noirq,
#endif
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(s3c24xx_i2c_suspend_noirq,
s3c24xx_i2c_resume_noirq)
};
#define S3C24XX_DEV_PM_OPS (&s3c24xx_i2c_dev_pm_ops)
@ -1331,8 +1289,6 @@ static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = {
#define S3C24XX_DEV_PM_OPS NULL
#endif
/* device driver for platform bus bits */
static struct platform_driver s3c24xx_i2c_driver = {
.probe = s3c24xx_i2c_probe,
.remove = s3c24xx_i2c_remove,

View File

@ -398,8 +398,7 @@ static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd,
{
switch (pd->pos) {
case -1:
*buf = (pd->msg->addr & 0x7f) << 1;
*buf |= (pd->msg->flags & I2C_M_RD) ? 1 : 0;
*buf = i2c_8bit_addr_from_msg(pd->msg);
break;
default:
*buf = pd->msg->buf[pd->pos];

View File

@ -190,9 +190,7 @@ static void i2c_sirfsoc_set_address(struct sirfsoc_i2c *siic,
writel(regval, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
addr = msg->addr << 1; /* Generate address */
if (msg->flags & I2C_M_RD)
addr |= 1;
addr = i2c_8bit_addr_from_msg(msg);
/* Reverse direction bit */
if (msg->flags & I2C_M_REV_DIR_ADDR)

View File

@ -337,10 +337,42 @@ static void st_i2c_hw_config(struct st_i2c_dev *i2c_dev)
writel_relaxed(val, i2c_dev->base + SSC_NOISE_SUPP_WIDTH_DATAOUT);
}
static int st_i2c_recover_bus(struct i2c_adapter *i2c_adap)
{
struct st_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
u32 ctl;
dev_dbg(i2c_dev->dev, "Trying to recover bus\n");
/*
* SSP IP is dual role SPI/I2C to generate 9 clock pulses
* we switch to SPI node, 9 bit words and write a 0. This
* has been validate with a oscilloscope and is easier
* than switching to GPIO mode.
*/
/* Disable interrupts */
writel_relaxed(0, i2c_dev->base + SSC_IEN);
st_i2c_hw_config(i2c_dev);
ctl = SSC_CTL_EN | SSC_CTL_MS | SSC_CTL_EN_RX_FIFO | SSC_CTL_EN_TX_FIFO;
st_i2c_set_bits(i2c_dev->base + SSC_CTL, ctl);
st_i2c_clr_bits(i2c_dev->base + SSC_I2C, SSC_I2C_I2CM);
usleep_range(8000, 10000);
writel_relaxed(0, i2c_dev->base + SSC_TBUF);
usleep_range(2000, 4000);
st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_I2CM);
return 0;
}
static int st_i2c_wait_free_bus(struct st_i2c_dev *i2c_dev)
{
u32 sta;
int i;
int i, ret;
for (i = 0; i < 10; i++) {
sta = readl_relaxed(i2c_dev->base + SSC_STA);
@ -352,6 +384,12 @@ static int st_i2c_wait_free_bus(struct st_i2c_dev *i2c_dev)
dev_err(i2c_dev->dev, "bus not free (status = 0x%08x)\n", sta);
ret = i2c_recover_bus(&i2c_dev->adap);
if (ret) {
dev_err(i2c_dev->dev, "Failed to recover the bus (%d)\n", ret);
return ret;
}
return -EBUSY;
}
@ -614,8 +652,7 @@ static int st_i2c_xfer_msg(struct st_i2c_dev *i2c_dev, struct i2c_msg *msg,
unsigned long timeout;
int ret;
c->addr = (u8)(msg->addr << 1);
c->addr |= (msg->flags & I2C_M_RD);
c->addr = i2c_8bit_addr_from_msg(msg);
c->buf = msg->buf;
c->count = msg->len;
c->xfered = 0;
@ -744,6 +781,10 @@ static struct i2c_algorithm st_i2c_algo = {
.functionality = st_i2c_func,
};
static struct i2c_bus_recovery_info st_i2c_recovery_info = {
.recover_bus = st_i2c_recover_bus,
};
static int st_i2c_of_get_deglitch(struct device_node *np,
struct st_i2c_dev *i2c_dev)
{
@ -826,6 +867,7 @@ static int st_i2c_probe(struct platform_device *pdev)
adap->timeout = 2 * HZ;
adap->retries = 0;
adap->algo = &st_i2c_algo;
adap->bus_recovery_info = &st_i2c_recovery_info;
adap->dev.parent = &pdev->dev;
adap->dev.of_node = pdev->dev.of_node;

View File

@ -38,6 +38,7 @@
#define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12
#define I2C_CNFG_PACKET_MODE_EN (1<<10)
#define I2C_CNFG_NEW_MASTER_FSM (1<<11)
#define I2C_CNFG_MULTI_MASTER_MODE (1<<17)
#define I2C_STATUS 0x01C
#define I2C_SL_CNFG 0x020
#define I2C_SL_CNFG_NACK (1<<1)
@ -106,6 +107,9 @@
#define I2C_SLV_CONFIG_LOAD (1 << 1)
#define I2C_TIMEOUT_CONFIG_LOAD (1 << 2)
#define I2C_CLKEN_OVERRIDE 0x090
#define I2C_MST_CORE_CLKEN_OVR (1 << 0)
/*
* msg_end_type: The bus control which need to be send at end of transfer.
* @MSG_END_STOP: Send stop pulse at end of transfer.
@ -143,6 +147,8 @@ struct tegra_i2c_hw_feature {
int clk_divisor_hs_mode;
int clk_divisor_std_fast_mode;
u16 clk_divisor_fast_plus_mode;
bool has_multi_master_mode;
bool has_slcg_override_reg;
};
/**
@ -184,6 +190,7 @@ struct tegra_i2c_dev {
u32 bus_clk_rate;
u16 clk_divisor_non_hs_mode;
bool is_suspended;
bool is_multimaster_mode;
};
static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned long reg)
@ -438,6 +445,10 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN |
(0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
if (i2c_dev->hw->has_multi_master_mode)
val |= I2C_CNFG_MULTI_MASTER_MODE;
i2c_writel(i2c_dev, val, I2C_CNFG);
i2c_writel(i2c_dev, 0, I2C_INT_MASK);
@ -463,25 +474,29 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
if (tegra_i2c_flush_fifos(i2c_dev))
err = -ETIMEDOUT;
if (i2c_dev->is_multimaster_mode && i2c_dev->hw->has_slcg_override_reg)
i2c_writel(i2c_dev, I2C_MST_CORE_CLKEN_OVR, I2C_CLKEN_OVERRIDE);
if (i2c_dev->hw->has_config_load_reg) {
i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD);
while (i2c_readl(i2c_dev, I2C_CONFIG_LOAD) != 0) {
if (time_after(jiffies, timeout)) {
dev_warn(i2c_dev->dev,
"timeout waiting for config load\n");
return -ETIMEDOUT;
err = -ETIMEDOUT;
goto err;
}
msleep(1);
}
}
tegra_i2c_clock_disable(i2c_dev);
if (i2c_dev->irq_disabled) {
i2c_dev->irq_disabled = 0;
enable_irq(i2c_dev->irq);
}
err:
tegra_i2c_clock_disable(i2c_dev);
return err;
}
@ -688,6 +703,20 @@ static u32 tegra_i2c_func(struct i2c_adapter *adap)
return ret;
}
static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev)
{
struct device_node *np = i2c_dev->dev->of_node;
int ret;
ret = of_property_read_u32(np, "clock-frequency",
&i2c_dev->bus_clk_rate);
if (ret)
i2c_dev->bus_clk_rate = 100000; /* default clock rate */
i2c_dev->is_multimaster_mode = of_property_read_bool(np,
"multi-master");
}
static const struct i2c_algorithm tegra_i2c_algo = {
.master_xfer = tegra_i2c_xfer,
.functionality = tegra_i2c_func,
@ -707,6 +736,8 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
.clk_divisor_std_fast_mode = 0,
.clk_divisor_fast_plus_mode = 0,
.has_config_load_reg = false,
.has_multi_master_mode = false,
.has_slcg_override_reg = false,
};
static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
@ -717,6 +748,8 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
.clk_divisor_std_fast_mode = 0,
.clk_divisor_fast_plus_mode = 0,
.has_config_load_reg = false,
.has_multi_master_mode = false,
.has_slcg_override_reg = false,
};
static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
@ -727,6 +760,8 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
.clk_divisor_std_fast_mode = 0x19,
.clk_divisor_fast_plus_mode = 0x10,
.has_config_load_reg = false,
.has_multi_master_mode = false,
.has_slcg_override_reg = false,
};
static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
@ -737,10 +772,25 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
.clk_divisor_std_fast_mode = 0x19,
.clk_divisor_fast_plus_mode = 0x10,
.has_config_load_reg = true,
.has_multi_master_mode = false,
.has_slcg_override_reg = true,
};
static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
.has_continue_xfer_support = true,
.has_per_pkt_xfer_complete_irq = true,
.has_single_clk_source = true,
.clk_divisor_hs_mode = 1,
.clk_divisor_std_fast_mode = 0x19,
.clk_divisor_fast_plus_mode = 0x10,
.has_config_load_reg = true,
.has_multi_master_mode = true,
.has_slcg_override_reg = true,
};
/* Match table for of_platform binding */
static const struct of_device_id tegra_i2c_of_match[] = {
{ .compatible = "nvidia,tegra210-i2c", .data = &tegra210_i2c_hw, },
{ .compatible = "nvidia,tegra124-i2c", .data = &tegra124_i2c_hw, },
{ .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, },
{ .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, },
@ -797,10 +847,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
return PTR_ERR(i2c_dev->rst);
}
ret = of_property_read_u32(i2c_dev->dev->of_node, "clock-frequency",
&i2c_dev->bus_clk_rate);
if (ret)
i2c_dev->bus_clk_rate = 100000; /* default clock rate */
tegra_i2c_parse_dt(i2c_dev);
i2c_dev->hw = &tegra20_i2c_hw;
@ -853,6 +900,15 @@ static int tegra_i2c_probe(struct platform_device *pdev)
goto unprepare_fast_clk;
}
if (i2c_dev->is_multimaster_mode) {
ret = clk_enable(i2c_dev->div_clk);
if (ret < 0) {
dev_err(i2c_dev->dev, "div_clk enable failed %d\n",
ret);
goto unprepare_div_clk;
}
}
ret = tegra_i2c_init(i2c_dev);
if (ret) {
dev_err(&pdev->dev, "Failed to initialize i2c controller");
@ -863,7 +919,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev);
if (ret) {
dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
goto unprepare_div_clk;
goto disable_div_clk;
}
i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
@ -878,11 +934,15 @@ static int tegra_i2c_probe(struct platform_device *pdev)
ret = i2c_add_numbered_adapter(&i2c_dev->adapter);
if (ret) {
dev_err(&pdev->dev, "Failed to add I2C adapter\n");
goto unprepare_div_clk;
goto disable_div_clk;
}
return 0;
disable_div_clk:
if (i2c_dev->is_multimaster_mode)
clk_disable(i2c_dev->div_clk);
unprepare_div_clk:
clk_unprepare(i2c_dev->div_clk);
@ -898,6 +958,9 @@ static int tegra_i2c_remove(struct platform_device *pdev)
struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
i2c_del_adapter(&i2c_dev->adapter);
if (i2c_dev->is_multimaster_mode)
clk_disable(i2c_dev->div_clk);
clk_unprepare(i2c_dev->div_clk);
if (!i2c_dev->hw->has_single_clk_source)
clk_unprepare(i2c_dev->fast_clk);

View File

@ -524,7 +524,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "failed to get IRQ number");
dev_err(dev, "failed to get IRQ number\n");
return irq;
}

View File

@ -381,7 +381,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "failed to get IRQ number");
dev_err(dev, "failed to get IRQ number\n");
return irq;
}

View File

@ -954,48 +954,40 @@ static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
}
/**
* i2c_lock_adapter - Get exclusive access to an I2C bus segment
* i2c_adapter_lock_bus - Get exclusive access to an I2C bus segment
* @adapter: Target I2C bus segment
* @flags: I2C_LOCK_ROOT_ADAPTER locks the root i2c adapter, I2C_LOCK_SEGMENT
* locks only this branch in the adapter tree
*/
void i2c_lock_adapter(struct i2c_adapter *adapter)
static void i2c_adapter_lock_bus(struct i2c_adapter *adapter,
unsigned int flags)
{
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
if (parent)
i2c_lock_adapter(parent);
else
rt_mutex_lock(&adapter->bus_lock);
}
EXPORT_SYMBOL_GPL(i2c_lock_adapter);
/**
* i2c_trylock_adapter - Try to get exclusive access to an I2C bus segment
* @adapter: Target I2C bus segment
*/
static int i2c_trylock_adapter(struct i2c_adapter *adapter)
{
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
if (parent)
return i2c_trylock_adapter(parent);
else
return rt_mutex_trylock(&adapter->bus_lock);
rt_mutex_lock(&adapter->bus_lock);
}
/**
* i2c_unlock_adapter - Release exclusive access to an I2C bus segment
* i2c_adapter_trylock_bus - Try to get exclusive access to an I2C bus segment
* @adapter: Target I2C bus segment
* @flags: I2C_LOCK_ROOT_ADAPTER trylocks the root i2c adapter, I2C_LOCK_SEGMENT
* trylocks only this branch in the adapter tree
*/
void i2c_unlock_adapter(struct i2c_adapter *adapter)
static int i2c_adapter_trylock_bus(struct i2c_adapter *adapter,
unsigned int flags)
{
struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
if (parent)
i2c_unlock_adapter(parent);
else
rt_mutex_unlock(&adapter->bus_lock);
return rt_mutex_trylock(&adapter->bus_lock);
}
/**
* i2c_adapter_unlock_bus - Release exclusive access to an I2C bus segment
* @adapter: Target I2C bus segment
* @flags: I2C_LOCK_ROOT_ADAPTER unlocks the root i2c adapter, I2C_LOCK_SEGMENT
* unlocks only this branch in the adapter tree
*/
static void i2c_adapter_unlock_bus(struct i2c_adapter *adapter,
unsigned int flags)
{
rt_mutex_unlock(&adapter->bus_lock);
}
EXPORT_SYMBOL_GPL(i2c_unlock_adapter);
static void i2c_dev_set_name(struct i2c_adapter *adap,
struct i2c_client *client)
@ -1541,7 +1533,14 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
return -EINVAL;
}
if (!adap->lock_bus) {
adap->lock_bus = i2c_adapter_lock_bus;
adap->trylock_bus = i2c_adapter_trylock_bus;
adap->unlock_bus = i2c_adapter_unlock_bus;
}
rt_mutex_init(&adap->bus_lock);
rt_mutex_init(&adap->mux_lock);
mutex_init(&adap->userspace_clients_lock);
INIT_LIST_HEAD(&adap->userspace_clients);
@ -1559,6 +1558,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
pm_runtime_no_callbacks(&adap->dev);
pm_suspend_ignore_children(&adap->dev, true);
pm_runtime_enable(&adap->dev);
#ifdef CONFIG_I2C_COMPAT
@ -1594,10 +1594,12 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
bri->get_scl = get_scl_gpio_value;
bri->set_scl = set_scl_gpio_value;
} else if (!bri->set_scl || !bri->get_scl) {
} else if (bri->recover_bus == i2c_generic_scl_recovery) {
/* Generic SCL recovery */
dev_err(&adap->dev, "No {get|set}_gpio() found, not using recovery\n");
adap->bus_recovery_info = NULL;
if (!bri->set_scl || !bri->get_scl) {
dev_err(&adap->dev, "No {get|set}_scl() found, not using recovery\n");
adap->bus_recovery_info = NULL;
}
}
}
@ -2309,16 +2311,16 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
#endif
if (in_atomic() || irqs_disabled()) {
ret = i2c_trylock_adapter(adap);
ret = adap->trylock_bus(adap, I2C_LOCK_SEGMENT);
if (!ret)
/* I2C activity is ongoing. */
return -EAGAIN;
} else {
i2c_lock_adapter(adap);
i2c_lock_bus(adap, I2C_LOCK_SEGMENT);
}
ret = __i2c_transfer(adap, msgs, num);
i2c_unlock_adapter(adap);
i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);
return ret;
} else {
@ -2646,7 +2648,7 @@ static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count)
static u8 i2c_smbus_msg_pec(u8 pec, struct i2c_msg *msg)
{
/* The address will be sent first */
u8 addr = (msg->addr << 1) | !!(msg->flags & I2C_M_RD);
u8 addr = i2c_8bit_addr_from_msg(msg);
pec = i2c_smbus_pec(pec, &addr, 1);
/* The data buffer follows */
@ -3093,7 +3095,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB;
if (adapter->algo->smbus_xfer) {
i2c_lock_adapter(adapter);
i2c_lock_bus(adapter, I2C_LOCK_SEGMENT);
/* Retry automatically on arbitration loss */
orig_jiffies = jiffies;
@ -3107,7 +3109,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
orig_jiffies + adapter->timeout))
break;
}
i2c_unlock_adapter(adapter);
i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT);
if (res != -EOPNOTSUPP || !adapter->algo->master_xfer)
goto trace;

View File

@ -31,30 +31,66 @@
struct i2c_mux_priv {
struct i2c_adapter adap;
struct i2c_algorithm algo;
struct i2c_adapter *parent;
struct device *mux_dev;
void *mux_priv;
struct i2c_mux_core *muxc;
u32 chan_id;
int (*select)(struct i2c_adapter *, void *mux_priv, u32 chan_id);
int (*deselect)(struct i2c_adapter *, void *mux_priv, u32 chan_id);
};
static int __i2c_mux_master_xfer(struct i2c_adapter *adap,
struct i2c_msg msgs[], int num)
{
struct i2c_mux_priv *priv = adap->algo_data;
struct i2c_mux_core *muxc = priv->muxc;
struct i2c_adapter *parent = muxc->parent;
int ret;
/* Switch to the right mux port and perform the transfer. */
ret = muxc->select(muxc, priv->chan_id);
if (ret >= 0)
ret = __i2c_transfer(parent, msgs, num);
if (muxc->deselect)
muxc->deselect(muxc, priv->chan_id);
return ret;
}
static int i2c_mux_master_xfer(struct i2c_adapter *adap,
struct i2c_msg msgs[], int num)
{
struct i2c_mux_priv *priv = adap->algo_data;
struct i2c_adapter *parent = priv->parent;
struct i2c_mux_core *muxc = priv->muxc;
struct i2c_adapter *parent = muxc->parent;
int ret;
/* Switch to the right mux port and perform the transfer. */
ret = priv->select(parent, priv->mux_priv, priv->chan_id);
ret = muxc->select(muxc, priv->chan_id);
if (ret >= 0)
ret = __i2c_transfer(parent, msgs, num);
if (priv->deselect)
priv->deselect(parent, priv->mux_priv, priv->chan_id);
ret = i2c_transfer(parent, msgs, num);
if (muxc->deselect)
muxc->deselect(muxc, priv->chan_id);
return ret;
}
static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap,
u16 addr, unsigned short flags,
char read_write, u8 command,
int size, union i2c_smbus_data *data)
{
struct i2c_mux_priv *priv = adap->algo_data;
struct i2c_mux_core *muxc = priv->muxc;
struct i2c_adapter *parent = muxc->parent;
int ret;
/* Select the right mux port and perform the transfer. */
ret = muxc->select(muxc, priv->chan_id);
if (ret >= 0)
ret = parent->algo->smbus_xfer(parent, addr, flags,
read_write, command, size, data);
if (muxc->deselect)
muxc->deselect(muxc, priv->chan_id);
return ret;
}
@ -65,17 +101,18 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
int size, union i2c_smbus_data *data)
{
struct i2c_mux_priv *priv = adap->algo_data;
struct i2c_adapter *parent = priv->parent;
struct i2c_mux_core *muxc = priv->muxc;
struct i2c_adapter *parent = muxc->parent;
int ret;
/* Select the right mux port and perform the transfer. */
ret = priv->select(parent, priv->mux_priv, priv->chan_id);
ret = muxc->select(muxc, priv->chan_id);
if (ret >= 0)
ret = parent->algo->smbus_xfer(parent, addr, flags,
read_write, command, size, data);
if (priv->deselect)
priv->deselect(parent, priv->mux_priv, priv->chan_id);
ret = i2c_smbus_xfer(parent, addr, flags,
read_write, command, size, data);
if (muxc->deselect)
muxc->deselect(muxc, priv->chan_id);
return ret;
}
@ -84,7 +121,7 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
static u32 i2c_mux_functionality(struct i2c_adapter *adap)
{
struct i2c_mux_priv *priv = adap->algo_data;
struct i2c_adapter *parent = priv->parent;
struct i2c_adapter *parent = priv->muxc->parent;
return parent->algo->functionality(parent);
}
@ -102,38 +139,167 @@ static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent)
return class;
}
struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
struct device *mux_dev,
void *mux_priv, u32 force_nr, u32 chan_id,
unsigned int class,
int (*select) (struct i2c_adapter *,
void *, u32),
int (*deselect) (struct i2c_adapter *,
void *, u32))
static void i2c_mux_lock_bus(struct i2c_adapter *adapter, unsigned int flags)
{
struct i2c_mux_priv *priv = adapter->algo_data;
struct i2c_adapter *parent = priv->muxc->parent;
rt_mutex_lock(&parent->mux_lock);
if (!(flags & I2C_LOCK_ROOT_ADAPTER))
return;
i2c_lock_bus(parent, flags);
}
static int i2c_mux_trylock_bus(struct i2c_adapter *adapter, unsigned int flags)
{
struct i2c_mux_priv *priv = adapter->algo_data;
struct i2c_adapter *parent = priv->muxc->parent;
if (!rt_mutex_trylock(&parent->mux_lock))
return 0; /* mux_lock not locked, failure */
if (!(flags & I2C_LOCK_ROOT_ADAPTER))
return 1; /* we only want mux_lock, success */
if (parent->trylock_bus(parent, flags))
return 1; /* parent locked too, success */
rt_mutex_unlock(&parent->mux_lock);
return 0; /* parent not locked, failure */
}
static void i2c_mux_unlock_bus(struct i2c_adapter *adapter, unsigned int flags)
{
struct i2c_mux_priv *priv = adapter->algo_data;
struct i2c_adapter *parent = priv->muxc->parent;
if (flags & I2C_LOCK_ROOT_ADAPTER)
i2c_unlock_bus(parent, flags);
rt_mutex_unlock(&parent->mux_lock);
}
static void i2c_parent_lock_bus(struct i2c_adapter *adapter,
unsigned int flags)
{
struct i2c_mux_priv *priv = adapter->algo_data;
struct i2c_adapter *parent = priv->muxc->parent;
rt_mutex_lock(&parent->mux_lock);
i2c_lock_bus(parent, flags);
}
static int i2c_parent_trylock_bus(struct i2c_adapter *adapter,
unsigned int flags)
{
struct i2c_mux_priv *priv = adapter->algo_data;
struct i2c_adapter *parent = priv->muxc->parent;
if (!rt_mutex_trylock(&parent->mux_lock))
return 0; /* mux_lock not locked, failure */
if (parent->trylock_bus(parent, flags))
return 1; /* parent locked too, success */
rt_mutex_unlock(&parent->mux_lock);
return 0; /* parent not locked, failure */
}
static void i2c_parent_unlock_bus(struct i2c_adapter *adapter,
unsigned int flags)
{
struct i2c_mux_priv *priv = adapter->algo_data;
struct i2c_adapter *parent = priv->muxc->parent;
i2c_unlock_bus(parent, flags);
rt_mutex_unlock(&parent->mux_lock);
}
struct i2c_adapter *i2c_root_adapter(struct device *dev)
{
struct device *i2c;
struct i2c_adapter *i2c_root;
/*
* Walk up the device tree to find an i2c adapter, indicating
* that this is an i2c client device. Check all ancestors to
* handle mfd devices etc.
*/
for (i2c = dev; i2c; i2c = i2c->parent) {
if (i2c->type == &i2c_adapter_type)
break;
}
if (!i2c)
return NULL;
/* Continue up the tree to find the root i2c adapter */
i2c_root = to_i2c_adapter(i2c);
while (i2c_parent_is_i2c_adapter(i2c_root))
i2c_root = i2c_parent_is_i2c_adapter(i2c_root);
return i2c_root;
}
EXPORT_SYMBOL_GPL(i2c_root_adapter);
struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
struct device *dev, int max_adapters,
int sizeof_priv, u32 flags,
int (*select)(struct i2c_mux_core *, u32),
int (*deselect)(struct i2c_mux_core *, u32))
{
struct i2c_mux_core *muxc;
muxc = devm_kzalloc(dev, sizeof(*muxc)
+ max_adapters * sizeof(muxc->adapter[0])
+ sizeof_priv, GFP_KERNEL);
if (!muxc)
return NULL;
if (sizeof_priv)
muxc->priv = &muxc->adapter[max_adapters];
muxc->parent = parent;
muxc->dev = dev;
if (flags & I2C_MUX_LOCKED)
muxc->mux_locked = true;
muxc->select = select;
muxc->deselect = deselect;
muxc->max_adapters = max_adapters;
return muxc;
}
EXPORT_SYMBOL_GPL(i2c_mux_alloc);
int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
u32 force_nr, u32 chan_id,
unsigned int class)
{
struct i2c_adapter *parent = muxc->parent;
struct i2c_mux_priv *priv;
char symlink_name[20];
int ret;
priv = kzalloc(sizeof(struct i2c_mux_priv), GFP_KERNEL);
if (muxc->num_adapters >= muxc->max_adapters) {
dev_err(muxc->dev, "No room for more i2c-mux adapters\n");
return -EINVAL;
}
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return NULL;
return -ENOMEM;
/* Set up private adapter data */
priv->parent = parent;
priv->mux_dev = mux_dev;
priv->mux_priv = mux_priv;
priv->muxc = muxc;
priv->chan_id = chan_id;
priv->select = select;
priv->deselect = deselect;
/* Need to do algo dynamically because we don't know ahead
* of time what sort of physical adapter we'll be dealing with.
*/
if (parent->algo->master_xfer)
priv->algo.master_xfer = i2c_mux_master_xfer;
if (parent->algo->smbus_xfer)
priv->algo.smbus_xfer = i2c_mux_smbus_xfer;
if (parent->algo->master_xfer) {
if (muxc->mux_locked)
priv->algo.master_xfer = i2c_mux_master_xfer;
else
priv->algo.master_xfer = __i2c_mux_master_xfer;
}
if (parent->algo->smbus_xfer) {
if (muxc->mux_locked)
priv->algo.smbus_xfer = i2c_mux_smbus_xfer;
else
priv->algo.smbus_xfer = __i2c_mux_smbus_xfer;
}
priv->algo.functionality = i2c_mux_functionality;
/* Now fill out new adapter structure */
@ -146,6 +312,15 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
priv->adap.retries = parent->retries;
priv->adap.timeout = parent->timeout;
priv->adap.quirks = parent->quirks;
if (muxc->mux_locked) {
priv->adap.lock_bus = i2c_mux_lock_bus;
priv->adap.trylock_bus = i2c_mux_trylock_bus;
priv->adap.unlock_bus = i2c_mux_unlock_bus;
} else {
priv->adap.lock_bus = i2c_parent_lock_bus;
priv->adap.trylock_bus = i2c_parent_trylock_bus;
priv->adap.unlock_bus = i2c_parent_unlock_bus;
}
/* Sanity check on class */
if (i2c_mux_parent_classes(parent) & class)
@ -159,11 +334,11 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
* Try to populate the mux adapter's of_node, expands to
* nothing if !CONFIG_OF.
*/
if (mux_dev->of_node) {
if (muxc->dev->of_node) {
struct device_node *child;
u32 reg;
for_each_child_of_node(mux_dev->of_node, child) {
for_each_child_of_node(muxc->dev->of_node, child) {
ret = of_property_read_u32(child, "reg", &reg);
if (ret)
continue;
@ -177,8 +352,9 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
/*
* Associate the mux channel with an ACPI node.
*/
if (has_acpi_companion(mux_dev))
acpi_preset_companion(&priv->adap.dev, ACPI_COMPANION(mux_dev),
if (has_acpi_companion(muxc->dev))
acpi_preset_companion(&priv->adap.dev,
ACPI_COMPANION(muxc->dev),
chan_id);
if (force_nr) {
@ -192,35 +368,45 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
"failed to add mux-adapter (error=%d)\n",
ret);
kfree(priv);
return NULL;
return ret;
}
WARN(sysfs_create_link(&priv->adap.dev.kobj, &mux_dev->kobj, "mux_device"),
"can't create symlink to mux device\n");
WARN(sysfs_create_link(&priv->adap.dev.kobj, &muxc->dev->kobj,
"mux_device"),
"can't create symlink to mux device\n");
snprintf(symlink_name, sizeof(symlink_name), "channel-%u", chan_id);
WARN(sysfs_create_link(&mux_dev->kobj, &priv->adap.dev.kobj, symlink_name),
"can't create symlink for channel %u\n", chan_id);
WARN(sysfs_create_link(&muxc->dev->kobj, &priv->adap.dev.kobj,
symlink_name),
"can't create symlink for channel %u\n", chan_id);
dev_info(&parent->dev, "Added multiplexed i2c bus %d\n",
i2c_adapter_id(&priv->adap));
return &priv->adap;
muxc->adapter[muxc->num_adapters++] = &priv->adap;
return 0;
}
EXPORT_SYMBOL_GPL(i2c_add_mux_adapter);
EXPORT_SYMBOL_GPL(i2c_mux_add_adapter);
void i2c_del_mux_adapter(struct i2c_adapter *adap)
void i2c_mux_del_adapters(struct i2c_mux_core *muxc)
{
struct i2c_mux_priv *priv = adap->algo_data;
char symlink_name[20];
snprintf(symlink_name, sizeof(symlink_name), "channel-%u", priv->chan_id);
sysfs_remove_link(&priv->mux_dev->kobj, symlink_name);
while (muxc->num_adapters) {
struct i2c_adapter *adap = muxc->adapter[--muxc->num_adapters];
struct i2c_mux_priv *priv = adap->algo_data;
sysfs_remove_link(&priv->adap.dev.kobj, "mux_device");
i2c_del_adapter(adap);
kfree(priv);
muxc->adapter[muxc->num_adapters] = NULL;
snprintf(symlink_name, sizeof(symlink_name),
"channel-%u", priv->chan_id);
sysfs_remove_link(&muxc->dev->kobj, symlink_name);
sysfs_remove_link(&priv->adap.dev.kobj, "mux_device");
i2c_del_adapter(adap);
kfree(priv);
}
}
EXPORT_SYMBOL_GPL(i2c_del_mux_adapter);
EXPORT_SYMBOL_GPL(i2c_mux_del_adapters);
MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
MODULE_DESCRIPTION("I2C driver for multiplexed I2C busses");

View File

@ -28,8 +28,6 @@
/**
* struct i2c_arbitrator_data - Driver data for I2C arbitrator
*
* @parent: Parent adapter
* @child: Child bus
* @our_gpio: GPIO we'll use to claim.
* @our_gpio_release: 0 if active high; 1 if active low; AKA if the GPIO ==
* this then consider it released.
@ -42,8 +40,6 @@
*/
struct i2c_arbitrator_data {
struct i2c_adapter *parent;
struct i2c_adapter *child;
int our_gpio;
int our_gpio_release;
int their_gpio;
@ -59,9 +55,9 @@ struct i2c_arbitrator_data {
*
* Use the GPIO-based signalling protocol; return -EBUSY if we fail.
*/
static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan)
static int i2c_arbitrator_select(struct i2c_mux_core *muxc, u32 chan)
{
const struct i2c_arbitrator_data *arb = data;
const struct i2c_arbitrator_data *arb = i2c_mux_priv(muxc);
unsigned long stop_retry, stop_time;
/* Start a round of trying to claim the bus */
@ -93,7 +89,7 @@ static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan)
/* Give up, release our claim */
gpio_set_value(arb->our_gpio, arb->our_gpio_release);
udelay(arb->slew_delay_us);
dev_err(&adap->dev, "Could not claim bus, timeout\n");
dev_err(muxc->dev, "Could not claim bus, timeout\n");
return -EBUSY;
}
@ -102,10 +98,9 @@ static int i2c_arbitrator_select(struct i2c_adapter *adap, void *data, u32 chan)
*
* Release the I2C bus using the GPIO-based signalling protocol.
*/
static int i2c_arbitrator_deselect(struct i2c_adapter *adap, void *data,
u32 chan)
static int i2c_arbitrator_deselect(struct i2c_mux_core *muxc, u32 chan)
{
const struct i2c_arbitrator_data *arb = data;
const struct i2c_arbitrator_data *arb = i2c_mux_priv(muxc);
/* Release the bus and wait for the other master to notice */
gpio_set_value(arb->our_gpio, arb->our_gpio_release);
@ -119,6 +114,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct device_node *parent_np;
struct i2c_mux_core *muxc;
struct i2c_arbitrator_data *arb;
enum of_gpio_flags gpio_flags;
unsigned long out_init;
@ -134,12 +130,13 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
return -EINVAL;
}
arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL);
if (!arb) {
dev_err(dev, "Cannot allocate i2c_arbitrator_data\n");
muxc = i2c_mux_alloc(NULL, dev, 1, sizeof(*arb), 0,
i2c_arbitrator_select, i2c_arbitrator_deselect);
if (!muxc)
return -ENOMEM;
}
platform_set_drvdata(pdev, arb);
arb = i2c_mux_priv(muxc);
platform_set_drvdata(pdev, muxc);
/* Request GPIOs */
ret = of_get_named_gpio_flags(np, "our-claim-gpio", 0, &gpio_flags);
@ -196,21 +193,18 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
dev_err(dev, "Cannot parse i2c-parent\n");
return -EINVAL;
}
arb->parent = of_get_i2c_adapter_by_node(parent_np);
muxc->parent = of_get_i2c_adapter_by_node(parent_np);
of_node_put(parent_np);
if (!arb->parent) {
if (!muxc->parent) {
dev_err(dev, "Cannot find parent bus\n");
return -EPROBE_DEFER;
}
/* Actually add the mux adapter */
arb->child = i2c_add_mux_adapter(arb->parent, dev, arb, 0, 0, 0,
i2c_arbitrator_select,
i2c_arbitrator_deselect);
if (!arb->child) {
ret = i2c_mux_add_adapter(muxc, 0, 0, 0);
if (ret) {
dev_err(dev, "Failed to add adapter\n");
ret = -ENODEV;
i2c_put_adapter(arb->parent);
i2c_put_adapter(muxc->parent);
}
return ret;
@ -218,11 +212,10 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
static int i2c_arbitrator_remove(struct platform_device *pdev)
{
struct i2c_arbitrator_data *arb = platform_get_drvdata(pdev);
i2c_del_mux_adapter(arb->child);
i2c_put_adapter(arb->parent);
struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
i2c_mux_del_adapters(muxc);
i2c_put_adapter(muxc->parent);
return 0;
}

View File

@ -15,11 +15,10 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include "../../gpio/gpiolib.h"
#include <linux/of_gpio.h>
struct gpiomux {
struct i2c_adapter *parent;
struct i2c_adapter **adap; /* child busses */
struct i2c_mux_gpio_platform_data data;
unsigned gpio_base;
};
@ -33,18 +32,18 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val)
val & (1 << i));
}
static int i2c_mux_gpio_select(struct i2c_adapter *adap, void *data, u32 chan)
static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan)
{
struct gpiomux *mux = data;
struct gpiomux *mux = i2c_mux_priv(muxc);
i2c_mux_gpio_set(mux, chan);
return 0;
}
static int i2c_mux_gpio_deselect(struct i2c_adapter *adap, void *data, u32 chan)
static int i2c_mux_gpio_deselect(struct i2c_mux_core *muxc, u32 chan)
{
struct gpiomux *mux = data;
struct gpiomux *mux = i2c_mux_priv(muxc);
i2c_mux_gpio_set(mux, mux->data.idle);
@ -136,19 +135,16 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
static int i2c_mux_gpio_probe(struct platform_device *pdev)
{
struct i2c_mux_core *muxc;
struct gpiomux *mux;
struct i2c_adapter *parent;
int (*deselect) (struct i2c_adapter *, void *, u32);
struct i2c_adapter *root;
unsigned initial_state, gpio_base;
int i, ret;
mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
if (!mux) {
dev_err(&pdev->dev, "Cannot allocate gpiomux structure");
if (!mux)
return -ENOMEM;
}
platform_set_drvdata(pdev, mux);
if (!dev_get_platdata(&pdev->dev)) {
ret = i2c_mux_gpio_probe_dt(mux, pdev);
@ -180,27 +176,32 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
if (!parent)
return -EPROBE_DEFER;
mux->parent = parent;
mux->gpio_base = gpio_base;
mux->adap = devm_kzalloc(&pdev->dev,
sizeof(*mux->adap) * mux->data.n_values,
GFP_KERNEL);
if (!mux->adap) {
dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure");
muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, 0, 0,
i2c_mux_gpio_select, NULL);
if (!muxc) {
ret = -ENOMEM;
goto alloc_failed;
}
muxc->priv = mux;
platform_set_drvdata(pdev, muxc);
root = i2c_root_adapter(&parent->dev);
muxc->mux_locked = true;
mux->gpio_base = gpio_base;
if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) {
initial_state = mux->data.idle;
deselect = i2c_mux_gpio_deselect;
muxc->deselect = i2c_mux_gpio_deselect;
} else {
initial_state = mux->data.values[0];
deselect = NULL;
}
for (i = 0; i < mux->data.n_gpios; i++) {
struct device *gpio_dev;
struct gpio_desc *gpio_desc;
ret = gpio_request(gpio_base + mux->data.gpios[i], "i2c-mux-gpio");
if (ret) {
dev_err(&pdev->dev, "Failed to request GPIO %d\n",
@ -217,17 +218,24 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
i++; /* gpio_request above succeeded, so must free */
goto err_request_gpio;
}
if (!muxc->mux_locked)
continue;
gpio_desc = gpio_to_desc(gpio_base + mux->data.gpios[i]);
gpio_dev = &gpio_desc->gdev->dev;
muxc->mux_locked = i2c_root_adapter(gpio_dev) == root;
}
if (muxc->mux_locked)
dev_info(&pdev->dev, "mux-locked i2c mux\n");
for (i = 0; i < mux->data.n_values; i++) {
u32 nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0;
unsigned int class = mux->data.classes ? mux->data.classes[i] : 0;
mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr,
mux->data.values[i], class,
i2c_mux_gpio_select, deselect);
if (!mux->adap[i]) {
ret = -ENODEV;
ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class);
if (ret) {
dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
goto add_adapter_failed;
}
@ -239,8 +247,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
return 0;
add_adapter_failed:
for (; i > 0; i--)
i2c_del_mux_adapter(mux->adap[i - 1]);
i2c_mux_del_adapters(muxc);
i = mux->data.n_gpios;
err_request_gpio:
for (; i > 0; i--)
@ -253,16 +260,16 @@ alloc_failed:
static int i2c_mux_gpio_remove(struct platform_device *pdev)
{
struct gpiomux *mux = platform_get_drvdata(pdev);
struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
struct gpiomux *mux = i2c_mux_priv(muxc);
int i;
for (i = 0; i < mux->data.n_values; i++)
i2c_del_mux_adapter(mux->adap[i]);
i2c_mux_del_adapters(muxc);
for (i = 0; i < mux->data.n_gpios; i++)
gpio_free(mux->gpio_base + mux->data.gpios[i]);
i2c_put_adapter(mux->parent);
i2c_put_adapter(muxc->parent);
return 0;
}

View File

@ -73,7 +73,7 @@
#define SELECT_DELAY_LONG 1000
struct pca9541 {
struct i2c_adapter *mux_adap;
struct i2c_client *client;
unsigned long select_timeout;
unsigned long arb_timeout;
};
@ -217,7 +217,8 @@ static const u8 pca9541_control[16] = {
*/
static int pca9541_arbitrate(struct i2c_client *client)
{
struct pca9541 *data = i2c_get_clientdata(client);
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
struct pca9541 *data = i2c_mux_priv(muxc);
int reg;
reg = pca9541_reg_read(client, PCA9541_CONTROL);
@ -285,9 +286,10 @@ static int pca9541_arbitrate(struct i2c_client *client)
return 0;
}
static int pca9541_select_chan(struct i2c_adapter *adap, void *client, u32 chan)
static int pca9541_select_chan(struct i2c_mux_core *muxc, u32 chan)
{
struct pca9541 *data = i2c_get_clientdata(client);
struct pca9541 *data = i2c_mux_priv(muxc);
struct i2c_client *client = data->client;
int ret;
unsigned long timeout = jiffies + ARB2_TIMEOUT;
/* give up after this time */
@ -309,9 +311,11 @@ static int pca9541_select_chan(struct i2c_adapter *adap, void *client, u32 chan)
return -ETIMEDOUT;
}
static int pca9541_release_chan(struct i2c_adapter *adap,
void *client, u32 chan)
static int pca9541_release_chan(struct i2c_mux_core *muxc, u32 chan)
{
struct pca9541 *data = i2c_mux_priv(muxc);
struct i2c_client *client = data->client;
pca9541_release_bus(client);
return 0;
}
@ -324,20 +328,13 @@ static int pca9541_probe(struct i2c_client *client,
{
struct i2c_adapter *adap = client->adapter;
struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
struct i2c_mux_core *muxc;
struct pca9541 *data;
int force;
int ret = -ENODEV;
int ret;
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA))
goto err;
data = kzalloc(sizeof(struct pca9541), GFP_KERNEL);
if (!data) {
ret = -ENOMEM;
goto err;
}
i2c_set_clientdata(client, data);
return -ENODEV;
/*
* I2C accesses are unprotected here.
@ -352,34 +349,33 @@ static int pca9541_probe(struct i2c_client *client,
force = 0;
if (pdata)
force = pdata->modes[0].adap_id;
data->mux_adap = i2c_add_mux_adapter(adap, &client->dev, client,
force, 0, 0,
pca9541_select_chan,
pca9541_release_chan);
muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), 0,
pca9541_select_chan, pca9541_release_chan);
if (!muxc)
return -ENOMEM;
if (data->mux_adap == NULL) {
data = i2c_mux_priv(muxc);
data->client = client;
i2c_set_clientdata(client, muxc);
ret = i2c_mux_add_adapter(muxc, force, 0, 0);
if (ret) {
dev_err(&client->dev, "failed to register master selector\n");
goto exit_free;
return ret;
}
dev_info(&client->dev, "registered master selector for I2C %s\n",
client->name);
return 0;
exit_free:
kfree(data);
err:
return ret;
}
static int pca9541_remove(struct i2c_client *client)
{
struct pca9541 *data = i2c_get_clientdata(client);
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
i2c_del_mux_adapter(data->mux_adap);
kfree(data);
i2c_mux_del_adapters(muxc);
return 0;
}

View File

@ -60,9 +60,10 @@ enum pca_type {
struct pca954x {
enum pca_type type;
struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS];
u8 last_chan; /* last register value */
u8 deselect;
struct i2c_client *client;
};
struct chip_desc {
@ -146,10 +147,10 @@ static int pca954x_reg_write(struct i2c_adapter *adap,
return ret;
}
static int pca954x_select_chan(struct i2c_adapter *adap,
void *client, u32 chan)
static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
{
struct pca954x *data = i2c_get_clientdata(client);
struct pca954x *data = i2c_mux_priv(muxc);
struct i2c_client *client = data->client;
const struct chip_desc *chip = &chips[data->type];
u8 regval;
int ret = 0;
@ -162,21 +163,24 @@ static int pca954x_select_chan(struct i2c_adapter *adap,
/* Only select the channel if its different from the last channel */
if (data->last_chan != regval) {
ret = pca954x_reg_write(adap, client, regval);
ret = pca954x_reg_write(muxc->parent, client, regval);
data->last_chan = regval;
}
return ret;
}
static int pca954x_deselect_mux(struct i2c_adapter *adap,
void *client, u32 chan)
static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
{
struct pca954x *data = i2c_get_clientdata(client);
struct pca954x *data = i2c_mux_priv(muxc);
struct i2c_client *client = data->client;
if (!(data->deselect & (1 << chan)))
return 0;
/* Deselect active channel */
data->last_chan = 0;
return pca954x_reg_write(adap, client, data->last_chan);
return pca954x_reg_write(muxc->parent, client, data->last_chan);
}
/*
@ -191,17 +195,22 @@ static int pca954x_probe(struct i2c_client *client,
bool idle_disconnect_dt;
struct gpio_desc *gpio;
int num, force, class;
struct i2c_mux_core *muxc;
struct pca954x *data;
int ret;
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
return -ENODEV;
data = devm_kzalloc(&client->dev, sizeof(struct pca954x), GFP_KERNEL);
if (!data)
muxc = i2c_mux_alloc(adap, &client->dev,
PCA954X_MAX_NCHANS, sizeof(*data), 0,
pca954x_select_chan, pca954x_deselect_mux);
if (!muxc)
return -ENOMEM;
data = i2c_mux_priv(muxc);
i2c_set_clientdata(client, data);
i2c_set_clientdata(client, muxc);
data->client = client;
/* Get the mux out of reset if a reset GPIO is specified. */
gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW);
@ -238,16 +247,13 @@ static int pca954x_probe(struct i2c_client *client,
/* discard unconfigured channels */
break;
idle_disconnect_pd = pdata->modes[num].deselect_on_exit;
data->deselect |= (idle_disconnect_pd
|| idle_disconnect_dt) << num;
}
data->virt_adaps[num] =
i2c_add_mux_adapter(adap, &client->dev, client,
force, num, class, pca954x_select_chan,
(idle_disconnect_pd || idle_disconnect_dt)
? pca954x_deselect_mux : NULL);
ret = i2c_mux_add_adapter(muxc, force, num, class);
if (data->virt_adaps[num] == NULL) {
ret = -ENODEV;
if (ret) {
dev_err(&client->dev,
"failed to register multiplexed adapter"
" %d as bus %d\n", num, force);
@ -263,23 +269,15 @@ static int pca954x_probe(struct i2c_client *client,
return 0;
virt_reg_failed:
for (num--; num >= 0; num--)
i2c_del_mux_adapter(data->virt_adaps[num]);
i2c_mux_del_adapters(muxc);
return ret;
}
static int pca954x_remove(struct i2c_client *client)
{
struct pca954x *data = i2c_get_clientdata(client);
const struct chip_desc *chip = &chips[data->type];
int i;
for (i = 0; i < chip->nchans; ++i)
if (data->virt_adaps[i]) {
i2c_del_mux_adapter(data->virt_adaps[i]);
data->virt_adaps[i] = NULL;
}
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
i2c_mux_del_adapters(muxc);
return 0;
}
@ -287,7 +285,8 @@ static int pca954x_remove(struct i2c_client *client)
static int pca954x_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct pca954x *data = i2c_get_clientdata(client);
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
struct pca954x *data = i2c_mux_priv(muxc);
data->last_chan = 0;
return i2c_smbus_write_byte(client, 0);

View File

@ -24,36 +24,32 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include "../../pinctrl/core.h"
struct i2c_mux_pinctrl {
struct device *dev;
struct i2c_mux_pinctrl_platform_data *pdata;
struct pinctrl *pinctrl;
struct pinctrl_state **states;
struct pinctrl_state *state_idle;
struct i2c_adapter *parent;
struct i2c_adapter **busses;
};
static int i2c_mux_pinctrl_select(struct i2c_adapter *adap, void *data,
u32 chan)
static int i2c_mux_pinctrl_select(struct i2c_mux_core *muxc, u32 chan)
{
struct i2c_mux_pinctrl *mux = data;
struct i2c_mux_pinctrl *mux = i2c_mux_priv(muxc);
return pinctrl_select_state(mux->pinctrl, mux->states[chan]);
}
static int i2c_mux_pinctrl_deselect(struct i2c_adapter *adap, void *data,
u32 chan)
static int i2c_mux_pinctrl_deselect(struct i2c_mux_core *muxc, u32 chan)
{
struct i2c_mux_pinctrl *mux = data;
struct i2c_mux_pinctrl *mux = i2c_mux_priv(muxc);
return pinctrl_select_state(mux->pinctrl, mux->state_idle);
}
#ifdef CONFIG_OF
static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
struct platform_device *pdev)
struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
int num_names, i, ret;
@ -64,15 +60,12 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
return 0;
mux->pdata = devm_kzalloc(&pdev->dev, sizeof(*mux->pdata), GFP_KERNEL);
if (!mux->pdata) {
dev_err(mux->dev,
"Cannot allocate i2c_mux_pinctrl_platform_data\n");
if (!mux->pdata)
return -ENOMEM;
}
num_names = of_property_count_strings(np, "pinctrl-names");
if (num_names < 0) {
dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
dev_err(&pdev->dev, "Cannot parse pinctrl-names: %d\n",
num_names);
return num_names;
}
@ -80,23 +73,22 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
mux->pdata->pinctrl_states = devm_kzalloc(&pdev->dev,
sizeof(*mux->pdata->pinctrl_states) * num_names,
GFP_KERNEL);
if (!mux->pdata->pinctrl_states) {
dev_err(mux->dev, "Cannot allocate pinctrl_states\n");
if (!mux->pdata->pinctrl_states)
return -ENOMEM;
}
for (i = 0; i < num_names; i++) {
ret = of_property_read_string_index(np, "pinctrl-names", i,
&mux->pdata->pinctrl_states[mux->pdata->bus_count]);
if (ret < 0) {
dev_err(mux->dev, "Cannot parse pinctrl-names: %d\n",
dev_err(&pdev->dev, "Cannot parse pinctrl-names: %d\n",
ret);
return ret;
}
if (!strcmp(mux->pdata->pinctrl_states[mux->pdata->bus_count],
"idle")) {
if (i != num_names - 1) {
dev_err(mux->dev, "idle state must be last\n");
dev_err(&pdev->dev,
"idle state must be last\n");
return -EINVAL;
}
mux->pdata->pinctrl_state_idle = "idle";
@ -107,13 +99,13 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
adapter_np = of_parse_phandle(np, "i2c-parent", 0);
if (!adapter_np) {
dev_err(mux->dev, "Cannot parse i2c-parent\n");
dev_err(&pdev->dev, "Cannot parse i2c-parent\n");
return -ENODEV;
}
adapter = of_find_i2c_adapter_by_node(adapter_np);
of_node_put(adapter_np);
if (!adapter) {
dev_err(mux->dev, "Cannot find parent bus\n");
dev_err(&pdev->dev, "Cannot find parent bus\n");
return -EPROBE_DEFER;
}
mux->pdata->parent_bus_num = i2c_adapter_id(adapter);
@ -129,21 +121,38 @@ static inline int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
}
#endif
static struct i2c_adapter *i2c_mux_pinctrl_root_adapter(
struct pinctrl_state *state)
{
struct i2c_adapter *root = NULL;
struct pinctrl_setting *setting;
struct i2c_adapter *pin_root;
list_for_each_entry(setting, &state->settings, node) {
pin_root = i2c_root_adapter(setting->pctldev->dev);
if (!pin_root)
return NULL;
if (!root)
root = pin_root;
else if (root != pin_root)
return NULL;
}
return root;
}
static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
{
struct i2c_mux_core *muxc;
struct i2c_mux_pinctrl *mux;
int (*deselect)(struct i2c_adapter *, void *, u32);
struct i2c_adapter *root;
int i, ret;
mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
if (!mux) {
dev_err(&pdev->dev, "Cannot allocate i2c_mux_pinctrl\n");
ret = -ENOMEM;
goto err;
}
platform_set_drvdata(pdev, mux);
mux->dev = &pdev->dev;
mux->pdata = dev_get_platdata(&pdev->dev);
if (!mux->pdata) {
@ -166,14 +175,15 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
goto err;
}
mux->busses = devm_kzalloc(&pdev->dev,
sizeof(*mux->busses) * mux->pdata->bus_count,
GFP_KERNEL);
if (!mux->busses) {
dev_err(&pdev->dev, "Cannot allocate busses\n");
muxc = i2c_mux_alloc(NULL, &pdev->dev, mux->pdata->bus_count, 0, 0,
i2c_mux_pinctrl_select, NULL);
if (!muxc) {
ret = -ENOMEM;
goto err;
}
muxc->priv = mux;
platform_set_drvdata(pdev, muxc);
mux->pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(mux->pinctrl)) {
@ -184,13 +194,13 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
for (i = 0; i < mux->pdata->bus_count; i++) {
mux->states[i] = pinctrl_lookup_state(mux->pinctrl,
mux->pdata->pinctrl_states[i]);
if (IS_ERR(mux->states[i])) {
ret = PTR_ERR(mux->states[i]);
dev_err(&pdev->dev,
"Cannot look up pinctrl state %s: %d\n",
mux->pdata->pinctrl_states[i], ret);
goto err;
}
if (IS_ERR(mux->states[i])) {
ret = PTR_ERR(mux->states[i]);
dev_err(&pdev->dev,
"Cannot look up pinctrl state %s: %d\n",
mux->pdata->pinctrl_states[i], ret);
goto err;
}
}
if (mux->pdata->pinctrl_state_idle) {
mux->state_idle = pinctrl_lookup_state(mux->pinctrl,
@ -203,29 +213,39 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
goto err;
}
deselect = i2c_mux_pinctrl_deselect;
} else {
deselect = NULL;
muxc->deselect = i2c_mux_pinctrl_deselect;
}
mux->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
if (!mux->parent) {
muxc->parent = i2c_get_adapter(mux->pdata->parent_bus_num);
if (!muxc->parent) {
dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
mux->pdata->parent_bus_num);
ret = -EPROBE_DEFER;
goto err;
}
root = i2c_root_adapter(&muxc->parent->dev);
muxc->mux_locked = true;
for (i = 0; i < mux->pdata->bus_count; i++) {
if (root != i2c_mux_pinctrl_root_adapter(mux->states[i])) {
muxc->mux_locked = false;
break;
}
}
if (muxc->mux_locked && mux->pdata->pinctrl_state_idle &&
root != i2c_mux_pinctrl_root_adapter(mux->state_idle))
muxc->mux_locked = false;
if (muxc->mux_locked)
dev_info(&pdev->dev, "mux-locked i2c mux\n");
for (i = 0; i < mux->pdata->bus_count; i++) {
u32 bus = mux->pdata->base_bus_num ?
(mux->pdata->base_bus_num + i) : 0;
mux->busses[i] = i2c_add_mux_adapter(mux->parent, &pdev->dev,
mux, bus, i, 0,
i2c_mux_pinctrl_select,
deselect);
if (!mux->busses[i]) {
ret = -ENODEV;
ret = i2c_mux_add_adapter(muxc, bus, i, 0);
if (ret) {
dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
goto err_del_adapter;
}
@ -234,23 +254,18 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
return 0;
err_del_adapter:
for (; i > 0; i--)
i2c_del_mux_adapter(mux->busses[i - 1]);
i2c_put_adapter(mux->parent);
i2c_mux_del_adapters(muxc);
i2c_put_adapter(muxc->parent);
err:
return ret;
}
static int i2c_mux_pinctrl_remove(struct platform_device *pdev)
{
struct i2c_mux_pinctrl *mux = platform_get_drvdata(pdev);
int i;
for (i = 0; i < mux->pdata->bus_count; i++)
i2c_del_mux_adapter(mux->busses[i]);
i2c_put_adapter(mux->parent);
struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
i2c_mux_del_adapters(muxc);
i2c_put_adapter(muxc->parent);
return 0;
}

View File

@ -21,8 +21,6 @@
#include <linux/slab.h>
struct regmux {
struct i2c_adapter *parent;
struct i2c_adapter **adap; /* child busses */
struct i2c_mux_reg_platform_data data;
};
@ -64,18 +62,16 @@ static int i2c_mux_reg_set(const struct regmux *mux, unsigned int chan_id)
return 0;
}
static int i2c_mux_reg_select(struct i2c_adapter *adap, void *data,
unsigned int chan)
static int i2c_mux_reg_select(struct i2c_mux_core *muxc, u32 chan)
{
struct regmux *mux = data;
struct regmux *mux = i2c_mux_priv(muxc);
return i2c_mux_reg_set(mux, chan);
}
static int i2c_mux_reg_deselect(struct i2c_adapter *adap, void *data,
unsigned int chan)
static int i2c_mux_reg_deselect(struct i2c_mux_core *muxc, u32 chan)
{
struct regmux *mux = data;
struct regmux *mux = i2c_mux_priv(muxc);
if (mux->data.idle_in_use)
return i2c_mux_reg_set(mux, mux->data.idle);
@ -85,7 +81,7 @@ static int i2c_mux_reg_deselect(struct i2c_adapter *adap, void *data,
#ifdef CONFIG_OF
static int i2c_mux_reg_probe_dt(struct regmux *mux,
struct platform_device *pdev)
struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct device_node *adapter_np, *child;
@ -107,7 +103,6 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
if (!adapter)
return -EPROBE_DEFER;
mux->parent = adapter;
mux->data.parent = i2c_adapter_id(adapter);
put_device(&adapter->dev);
@ -161,7 +156,7 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
}
#else
static int i2c_mux_reg_probe_dt(struct regmux *mux,
struct platform_device *pdev)
struct platform_device *pdev)
{
return 0;
}
@ -169,10 +164,10 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux,
static int i2c_mux_reg_probe(struct platform_device *pdev)
{
struct i2c_mux_core *muxc;
struct regmux *mux;
struct i2c_adapter *parent;
struct resource *res;
int (*deselect)(struct i2c_adapter *, void *, u32);
unsigned int class;
int i, ret, nr;
@ -180,17 +175,9 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
if (!mux)
return -ENOMEM;
platform_set_drvdata(pdev, mux);
if (dev_get_platdata(&pdev->dev)) {
memcpy(&mux->data, dev_get_platdata(&pdev->dev),
sizeof(mux->data));
parent = i2c_get_adapter(mux->data.parent);
if (!parent)
return -EPROBE_DEFER;
mux->parent = parent;
} else {
ret = i2c_mux_reg_probe_dt(mux, pdev);
if (ret < 0) {
@ -199,6 +186,10 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
}
}
parent = i2c_get_adapter(mux->data.parent);
if (!parent)
return -EPROBE_DEFER;
if (!mux->data.reg) {
dev_info(&pdev->dev,
"Register not set, using platform resource\n");
@ -215,55 +206,45 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
return -EINVAL;
}
mux->adap = devm_kzalloc(&pdev->dev,
sizeof(*mux->adap) * mux->data.n_values,
GFP_KERNEL);
if (!mux->adap) {
dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure");
muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, 0, 0,
i2c_mux_reg_select, NULL);
if (!muxc)
return -ENOMEM;
}
muxc->priv = mux;
platform_set_drvdata(pdev, muxc);
if (mux->data.idle_in_use)
deselect = i2c_mux_reg_deselect;
else
deselect = NULL;
muxc->deselect = i2c_mux_reg_deselect;
for (i = 0; i < mux->data.n_values; i++) {
nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0;
class = mux->data.classes ? mux->data.classes[i] : 0;
mux->adap[i] = i2c_add_mux_adapter(mux->parent, &pdev->dev, mux,
nr, mux->data.values[i],
class, i2c_mux_reg_select,
deselect);
if (!mux->adap[i]) {
ret = -ENODEV;
ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class);
if (ret) {
dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
goto add_adapter_failed;
}
}
dev_dbg(&pdev->dev, "%d port mux on %s adapter\n",
mux->data.n_values, mux->parent->name);
mux->data.n_values, muxc->parent->name);
return 0;
add_adapter_failed:
for (; i > 0; i--)
i2c_del_mux_adapter(mux->adap[i - 1]);
i2c_mux_del_adapters(muxc);
return ret;
}
static int i2c_mux_reg_remove(struct platform_device *pdev)
{
struct regmux *mux = platform_get_drvdata(pdev);
int i;
struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
for (i = 0; i < mux->data.n_values; i++)
i2c_del_mux_adapter(mux->adap[i]);
i2c_put_adapter(mux->parent);
i2c_mux_del_adapters(muxc);
i2c_put_adapter(muxc->parent);
return 0;
}

View File

@ -183,7 +183,7 @@ int inv_mpu_acpi_create_mux_client(struct i2c_client *client)
} else
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)
return -ENODEV;
}

View File

@ -23,7 +23,6 @@
#include <linux/kfifo.h>
#include <linux/spinlock.h>
#include <linux/iio/iio.h>
#include <linux/i2c-mux.h>
#include <linux/acpi.h>
#include "inv_mpu_iio.h"

View File

@ -15,7 +15,6 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
#include "inv_mpu_iio.h"
@ -25,46 +24,16 @@ static const struct regmap_config inv_mpu_regmap_config = {
.val_bits = 8,
};
/*
* The i2c read/write needs to happen in unlocked mode. As the parent
* adapter is common. If we use locked versions, it will fail as
* the mux adapter will lock the parent i2c adapter, while calling
* select/deselect functions.
*/
static int inv_mpu6050_write_reg_unlocked(struct i2c_client *client,
u8 reg, u8 d)
static int inv_mpu6050_select_bypass(struct i2c_mux_core *muxc, u32 chan_id)
{
int ret;
u8 buf[2] = {reg, d};
struct i2c_msg msg[1] = {
{
.addr = client->addr,
.flags = 0,
.len = sizeof(buf),
.buf = buf,
}
};
ret = __i2c_transfer(client->adapter, msg, 1);
if (ret != 1)
return ret;
return 0;
}
static int inv_mpu6050_select_bypass(struct i2c_adapter *adap, void *mux_priv,
u32 chan_id)
{
struct i2c_client *client = mux_priv;
struct iio_dev *indio_dev = dev_get_drvdata(&client->dev);
struct iio_dev *indio_dev = i2c_mux_priv(muxc);
struct inv_mpu6050_state *st = iio_priv(indio_dev);
int ret = 0;
/* Use the same mutex which was used everywhere to protect power-op */
mutex_lock(&indio_dev->mlock);
if (!st->powerup_count) {
ret = inv_mpu6050_write_reg_unlocked(client,
st->reg->pwr_mgmt_1, 0);
ret = regmap_write(st->map, st->reg->pwr_mgmt_1, 0);
if (ret)
goto write_error;
@ -73,10 +42,9 @@ static int inv_mpu6050_select_bypass(struct i2c_adapter *adap, void *mux_priv,
}
if (!ret) {
st->powerup_count++;
ret = inv_mpu6050_write_reg_unlocked(client,
st->reg->int_pin_cfg,
INV_MPU6050_INT_PIN_CFG |
INV_MPU6050_BIT_BYPASS_EN);
ret = regmap_write(st->map, st->reg->int_pin_cfg,
INV_MPU6050_INT_PIN_CFG |
INV_MPU6050_BIT_BYPASS_EN);
}
write_error:
mutex_unlock(&indio_dev->mlock);
@ -84,21 +52,18 @@ write_error:
return ret;
}
static int inv_mpu6050_deselect_bypass(struct i2c_adapter *adap,
void *mux_priv, u32 chan_id)
static int inv_mpu6050_deselect_bypass(struct i2c_mux_core *muxc, u32 chan_id)
{
struct i2c_client *client = mux_priv;
struct iio_dev *indio_dev = dev_get_drvdata(&client->dev);
struct iio_dev *indio_dev = i2c_mux_priv(muxc);
struct inv_mpu6050_state *st = iio_priv(indio_dev);
mutex_lock(&indio_dev->mlock);
/* It doesn't really mattter, if any of the calls fails */
inv_mpu6050_write_reg_unlocked(client, st->reg->int_pin_cfg,
INV_MPU6050_INT_PIN_CFG);
regmap_write(st->map, st->reg->int_pin_cfg, INV_MPU6050_INT_PIN_CFG);
st->powerup_count--;
if (!st->powerup_count)
inv_mpu6050_write_reg_unlocked(client, st->reg->pwr_mgmt_1,
INV_MPU6050_BIT_SLEEP);
regmap_write(st->map, st->reg->pwr_mgmt_1,
INV_MPU6050_BIT_SLEEP);
mutex_unlock(&indio_dev->mlock);
return 0;
@ -160,16 +125,18 @@ static int inv_mpu_probe(struct i2c_client *client,
return result;
st = iio_priv(dev_get_drvdata(&client->dev));
st->mux_adapter = i2c_add_mux_adapter(client->adapter,
&client->dev,
client,
0, 0, 0,
inv_mpu6050_select_bypass,
inv_mpu6050_deselect_bypass);
if (!st->mux_adapter) {
result = -ENODEV;
st->muxc = i2c_mux_alloc(client->adapter, &client->dev,
1, 0, I2C_MUX_LOCKED,
inv_mpu6050_select_bypass,
inv_mpu6050_deselect_bypass);
if (!st->muxc) {
result = -ENOMEM;
goto out_unreg_device;
}
st->muxc->priv = dev_get_drvdata(&client->dev);
result = i2c_mux_add_adapter(st->muxc, 0, 0, 0);
if (result)
goto out_unreg_device;
result = inv_mpu_acpi_create_mux_client(client);
if (result)
@ -178,7 +145,7 @@ static int inv_mpu_probe(struct i2c_client *client,
return 0;
out_del_mux:
i2c_del_mux_adapter(st->mux_adapter);
i2c_mux_del_adapters(st->muxc);
out_unreg_device:
inv_mpu_core_remove(&client->dev);
return result;
@ -190,7 +157,7 @@ static int inv_mpu_remove(struct i2c_client *client)
struct inv_mpu6050_state *st = iio_priv(indio_dev);
inv_mpu_acpi_delete_mux_client(client);
i2c_del_mux_adapter(st->mux_adapter);
i2c_mux_del_adapters(st->muxc);
return inv_mpu_core_remove(&client->dev);
}

View File

@ -11,6 +11,7 @@
* GNU General Public License for more details.
*/
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/kfifo.h>
#include <linux/spinlock.h>
#include <linux/iio/iio.h>
@ -127,7 +128,7 @@ struct inv_mpu6050_state {
const struct inv_mpu6050_hw *hw;
enum inv_devices chip_type;
spinlock_t time_stamp_lock;
struct i2c_adapter *mux_adapter;
struct i2c_mux_core *muxc;
struct i2c_client *mux_client;
unsigned int powerup_count;
struct inv_mpu6050_platform_data plat_data;

View File

@ -1251,9 +1251,9 @@ static void m88ds3103_release(struct dvb_frontend *fe)
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;
int ret;
struct i2c_msg msg = {
@ -1374,7 +1374,7 @@ static struct i2c_adapter *m88ds3103_get_i2c_adapter(struct i2c_client *client)
dev_dbg(&client->dev, "\n");
return dev->i2c_adapter;
return dev->muxc->adapter[0];
}
static int m88ds3103_probe(struct i2c_client *client,
@ -1467,13 +1467,16 @@ static int m88ds3103_probe(struct i2c_client *client,
goto err_kfree;
/* create mux i2c adapter for tuner */
dev->i2c_adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
dev, 0, 0, 0, m88ds3103_select,
NULL);
if (dev->i2c_adapter == NULL) {
dev->muxc = i2c_mux_alloc(client->adapter, &client->dev, 1, 0, 0,
m88ds3103_select, NULL);
if (!dev->muxc) {
ret = -ENOMEM;
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 */
memcpy(&dev->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops));
@ -1502,7 +1505,7 @@ static int m88ds3103_remove(struct i2c_client *client)
dev_dbg(&client->dev, "\n");
i2c_del_mux_adapter(dev->i2c_adapter);
i2c_mux_del_adapters(dev->muxc);
kfree(dev);
return 0;

View File

@ -42,7 +42,7 @@ struct m88ds3103_dev {
enum fe_status fe_status;
u32 dvbv3_ber; /* for old DVBv3 API read_ber */
bool warm; /* FW running */
struct i2c_adapter *i2c_adapter;
struct i2c_mux_core *muxc;
/* auto detect chip id to do different config */
u8 chip_id;
/* main mclk is calculated for M88RS6000 dynamically */

View File

@ -677,9 +677,9 @@ err:
* adapter lock is already taken by tuner driver.
* Gate is closed automatically after single I2C transfer.
*/
static int rtl2830_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id)
static int rtl2830_select(struct i2c_mux_core *muxc, u32 chan_id)
{
struct i2c_client *client = mux_priv;
struct i2c_client *client = i2c_mux_priv(muxc);
struct rtl2830_dev *dev = i2c_get_clientdata(client);
int ret;
@ -712,7 +712,7 @@ static struct i2c_adapter *rtl2830_get_i2c_adapter(struct i2c_client *client)
dev_dbg(&client->dev, "\n");
return dev->adapter;
return dev->muxc->adapter[0];
}
/*
@ -865,12 +865,16 @@ static int rtl2830_probe(struct i2c_client *client,
goto err_regmap_exit;
/* create muxed i2c adapter for tuner */
dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
client, 0, 0, 0, rtl2830_select, NULL);
if (dev->adapter == NULL) {
ret = -ENODEV;
dev->muxc = i2c_mux_alloc(client->adapter, &client->dev, 1, 0, 0,
rtl2830_select, NULL);
if (!dev->muxc) {
ret = -ENOMEM;
goto err_regmap_exit;
}
dev->muxc->priv = client;
ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0);
if (ret)
goto err_regmap_exit;
/* create dvb frontend */
memcpy(&dev->fe.ops, &rtl2830_ops, sizeof(dev->fe.ops));
@ -903,7 +907,7 @@ static int rtl2830_remove(struct i2c_client *client)
/* stop statistics polling */
cancel_delayed_work_sync(&dev->stat_work);
i2c_del_mux_adapter(dev->adapter);
i2c_mux_del_adapters(dev->muxc);
regmap_exit(dev->regmap);
kfree(dev);

View File

@ -29,7 +29,7 @@ struct rtl2830_dev {
struct rtl2830_platform_data *pdata;
struct i2c_client *client;
struct regmap *regmap;
struct i2c_adapter *adapter;
struct i2c_mux_core *muxc;
struct dvb_frontend fe;
bool sleeping;
unsigned long filters;

View File

@ -153,43 +153,6 @@ static const struct rtl2832_reg_entry registers[] = {
[DVBT_REG_4MSEL] = {0x013, 0, 0},
};
/* Our regmap is bypassing I2C adapter lock, thus we do it! */
static int rtl2832_bulk_write(struct i2c_client *client, unsigned int reg,
const void *val, size_t val_count)
{
struct rtl2832_dev *dev = i2c_get_clientdata(client);
int ret;
i2c_lock_adapter(client->adapter);
ret = regmap_bulk_write(dev->regmap, reg, val, val_count);
i2c_unlock_adapter(client->adapter);
return ret;
}
static int rtl2832_update_bits(struct i2c_client *client, unsigned int reg,
unsigned int mask, unsigned int val)
{
struct rtl2832_dev *dev = i2c_get_clientdata(client);
int ret;
i2c_lock_adapter(client->adapter);
ret = regmap_update_bits(dev->regmap, reg, mask, val);
i2c_unlock_adapter(client->adapter);
return ret;
}
static int rtl2832_bulk_read(struct i2c_client *client, unsigned int reg,
void *val, size_t val_count)
{
struct rtl2832_dev *dev = i2c_get_clientdata(client);
int ret;
i2c_lock_adapter(client->adapter);
ret = regmap_bulk_read(dev->regmap, reg, val, val_count);
i2c_unlock_adapter(client->adapter);
return ret;
}
static int rtl2832_rd_demod_reg(struct rtl2832_dev *dev, int reg, u32 *val)
{
struct i2c_client *client = dev->client;
@ -204,7 +167,7 @@ static int rtl2832_rd_demod_reg(struct rtl2832_dev *dev, int reg, u32 *val)
len = (msb >> 3) + 1;
mask = REG_MASK(msb - lsb);
ret = rtl2832_bulk_read(client, reg_start_addr, reading, len);
ret = regmap_bulk_read(dev->regmap, reg_start_addr, reading, len);
if (ret)
goto err;
@ -234,7 +197,7 @@ static int rtl2832_wr_demod_reg(struct rtl2832_dev *dev, int reg, u32 val)
len = (msb >> 3) + 1;
mask = REG_MASK(msb - lsb);
ret = rtl2832_bulk_read(client, reg_start_addr, reading, len);
ret = regmap_bulk_read(dev->regmap, reg_start_addr, reading, len);
if (ret)
goto err;
@ -248,7 +211,7 @@ static int rtl2832_wr_demod_reg(struct rtl2832_dev *dev, int reg, u32 val)
for (i = 0; i < len; i++)
writing[i] = (writing_tmp >> ((len - 1 - i) * 8)) & 0xff;
ret = rtl2832_bulk_write(client, reg_start_addr, writing, len);
ret = regmap_bulk_write(dev->regmap, reg_start_addr, writing, len);
if (ret)
goto err;
@ -525,7 +488,8 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
}
for (j = 0; j < sizeof(bw_params[0]); j++) {
ret = rtl2832_bulk_write(client, 0x11c + j, &bw_params[i][j], 1);
ret = regmap_bulk_write(dev->regmap,
0x11c + j, &bw_params[i][j], 1);
if (ret)
goto err;
}
@ -581,11 +545,11 @@ static int rtl2832_get_frontend(struct dvb_frontend *fe,
if (dev->sleeping)
return 0;
ret = rtl2832_bulk_read(client, 0x33c, buf, 2);
ret = regmap_bulk_read(dev->regmap, 0x33c, buf, 2);
if (ret)
goto err;
ret = rtl2832_bulk_read(client, 0x351, &buf[2], 1);
ret = regmap_bulk_read(dev->regmap, 0x351, &buf[2], 1);
if (ret)
goto err;
@ -716,7 +680,7 @@ static int rtl2832_read_status(struct dvb_frontend *fe, enum fe_status *status)
/* signal strength */
if (dev->fe_status & FE_HAS_SIGNAL) {
/* read digital AGC */
ret = rtl2832_bulk_read(client, 0x305, &u8tmp, 1);
ret = regmap_bulk_read(dev->regmap, 0x305, &u8tmp, 1);
if (ret)
goto err;
@ -742,7 +706,7 @@ static int rtl2832_read_status(struct dvb_frontend *fe, enum fe_status *status)
{87659938, 87659938, 87885178, 88241743},
};
ret = rtl2832_bulk_read(client, 0x33c, &u8tmp, 1);
ret = regmap_bulk_read(dev->regmap, 0x33c, &u8tmp, 1);
if (ret)
goto err;
@ -754,7 +718,7 @@ static int rtl2832_read_status(struct dvb_frontend *fe, enum fe_status *status)
if (hierarchy > HIERARCHY_NUM - 1)
goto err;
ret = rtl2832_bulk_read(client, 0x40c, buf, 2);
ret = regmap_bulk_read(dev->regmap, 0x40c, buf, 2);
if (ret)
goto err;
@ -775,7 +739,7 @@ static int rtl2832_read_status(struct dvb_frontend *fe, enum fe_status *status)
/* BER */
if (dev->fe_status & FE_HAS_LOCK) {
ret = rtl2832_bulk_read(client, 0x34e, buf, 2);
ret = regmap_bulk_read(dev->regmap, 0x34e, buf, 2);
if (ret)
goto err;
@ -825,8 +789,6 @@ static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
/*
* I2C gate/mux/repeater logic
* We must use unlocked __i2c_transfer() here (through regmap) because of I2C
* adapter lock is already taken by tuner driver.
* There is delay mechanism to avoid unneeded I2C gate open / close. Gate close
* is delayed here a little bit in order to see if there is sequence of I2C
* messages sent to same I2C bus.
@ -838,7 +800,7 @@ static void rtl2832_i2c_gate_work(struct work_struct *work)
int ret;
/* close gate */
ret = rtl2832_update_bits(dev->client, 0x101, 0x08, 0x00);
ret = regmap_update_bits(dev->regmap, 0x101, 0x08, 0x00);
if (ret)
goto err;
@ -847,19 +809,16 @@ err:
dev_dbg(&client->dev, "failed=%d\n", ret);
}
static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id)
static int rtl2832_select(struct i2c_mux_core *muxc, u32 chan_id)
{
struct rtl2832_dev *dev = mux_priv;
struct rtl2832_dev *dev = i2c_mux_priv(muxc);
struct i2c_client *client = dev->client;
int ret;
/* terminate possible gate closing */
cancel_delayed_work(&dev->i2c_gate_work);
/*
* I2C adapter lock is already taken and due to that we will use
* regmap_update_bits() which does not lock again I2C adapter.
*/
/* open gate */
ret = regmap_update_bits(dev->regmap, 0x101, 0x08, 0x08);
if (ret)
goto err;
@ -870,10 +829,9 @@ err:
return ret;
}
static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv,
u32 chan_id)
static int rtl2832_deselect(struct i2c_mux_core *muxc, u32 chan_id)
{
struct rtl2832_dev *dev = mux_priv;
struct rtl2832_dev *dev = i2c_mux_priv(muxc);
schedule_delayed_work(&dev->i2c_gate_work, usecs_to_jiffies(100));
return 0;
@ -932,120 +890,6 @@ static bool rtl2832_volatile_reg(struct device *dev, unsigned int reg)
return false;
}
/*
* We implement own I2C access routines for regmap in order to get manual access
* to I2C adapter lock, which is needed for I2C mux adapter.
*/
static int rtl2832_regmap_read(void *context, const void *reg_buf,
size_t reg_size, void *val_buf, size_t val_size)
{
struct i2c_client *client = context;
int ret;
struct i2c_msg msg[2] = {
{
.addr = client->addr,
.flags = 0,
.len = reg_size,
.buf = (u8 *)reg_buf,
}, {
.addr = client->addr,
.flags = I2C_M_RD,
.len = val_size,
.buf = val_buf,
}
};
ret = __i2c_transfer(client->adapter, msg, 2);
if (ret != 2) {
dev_warn(&client->dev, "i2c reg read failed %d reg %02x\n",
ret, *(u8 *)reg_buf);
if (ret >= 0)
ret = -EREMOTEIO;
return ret;
}
return 0;
}
static int rtl2832_regmap_write(void *context, const void *data, size_t count)
{
struct i2c_client *client = context;
int ret;
struct i2c_msg msg[1] = {
{
.addr = client->addr,
.flags = 0,
.len = count,
.buf = (u8 *)data,
}
};
ret = __i2c_transfer(client->adapter, msg, 1);
if (ret != 1) {
dev_warn(&client->dev, "i2c reg write failed %d reg %02x\n",
ret, *(u8 *)data);
if (ret >= 0)
ret = -EREMOTEIO;
return ret;
}
return 0;
}
static int rtl2832_regmap_gather_write(void *context, const void *reg,
size_t reg_len, const void *val,
size_t val_len)
{
struct i2c_client *client = context;
int ret;
u8 buf[256];
struct i2c_msg msg[1] = {
{
.addr = client->addr,
.flags = 0,
.len = 1 + val_len,
.buf = buf,
}
};
buf[0] = *(u8 const *)reg;
memcpy(&buf[1], val, val_len);
ret = __i2c_transfer(client->adapter, msg, 1);
if (ret != 1) {
dev_warn(&client->dev, "i2c reg write failed %d reg %02x\n",
ret, *(u8 const *)reg);
if (ret >= 0)
ret = -EREMOTEIO;
return ret;
}
return 0;
}
/*
* FIXME: Hack. Implement own regmap locking in order to silence lockdep
* recursive lock warning. That happens when regmap I2C client calls I2C mux
* adapter, which leads demod I2C repeater enable via demod regmap. Operation
* takes two regmap locks recursively - but those are different regmap instances
* in a two different I2C drivers, so it is not deadlock. Proper fix is to make
* regmap aware of lockdep.
*/
static void rtl2832_regmap_lock(void *__dev)
{
struct rtl2832_dev *dev = __dev;
struct i2c_client *client = dev->client;
dev_dbg(&client->dev, "\n");
mutex_lock(&dev->regmap_mutex);
}
static void rtl2832_regmap_unlock(void *__dev)
{
struct rtl2832_dev *dev = __dev;
struct i2c_client *client = dev->client;
dev_dbg(&client->dev, "\n");
mutex_unlock(&dev->regmap_mutex);
}
static struct dvb_frontend *rtl2832_get_dvb_frontend(struct i2c_client *client)
{
struct rtl2832_dev *dev = i2c_get_clientdata(client);
@ -1059,7 +903,7 @@ static struct i2c_adapter *rtl2832_get_i2c_adapter(struct i2c_client *client)
struct rtl2832_dev *dev = i2c_get_clientdata(client);
dev_dbg(&client->dev, "\n");
return dev->i2c_adapter_tuner;
return dev->muxc->adapter[0];
}
static int rtl2832_slave_ts_ctrl(struct i2c_client *client, bool enable)
@ -1073,29 +917,29 @@ static int rtl2832_slave_ts_ctrl(struct i2c_client *client, bool enable)
ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x0);
if (ret)
goto err;
ret = rtl2832_bulk_write(client, 0x10c, "\x5f\xff", 2);
ret = regmap_bulk_write(dev->regmap, 0x10c, "\x5f\xff", 2);
if (ret)
goto err;
ret = rtl2832_wr_demod_reg(dev, DVBT_PIP_ON, 0x1);
if (ret)
goto err;
ret = rtl2832_bulk_write(client, 0x0bc, "\x18", 1);
ret = regmap_bulk_write(dev->regmap, 0x0bc, "\x18", 1);
if (ret)
goto err;
ret = rtl2832_bulk_write(client, 0x192, "\x7f\xf7\xff", 3);
ret = regmap_bulk_write(dev->regmap, 0x192, "\x7f\xf7\xff", 3);
if (ret)
goto err;
} else {
ret = rtl2832_bulk_write(client, 0x192, "\x00\x0f\xff", 3);
ret = regmap_bulk_write(dev->regmap, 0x192, "\x00\x0f\xff", 3);
if (ret)
goto err;
ret = rtl2832_bulk_write(client, 0x0bc, "\x08", 1);
ret = regmap_bulk_write(dev->regmap, 0x0bc, "\x08", 1);
if (ret)
goto err;
ret = rtl2832_wr_demod_reg(dev, DVBT_PIP_ON, 0x0);
if (ret)
goto err;
ret = rtl2832_bulk_write(client, 0x10c, "\x00\x00", 2);
ret = regmap_bulk_write(dev->regmap, 0x10c, "\x00\x00", 2);
if (ret)
goto err;
ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x1);
@ -1124,7 +968,7 @@ static int rtl2832_pid_filter_ctrl(struct dvb_frontend *fe, int onoff)
else
u8tmp = 0x00;
ret = rtl2832_update_bits(client, 0x061, 0xc0, u8tmp);
ret = regmap_update_bits(dev->regmap, 0x061, 0xc0, u8tmp);
if (ret)
goto err;
@ -1159,14 +1003,14 @@ static int rtl2832_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid,
buf[1] = (dev->filters >> 8) & 0xff;
buf[2] = (dev->filters >> 16) & 0xff;
buf[3] = (dev->filters >> 24) & 0xff;
ret = rtl2832_bulk_write(client, 0x062, buf, 4);
ret = regmap_bulk_write(dev->regmap, 0x062, buf, 4);
if (ret)
goto err;
/* add PID */
buf[0] = (pid >> 8) & 0xff;
buf[1] = (pid >> 0) & 0xff;
ret = rtl2832_bulk_write(client, 0x066 + 2 * index, buf, 2);
ret = regmap_bulk_write(dev->regmap, 0x066 + 2 * index, buf, 2);
if (ret)
goto err;
@ -1184,12 +1028,6 @@ static int rtl2832_probe(struct i2c_client *client,
struct rtl2832_dev *dev;
int ret;
u8 tmp;
static const struct regmap_bus regmap_bus = {
.read = rtl2832_regmap_read,
.write = rtl2832_regmap_write,
.gather_write = rtl2832_regmap_gather_write,
.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
};
static const struct regmap_range_cfg regmap_range_cfg[] = {
{
.selector_reg = 0x00,
@ -1218,36 +1056,35 @@ static int rtl2832_probe(struct i2c_client *client,
dev->sleeping = true;
INIT_DELAYED_WORK(&dev->i2c_gate_work, rtl2832_i2c_gate_work);
/* create regmap */
mutex_init(&dev->regmap_mutex);
dev->regmap_config.reg_bits = 8,
dev->regmap_config.val_bits = 8,
dev->regmap_config.lock = rtl2832_regmap_lock,
dev->regmap_config.unlock = rtl2832_regmap_unlock,
dev->regmap_config.lock_arg = dev,
dev->regmap_config.volatile_reg = rtl2832_volatile_reg,
dev->regmap_config.max_register = 5 * 0x100,
dev->regmap_config.ranges = regmap_range_cfg,
dev->regmap_config.num_ranges = ARRAY_SIZE(regmap_range_cfg),
dev->regmap_config.cache_type = REGCACHE_NONE,
dev->regmap = regmap_init(&client->dev, &regmap_bus, client,
&dev->regmap_config);
dev->regmap = regmap_init_i2c(client, &dev->regmap_config);
if (IS_ERR(dev->regmap)) {
ret = PTR_ERR(dev->regmap);
goto err_kfree;
}
/* check if the demod is there */
ret = rtl2832_bulk_read(client, 0x000, &tmp, 1);
ret = regmap_bulk_read(dev->regmap, 0x000, &tmp, 1);
if (ret)
goto err_regmap_exit;
/* create muxed i2c adapter for demod tuner bus */
dev->i2c_adapter_tuner = i2c_add_mux_adapter(i2c, &i2c->dev, dev,
0, 0, 0, rtl2832_select, rtl2832_deselect);
if (dev->i2c_adapter_tuner == NULL) {
ret = -ENODEV;
dev->muxc = i2c_mux_alloc(i2c, &i2c->dev, 1, 0, I2C_MUX_LOCKED,
rtl2832_select, rtl2832_deselect);
if (!dev->muxc) {
ret = -ENOMEM;
goto err_regmap_exit;
}
dev->muxc->priv = dev;
ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0);
if (ret)
goto err_regmap_exit;
/* create dvb_frontend */
memcpy(&dev->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
@ -1259,9 +1096,7 @@ static int rtl2832_probe(struct i2c_client *client,
pdata->slave_ts_ctrl = rtl2832_slave_ts_ctrl;
pdata->pid_filter = rtl2832_pid_filter;
pdata->pid_filter_ctrl = rtl2832_pid_filter_ctrl;
pdata->bulk_read = rtl2832_bulk_read;
pdata->bulk_write = rtl2832_bulk_write;
pdata->update_bits = rtl2832_update_bits;
pdata->regmap = dev->regmap;
dev_info(&client->dev, "Realtek RTL2832 successfully attached\n");
return 0;
@ -1282,7 +1117,7 @@ static int rtl2832_remove(struct i2c_client *client)
cancel_delayed_work_sync(&dev->i2c_gate_work);
i2c_del_mux_adapter(dev->i2c_adapter_tuner);
i2c_mux_del_adapters(dev->muxc);
regmap_exit(dev->regmap);

View File

@ -57,9 +57,7 @@ struct rtl2832_platform_data {
int (*pid_filter)(struct dvb_frontend *, u8, u16, int);
int (*pid_filter_ctrl)(struct dvb_frontend *, int);
/* private: Register access for SDR module use only */
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 regmap *regmap;
};
#endif /* RTL2832_H */

View File

@ -33,10 +33,9 @@
struct rtl2832_dev {
struct rtl2832_platform_data *pdata;
struct i2c_client *client;
struct mutex regmap_mutex;
struct regmap_config regmap_config;
struct regmap *regmap;
struct i2c_adapter *i2c_adapter_tuner;
struct i2c_mux_core *muxc;
struct dvb_frontend fe;
enum fe_status fe_status;
u64 post_bit_error_prev; /* for old DVBv3 read_ber() calculation */

View File

@ -35,6 +35,7 @@
#include <linux/platform_device.h>
#include <linux/jiffies.h>
#include <linux/math64.h>
#include <linux/regmap.h>
static bool rtl2832_sdr_emulated_fmt;
module_param_named(emulated_formats, rtl2832_sdr_emulated_fmt, bool, 0644);
@ -119,6 +120,7 @@ struct rtl2832_sdr_dev {
unsigned long flags;
struct platform_device *pdev;
struct regmap *regmap;
struct video_device vdev;
struct v4l2_device v4l2_dev;
@ -163,47 +165,6 @@ struct rtl2832_sdr_dev {
unsigned long jiffies_next;
};
/* write multiple registers */
static int rtl2832_sdr_wr_regs(struct rtl2832_sdr_dev *dev, u16 reg,
const u8 *val, int len)
{
struct platform_device *pdev = dev->pdev;
struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
struct i2c_client *client = pdata->i2c_client;
return pdata->bulk_write(client, reg, val, len);
}
#if 0
/* read multiple registers */
static int rtl2832_sdr_rd_regs(struct rtl2832_sdr_dev *dev, u16 reg, u8 *val,
int len)
{
struct platform_device *pdev = dev->pdev;
struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
struct i2c_client *client = pdata->i2c_client;
return pdata->bulk_read(client, reg, val, len);
}
#endif
/* write single register */
static int rtl2832_sdr_wr_reg(struct rtl2832_sdr_dev *dev, u16 reg, u8 val)
{
return rtl2832_sdr_wr_regs(dev, reg, &val, 1);
}
/* write single register with mask */
static int rtl2832_sdr_wr_reg_mask(struct rtl2832_sdr_dev *dev, u16 reg,
u8 val, u8 mask)
{
struct platform_device *pdev = dev->pdev;
struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
struct i2c_client *client = pdata->i2c_client;
return pdata->update_bits(client, reg, mask, val);
}
/* Private functions */
static struct rtl2832_sdr_frame_buf *rtl2832_sdr_get_next_fill_buf(
struct rtl2832_sdr_dev *dev)
@ -558,11 +519,11 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_dev *dev)
f_sr = dev->f_adc;
ret = rtl2832_sdr_wr_regs(dev, 0x13e, "\x00\x00", 2);
ret = regmap_bulk_write(dev->regmap, 0x13e, "\x00\x00", 2);
if (ret)
goto err;
ret = rtl2832_sdr_wr_regs(dev, 0x115, "\x00\x00\x00\x00", 4);
ret = regmap_bulk_write(dev->regmap, 0x115, "\x00\x00\x00\x00", 4);
if (ret)
goto err;
@ -588,7 +549,7 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_dev *dev)
buf[1] = (u32tmp >> 8) & 0xff;
buf[2] = (u32tmp >> 0) & 0xff;
ret = rtl2832_sdr_wr_regs(dev, 0x119, buf, 3);
ret = regmap_bulk_write(dev->regmap, 0x119, buf, 3);
if (ret)
goto err;
@ -602,15 +563,15 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_dev *dev)
u8tmp2 = 0xcd; /* enable ADC I, ADC Q */
}
ret = rtl2832_sdr_wr_reg(dev, 0x1b1, u8tmp1);
ret = regmap_write(dev->regmap, 0x1b1, u8tmp1);
if (ret)
goto err;
ret = rtl2832_sdr_wr_reg(dev, 0x008, u8tmp2);
ret = regmap_write(dev->regmap, 0x008, u8tmp2);
if (ret)
goto err;
ret = rtl2832_sdr_wr_reg(dev, 0x006, 0x80);
ret = regmap_write(dev->regmap, 0x006, 0x80);
if (ret)
goto err;
@ -621,168 +582,169 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_dev *dev)
buf[1] = (u32tmp >> 16) & 0xff;
buf[2] = (u32tmp >> 8) & 0xff;
buf[3] = (u32tmp >> 0) & 0xff;
ret = rtl2832_sdr_wr_regs(dev, 0x19f, buf, 4);
ret = regmap_bulk_write(dev->regmap, 0x19f, buf, 4);
if (ret)
goto err;
/* low-pass filter */
ret = rtl2832_sdr_wr_regs(dev, 0x11c,
"\xca\xdc\xd7\xd8\xe0\xf2\x0e\x35\x06\x50\x9c\x0d\x71\x11\x14\x71\x74\x19\x41\xa5",
20);
ret = regmap_bulk_write(dev->regmap, 0x11c,
"\xca\xdc\xd7\xd8\xe0\xf2\x0e\x35\x06\x50\x9c\x0d\x71\x11\x14\x71\x74\x19\x41\xa5",
20);
if (ret)
goto err;
ret = rtl2832_sdr_wr_regs(dev, 0x017, "\x11\x10", 2);
ret = regmap_bulk_write(dev->regmap, 0x017, "\x11\x10", 2);
if (ret)
goto err;
/* mode */
ret = rtl2832_sdr_wr_regs(dev, 0x019, "\x05", 1);
ret = regmap_write(dev->regmap, 0x019, 0x05);
if (ret)
goto err;
ret = rtl2832_sdr_wr_regs(dev, 0x01a, "\x1b\x16\x0d\x06\x01\xff", 6);
ret = regmap_bulk_write(dev->regmap, 0x01a,
"\x1b\x16\x0d\x06\x01\xff", 6);
if (ret)
goto err;
/* FSM */
ret = rtl2832_sdr_wr_regs(dev, 0x192, "\x00\xf0\x0f", 3);
ret = regmap_bulk_write(dev->regmap, 0x192, "\x00\xf0\x0f", 3);
if (ret)
goto err;
/* PID filter */
ret = rtl2832_sdr_wr_regs(dev, 0x061, "\x60", 1);
ret = regmap_write(dev->regmap, 0x061, 0x60);
if (ret)
goto err;
/* used RF tuner based settings */
switch (pdata->tuner) {
case RTL2832_SDR_TUNER_E4000:
ret = rtl2832_sdr_wr_regs(dev, 0x112, "\x5a", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x102, "\x40", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x103, "\x5a", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1c7, "\x30", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x104, "\xd0", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x105, "\xbe", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1c8, "\x18", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x106, "\x35", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1c9, "\x21", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1ca, "\x21", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1cb, "\x00", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x107, "\x40", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1cd, "\x10", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1ce, "\x10", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x108, "\x80", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x109, "\x7f", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x10a, "\x80", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x10b, "\x7f", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x011, "\xd4", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1e5, "\xf0", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1d9, "\x00", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1db, "\x00", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1dd, "\x14", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1de, "\xec", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1d8, "\x0c", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1e6, "\x02", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1d7, "\x09", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x00d, "\x83", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x010, "\x49", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x00d, "\x87", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x00d, "\x85", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x013, "\x02", 1);
ret = regmap_write(dev->regmap, 0x112, 0x5a);
ret = regmap_write(dev->regmap, 0x102, 0x40);
ret = regmap_write(dev->regmap, 0x103, 0x5a);
ret = regmap_write(dev->regmap, 0x1c7, 0x30);
ret = regmap_write(dev->regmap, 0x104, 0xd0);
ret = regmap_write(dev->regmap, 0x105, 0xbe);
ret = regmap_write(dev->regmap, 0x1c8, 0x18);
ret = regmap_write(dev->regmap, 0x106, 0x35);
ret = regmap_write(dev->regmap, 0x1c9, 0x21);
ret = regmap_write(dev->regmap, 0x1ca, 0x21);
ret = regmap_write(dev->regmap, 0x1cb, 0x00);
ret = regmap_write(dev->regmap, 0x107, 0x40);
ret = regmap_write(dev->regmap, 0x1cd, 0x10);
ret = regmap_write(dev->regmap, 0x1ce, 0x10);
ret = regmap_write(dev->regmap, 0x108, 0x80);
ret = regmap_write(dev->regmap, 0x109, 0x7f);
ret = regmap_write(dev->regmap, 0x10a, 0x80);
ret = regmap_write(dev->regmap, 0x10b, 0x7f);
ret = regmap_write(dev->regmap, 0x00e, 0xfc);
ret = regmap_write(dev->regmap, 0x00e, 0xfc);
ret = regmap_write(dev->regmap, 0x011, 0xd4);
ret = regmap_write(dev->regmap, 0x1e5, 0xf0);
ret = regmap_write(dev->regmap, 0x1d9, 0x00);
ret = regmap_write(dev->regmap, 0x1db, 0x00);
ret = regmap_write(dev->regmap, 0x1dd, 0x14);
ret = regmap_write(dev->regmap, 0x1de, 0xec);
ret = regmap_write(dev->regmap, 0x1d8, 0x0c);
ret = regmap_write(dev->regmap, 0x1e6, 0x02);
ret = regmap_write(dev->regmap, 0x1d7, 0x09);
ret = regmap_write(dev->regmap, 0x00d, 0x83);
ret = regmap_write(dev->regmap, 0x010, 0x49);
ret = regmap_write(dev->regmap, 0x00d, 0x87);
ret = regmap_write(dev->regmap, 0x00d, 0x85);
ret = regmap_write(dev->regmap, 0x013, 0x02);
break;
case RTL2832_SDR_TUNER_FC0012:
case RTL2832_SDR_TUNER_FC0013:
ret = rtl2832_sdr_wr_regs(dev, 0x112, "\x5a", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x102, "\x40", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x103, "\x5a", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1c7, "\x2c", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x104, "\xcc", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x105, "\xbe", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1c8, "\x16", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x106, "\x35", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1c9, "\x21", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1ca, "\x21", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1cb, "\x00", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x107, "\x40", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1cd, "\x10", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1ce, "\x10", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x108, "\x80", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x109, "\x7f", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x10a, "\x80", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x10b, "\x7f", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x011, "\xe9\xbf", 2);
ret = rtl2832_sdr_wr_regs(dev, 0x1e5, "\xf0", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1d9, "\x00", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1db, "\x00", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1dd, "\x11", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1de, "\xef", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1d8, "\x0c", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1e6, "\x02", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1d7, "\x09", 1);
ret = regmap_write(dev->regmap, 0x112, 0x5a);
ret = regmap_write(dev->regmap, 0x102, 0x40);
ret = regmap_write(dev->regmap, 0x103, 0x5a);
ret = regmap_write(dev->regmap, 0x1c7, 0x2c);
ret = regmap_write(dev->regmap, 0x104, 0xcc);
ret = regmap_write(dev->regmap, 0x105, 0xbe);
ret = regmap_write(dev->regmap, 0x1c8, 0x16);
ret = regmap_write(dev->regmap, 0x106, 0x35);
ret = regmap_write(dev->regmap, 0x1c9, 0x21);
ret = regmap_write(dev->regmap, 0x1ca, 0x21);
ret = regmap_write(dev->regmap, 0x1cb, 0x00);
ret = regmap_write(dev->regmap, 0x107, 0x40);
ret = regmap_write(dev->regmap, 0x1cd, 0x10);
ret = regmap_write(dev->regmap, 0x1ce, 0x10);
ret = regmap_write(dev->regmap, 0x108, 0x80);
ret = regmap_write(dev->regmap, 0x109, 0x7f);
ret = regmap_write(dev->regmap, 0x10a, 0x80);
ret = regmap_write(dev->regmap, 0x10b, 0x7f);
ret = regmap_write(dev->regmap, 0x00e, 0xfc);
ret = regmap_write(dev->regmap, 0x00e, 0xfc);
ret = regmap_bulk_write(dev->regmap, 0x011, "\xe9\xbf", 2);
ret = regmap_write(dev->regmap, 0x1e5, 0xf0);
ret = regmap_write(dev->regmap, 0x1d9, 0x00);
ret = regmap_write(dev->regmap, 0x1db, 0x00);
ret = regmap_write(dev->regmap, 0x1dd, 0x11);
ret = regmap_write(dev->regmap, 0x1de, 0xef);
ret = regmap_write(dev->regmap, 0x1d8, 0x0c);
ret = regmap_write(dev->regmap, 0x1e6, 0x02);
ret = regmap_write(dev->regmap, 0x1d7, 0x09);
break;
case RTL2832_SDR_TUNER_R820T:
case RTL2832_SDR_TUNER_R828D:
ret = rtl2832_sdr_wr_regs(dev, 0x112, "\x5a", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x102, "\x40", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x115, "\x01", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x103, "\x80", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1c7, "\x24", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x104, "\xcc", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x105, "\xbe", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1c8, "\x14", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x106, "\x35", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1c9, "\x21", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1ca, "\x21", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1cb, "\x00", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x107, "\x40", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1cd, "\x10", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1ce, "\x10", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x108, "\x80", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x109, "\x7f", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x10a, "\x80", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x10b, "\x7f", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x011, "\xf4", 1);
ret = regmap_write(dev->regmap, 0x112, 0x5a);
ret = regmap_write(dev->regmap, 0x102, 0x40);
ret = regmap_write(dev->regmap, 0x115, 0x01);
ret = regmap_write(dev->regmap, 0x103, 0x80);
ret = regmap_write(dev->regmap, 0x1c7, 0x24);
ret = regmap_write(dev->regmap, 0x104, 0xcc);
ret = regmap_write(dev->regmap, 0x105, 0xbe);
ret = regmap_write(dev->regmap, 0x1c8, 0x14);
ret = regmap_write(dev->regmap, 0x106, 0x35);
ret = regmap_write(dev->regmap, 0x1c9, 0x21);
ret = regmap_write(dev->regmap, 0x1ca, 0x21);
ret = regmap_write(dev->regmap, 0x1cb, 0x00);
ret = regmap_write(dev->regmap, 0x107, 0x40);
ret = regmap_write(dev->regmap, 0x1cd, 0x10);
ret = regmap_write(dev->regmap, 0x1ce, 0x10);
ret = regmap_write(dev->regmap, 0x108, 0x80);
ret = regmap_write(dev->regmap, 0x109, 0x7f);
ret = regmap_write(dev->regmap, 0x10a, 0x80);
ret = regmap_write(dev->regmap, 0x10b, 0x7f);
ret = regmap_write(dev->regmap, 0x00e, 0xfc);
ret = regmap_write(dev->regmap, 0x00e, 0xfc);
ret = regmap_write(dev->regmap, 0x011, 0xf4);
break;
case RTL2832_SDR_TUNER_FC2580:
ret = rtl2832_sdr_wr_regs(dev, 0x112, "\x39", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x102, "\x40", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x103, "\x5a", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1c7, "\x2c", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x104, "\xcc", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x105, "\xbe", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1c8, "\x16", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x106, "\x35", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1c9, "\x21", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1ca, "\x21", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1cb, "\x00", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x107, "\x40", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1cd, "\x10", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x1ce, "\x10", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x108, "\x80", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x109, "\x7f", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x10a, "\x9c", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x10b, "\x7f", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
ret = rtl2832_sdr_wr_regs(dev, 0x011, "\xe9\xf4", 2);
ret = regmap_write(dev->regmap, 0x112, 0x39);
ret = regmap_write(dev->regmap, 0x102, 0x40);
ret = regmap_write(dev->regmap, 0x103, 0x5a);
ret = regmap_write(dev->regmap, 0x1c7, 0x2c);
ret = regmap_write(dev->regmap, 0x104, 0xcc);
ret = regmap_write(dev->regmap, 0x105, 0xbe);
ret = regmap_write(dev->regmap, 0x1c8, 0x16);
ret = regmap_write(dev->regmap, 0x106, 0x35);
ret = regmap_write(dev->regmap, 0x1c9, 0x21);
ret = regmap_write(dev->regmap, 0x1ca, 0x21);
ret = regmap_write(dev->regmap, 0x1cb, 0x00);
ret = regmap_write(dev->regmap, 0x107, 0x40);
ret = regmap_write(dev->regmap, 0x1cd, 0x10);
ret = regmap_write(dev->regmap, 0x1ce, 0x10);
ret = regmap_write(dev->regmap, 0x108, 0x80);
ret = regmap_write(dev->regmap, 0x109, 0x7f);
ret = regmap_write(dev->regmap, 0x10a, 0x9c);
ret = regmap_write(dev->regmap, 0x10b, 0x7f);
ret = regmap_write(dev->regmap, 0x00e, 0xfc);
ret = regmap_write(dev->regmap, 0x00e, 0xfc);
ret = regmap_bulk_write(dev->regmap, 0x011, "\xe9\xf4", 2);
break;
default:
dev_notice(&pdev->dev, "Unsupported tuner\n");
}
/* software reset */
ret = rtl2832_sdr_wr_reg_mask(dev, 0x101, 0x04, 0x04);
ret = regmap_update_bits(dev->regmap, 0x101, 0x04, 0x04);
if (ret)
goto err;
ret = rtl2832_sdr_wr_reg_mask(dev, 0x101, 0x00, 0x04);
ret = regmap_update_bits(dev->regmap, 0x101, 0x04, 0x00);
if (ret)
goto err;
err:
@ -797,29 +759,29 @@ static void rtl2832_sdr_unset_adc(struct rtl2832_sdr_dev *dev)
dev_dbg(&pdev->dev, "\n");
/* PID filter */
ret = rtl2832_sdr_wr_regs(dev, 0x061, "\xe0", 1);
ret = regmap_write(dev->regmap, 0x061, 0xe0);
if (ret)
goto err;
/* mode */
ret = rtl2832_sdr_wr_regs(dev, 0x019, "\x20", 1);
ret = regmap_write(dev->regmap, 0x019, 0x20);
if (ret)
goto err;
ret = rtl2832_sdr_wr_regs(dev, 0x017, "\x11\x10", 2);
ret = regmap_bulk_write(dev->regmap, 0x017, "\x11\x10", 2);
if (ret)
goto err;
/* FSM */
ret = rtl2832_sdr_wr_regs(dev, 0x192, "\x00\x0f\xff", 3);
ret = regmap_bulk_write(dev->regmap, 0x192, "\x00\x0f\xff", 3);
if (ret)
goto err;
ret = rtl2832_sdr_wr_regs(dev, 0x13e, "\x40\x00", 2);
ret = regmap_bulk_write(dev->regmap, 0x13e, "\x40\x00", 2);
if (ret)
goto err;
ret = rtl2832_sdr_wr_regs(dev, 0x115, "\x06\x3f\xce\xcc", 4);
ret = regmap_bulk_write(dev->regmap, 0x115, "\x06\x3f\xce\xcc", 4);
if (ret)
goto err;
err:
@ -1399,6 +1361,7 @@ static int rtl2832_sdr_probe(struct platform_device *pdev)
subdev = pdata->v4l2_subdev;
dev->v4l2_subdev = pdata->v4l2_subdev;
dev->pdev = pdev;
dev->regmap = pdata->regmap;
dev->udev = pdata->dvb_usb_device->udev;
dev->f_adc = bands_adc[0].rangelow;
dev->f_tuner = bands_fm[0].rangelow;

View File

@ -56,10 +56,7 @@ struct rtl2832_sdr_platform_data {
#define RTL2832_SDR_TUNER_R828D 0x2b
u8 tuner;
struct i2c_client *i2c_client;
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 regmap *regmap;
struct dvb_frontend *dvb_frontend;
struct v4l2_subdev *v4l2_subdev;
struct dvb_usb_device *dvb_usb_device;

View File

@ -18,53 +18,23 @@
static const struct dvb_frontend_ops si2168_ops;
/* Own I2C adapter locking is needed because of I2C gate logic. */
static int si2168_i2c_master_send_unlocked(const struct i2c_client *client,
const char *buf, int count)
{
int ret;
struct i2c_msg msg = {
.addr = client->addr,
.flags = 0,
.len = count,
.buf = (char *)buf,
};
ret = __i2c_transfer(client->adapter, &msg, 1);
return (ret == 1) ? count : ret;
}
static int si2168_i2c_master_recv_unlocked(const struct i2c_client *client,
char *buf, int count)
{
int ret;
struct i2c_msg msg = {
.addr = client->addr,
.flags = I2C_M_RD,
.len = count,
.buf = buf,
};
ret = __i2c_transfer(client->adapter, &msg, 1);
return (ret == 1) ? count : ret;
}
/* execute firmware command */
static int si2168_cmd_execute_unlocked(struct i2c_client *client,
struct si2168_cmd *cmd)
static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd)
{
struct si2168_dev *dev = i2c_get_clientdata(client);
int ret;
unsigned long timeout;
mutex_lock(&dev->i2c_mutex);
if (cmd->wlen) {
/* write cmd and args for firmware */
ret = si2168_i2c_master_send_unlocked(client, cmd->args,
cmd->wlen);
ret = i2c_master_send(client, cmd->args, cmd->wlen);
if (ret < 0) {
goto err;
goto err_mutex_unlock;
} else if (ret != cmd->wlen) {
ret = -EREMOTEIO;
goto err;
goto err_mutex_unlock;
}
}
@ -73,13 +43,12 @@ static int si2168_cmd_execute_unlocked(struct i2c_client *client,
#define TIMEOUT 70
timeout = jiffies + msecs_to_jiffies(TIMEOUT);
while (!time_after(jiffies, timeout)) {
ret = si2168_i2c_master_recv_unlocked(client, cmd->args,
cmd->rlen);
ret = i2c_master_recv(client, cmd->args, cmd->rlen);
if (ret < 0) {
goto err;
goto err_mutex_unlock;
} else if (ret != cmd->rlen) {
ret = -EREMOTEIO;
goto err;
goto err_mutex_unlock;
}
/* firmware ready? */
@ -94,32 +63,23 @@ static int si2168_cmd_execute_unlocked(struct i2c_client *client,
/* error bit set? */
if ((cmd->args[0] >> 6) & 0x01) {
ret = -EREMOTEIO;
goto err;
goto err_mutex_unlock;
}
if (!((cmd->args[0] >> 7) & 0x01)) {
ret = -ETIMEDOUT;
goto err;
goto err_mutex_unlock;
}
}
mutex_unlock(&dev->i2c_mutex);
return 0;
err:
err_mutex_unlock:
mutex_unlock(&dev->i2c_mutex);
dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd)
{
int ret;
i2c_lock_adapter(client->adapter);
ret = si2168_cmd_execute_unlocked(client, cmd);
i2c_unlock_adapter(client->adapter);
return ret;
}
static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status)
{
struct i2c_client *client = fe->demodulator_priv;
@ -610,14 +570,9 @@ static int si2168_get_tune_settings(struct dvb_frontend *fe,
return 0;
}
/*
* I2C gate logic
* We must use unlocked I2C I/O because I2C adapter lock is already taken
* by the caller (usually tuner driver).
*/
static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
static int si2168_select(struct i2c_mux_core *muxc, u32 chan)
{
struct i2c_client *client = mux_priv;
struct i2c_client *client = i2c_mux_priv(muxc);
int ret;
struct si2168_cmd cmd;
@ -625,7 +580,7 @@ static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
memcpy(cmd.args, "\xc0\x0d\x01", 3);
cmd.wlen = 3;
cmd.rlen = 0;
ret = si2168_cmd_execute_unlocked(client, &cmd);
ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
@ -635,9 +590,9 @@ err:
return ret;
}
static int si2168_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan)
static int si2168_deselect(struct i2c_mux_core *muxc, u32 chan)
{
struct i2c_client *client = mux_priv;
struct i2c_client *client = i2c_mux_priv(muxc);
int ret;
struct si2168_cmd cmd;
@ -645,7 +600,7 @@ static int si2168_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan)
memcpy(cmd.args, "\xc0\x0d\x00", 3);
cmd.wlen = 3;
cmd.rlen = 0;
ret = si2168_cmd_execute_unlocked(client, &cmd);
ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
@ -708,18 +663,25 @@ static int si2168_probe(struct i2c_client *client,
goto err;
}
mutex_init(&dev->i2c_mutex);
/* create mux i2c adapter for tuner */
dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
client, 0, 0, 0, si2168_select, si2168_deselect);
if (dev->adapter == NULL) {
ret = -ENODEV;
dev->muxc = i2c_mux_alloc(client->adapter, &client->dev,
1, 0, I2C_MUX_LOCKED,
si2168_select, si2168_deselect);
if (!dev->muxc) {
ret = -ENOMEM;
goto err_kfree;
}
dev->muxc->priv = client;
ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0);
if (ret)
goto err_kfree;
/* create dvb_frontend */
memcpy(&dev->fe.ops, &si2168_ops, sizeof(struct dvb_frontend_ops));
dev->fe.demodulator_priv = client;
*config->i2c_adapter = dev->adapter;
*config->i2c_adapter = dev->muxc->adapter[0];
*config->fe = &dev->fe;
dev->ts_mode = config->ts_mode;
dev->ts_clock_inv = config->ts_clock_inv;
@ -743,7 +705,7 @@ static int si2168_remove(struct i2c_client *client)
dev_dbg(&client->dev, "\n");
i2c_del_mux_adapter(dev->adapter);
i2c_mux_del_adapters(dev->muxc);
dev->fe.ops.release = NULL;
dev->fe.demodulator_priv = NULL;

View File

@ -29,7 +29,8 @@
/* state struct */
struct si2168_dev {
struct i2c_adapter *adapter;
struct mutex i2c_mutex;
struct i2c_mux_core *muxc;
struct dvb_frontend fe;
enum fe_delivery_system delivery_system;
enum fe_status fe_status;

View File

@ -1305,6 +1305,9 @@ int cx231xx_dev_init(struct cx231xx *dev)
cx231xx_i2c_register(&dev->i2c_bus[1]);
cx231xx_i2c_register(&dev->i2c_bus[2]);
errCode = cx231xx_i2c_mux_create(dev);
if (errCode < 0)
return errCode;
cx231xx_i2c_mux_register(dev, 0);
cx231xx_i2c_mux_register(dev, 1);
@ -1427,8 +1430,7 @@ EXPORT_SYMBOL_GPL(cx231xx_dev_init);
void cx231xx_dev_uninit(struct cx231xx *dev)
{
/* Un Initialize I2C bus */
cx231xx_i2c_mux_unregister(dev, 1);
cx231xx_i2c_mux_unregister(dev, 0);
cx231xx_i2c_mux_unregister(dev);
cx231xx_i2c_unregister(&dev->i2c_bus[2]);
cx231xx_i2c_unregister(&dev->i2c_bus[1]);
cx231xx_i2c_unregister(&dev->i2c_bus[0]);

View File

@ -557,40 +557,41 @@ int cx231xx_i2c_unregister(struct cx231xx_i2c *bus)
* cx231xx_i2c_mux_select()
* switch i2c master number 1 between port1 and port3
*/
static int cx231xx_i2c_mux_select(struct i2c_adapter *adap,
void *mux_priv, u32 chan_id)
static int cx231xx_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan_id)
{
struct cx231xx *dev = mux_priv;
struct cx231xx *dev = i2c_mux_priv(muxc);
return cx231xx_enable_i2c_port_3(dev, chan_id);
}
int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no)
int cx231xx_i2c_mux_create(struct cx231xx *dev)
{
struct i2c_adapter *i2c_parent = &dev->i2c_bus[1].i2c_adap;
/* what is the correct mux_dev? */
struct device *mux_dev = dev->dev;
dev->i2c_mux_adap[mux_no] = i2c_add_mux_adapter(i2c_parent,
mux_dev,
dev /* mux_priv */,
0,
mux_no /* chan_id */,
0 /* class */,
&cx231xx_i2c_mux_select,
NULL);
if (!dev->i2c_mux_adap[mux_no])
dev_warn(dev->dev,
"i2c mux %d register FAILED\n", mux_no);
dev->muxc = i2c_mux_alloc(&dev->i2c_bus[1].i2c_adap, dev->dev, 2, 0, 0,
cx231xx_i2c_mux_select, NULL);
if (!dev->muxc)
return -ENOMEM;
dev->muxc->priv = dev;
return 0;
}
void cx231xx_i2c_mux_unregister(struct cx231xx *dev, int mux_no)
int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no)
{
i2c_del_mux_adapter(dev->i2c_mux_adap[mux_no]);
dev->i2c_mux_adap[mux_no] = NULL;
int rc;
rc = i2c_mux_add_adapter(dev->muxc,
0,
mux_no /* chan_id */,
0 /* class */);
if (rc)
dev_warn(dev->dev,
"i2c mux %d register FAILED\n", mux_no);
return rc;
}
void cx231xx_i2c_mux_unregister(struct cx231xx *dev)
{
i2c_mux_del_adapters(dev->muxc);
}
struct i2c_adapter *cx231xx_get_i2c_adap(struct cx231xx *dev, int i2c_port)
@ -603,9 +604,9 @@ struct i2c_adapter *cx231xx_get_i2c_adap(struct cx231xx *dev, int i2c_port)
case I2C_2:
return &dev->i2c_bus[2].i2c_adap;
case I2C_1_MUX_1:
return dev->i2c_mux_adap[0];
return dev->muxc->adapter[0];
case I2C_1_MUX_3:
return dev->i2c_mux_adap[1];
return dev->muxc->adapter[1];
default:
return NULL;
}

View File

@ -624,6 +624,7 @@ struct cx231xx {
/* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */
struct cx231xx_i2c i2c_bus[3];
struct i2c_mux_core *muxc;
struct i2c_adapter *i2c_mux_adap[2];
unsigned int xc_fw_load_done:1;
@ -760,8 +761,9 @@ int cx231xx_reset_analog_tuner(struct cx231xx *dev);
void cx231xx_do_i2c_scan(struct cx231xx *dev, int i2c_port);
int cx231xx_i2c_register(struct cx231xx_i2c *bus);
int cx231xx_i2c_unregister(struct cx231xx_i2c *bus);
int cx231xx_i2c_mux_create(struct cx231xx *dev);
int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no);
void cx231xx_i2c_mux_unregister(struct cx231xx *dev, int mux_no);
void cx231xx_i2c_mux_unregister(struct cx231xx *dev);
struct i2c_adapter *cx231xx_get_i2c_adap(struct cx231xx *dev, int i2c_port);
/* Internal block control functions */

View File

@ -1333,10 +1333,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
case TUNER_RTL2832_R828D:
pdata.clk = dev->rtl2832_platform_data.clk;
pdata.tuner = dev->tuner;
pdata.i2c_client = dev->i2c_client_demod;
pdata.bulk_read = dev->rtl2832_platform_data.bulk_read;
pdata.bulk_write = dev->rtl2832_platform_data.bulk_write;
pdata.update_bits = dev->rtl2832_platform_data.update_bits;
pdata.regmap = dev->rtl2832_platform_data.regmap;
pdata.dvb_frontend = adap->fe[0];
pdata.dvb_usb_device = d;
pdata.v4l2_subdev = subdev;

View File

@ -245,8 +245,7 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
if (status == count)
return count;
/* REVISIT: at HZ=100, this is sloooow */
msleep(1);
usleep_range(1000, 1500);
} while (time_before(read_time, timeout));
return -ETIMEDOUT;
@ -365,8 +364,7 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
if (status == count)
return count;
/* REVISIT: at HZ=100, this is sloooow */
msleep(1);
usleep_range(1000, 1500);
} while (time_before(write_time, timeout));
return -ETIMEDOUT;
@ -544,10 +542,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
} else {
return -EPFNOSUPPORT;
}
}
/* Use I2C operations unless we're stuck with SMBus extensions. */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
if (i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
use_smbus_write = I2C_SMBUS_I2C_BLOCK_DATA;

View File

@ -1692,13 +1692,7 @@ static struct i2c_driver unittest_i2c_dev_driver = {
#if IS_BUILTIN(CONFIG_I2C_MUX)
struct unittest_i2c_mux_data {
int nchans;
struct i2c_adapter *adap[];
};
static int unittest_i2c_mux_select_chan(struct i2c_adapter *adap,
void *client, u32 chan)
static int unittest_i2c_mux_select_chan(struct i2c_mux_core *muxc, u32 chan)
{
return 0;
}
@ -1706,11 +1700,11 @@ static int unittest_i2c_mux_select_chan(struct i2c_adapter *adap,
static int unittest_i2c_mux_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret, i, nchans, size;
int ret, i, nchans;
struct device *dev = &client->dev;
struct i2c_adapter *adap = to_i2c_adapter(dev->parent);
struct device_node *np = client->dev.of_node, *child;
struct unittest_i2c_mux_data *stm;
struct i2c_mux_core *muxc;
u32 reg, max_reg;
dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
@ -1734,25 +1728,20 @@ static int unittest_i2c_mux_probe(struct i2c_client *client,
return -EINVAL;
}
size = offsetof(struct unittest_i2c_mux_data, adap[nchans]);
stm = devm_kzalloc(dev, size, GFP_KERNEL);
if (!stm) {
dev_err(dev, "Out of memory\n");
muxc = i2c_mux_alloc(adap, dev, nchans, 0, 0,
unittest_i2c_mux_select_chan, NULL);
if (!muxc)
return -ENOMEM;
}
stm->nchans = nchans;
for (i = 0; i < nchans; i++) {
stm->adap[i] = i2c_add_mux_adapter(adap, dev, client,
0, i, 0, unittest_i2c_mux_select_chan, NULL);
if (!stm->adap[i]) {
ret = i2c_mux_add_adapter(muxc, 0, i, 0);
if (ret) {
dev_err(dev, "Failed to register mux #%d\n", i);
for (i--; i >= 0; i--)
i2c_del_mux_adapter(stm->adap[i]);
i2c_mux_del_adapters(muxc);
return -ENODEV;
}
}
i2c_set_clientdata(client, stm);
i2c_set_clientdata(client, muxc);
return 0;
};
@ -1761,12 +1750,10 @@ static int unittest_i2c_mux_remove(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct device_node *np = client->dev.of_node;
struct unittest_i2c_mux_data *stm = i2c_get_clientdata(client);
int i;
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
for (i = stm->nchans - 1; i >= 0; i--)
i2c_del_mux_adapter(stm->adap[i]);
i2c_mux_del_adapters(muxc);
return 0;
}

View File

@ -27,22 +27,49 @@
#ifdef __KERNEL__
/*
* Called to create a i2c bus on a multiplexed bus segment.
* The mux_dev and chan_id parameters are passed to the select
* and deselect callback functions to perform hardware-specific
* mux control.
*/
struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
struct device *mux_dev,
void *mux_priv, u32 force_nr, u32 chan_id,
unsigned int class,
int (*select) (struct i2c_adapter *,
void *mux_dev, u32 chan_id),
int (*deselect) (struct i2c_adapter *,
void *mux_dev, u32 chan_id));
#include <linux/bitops.h>
void i2c_del_mux_adapter(struct i2c_adapter *adap);
struct i2c_mux_core {
struct i2c_adapter *parent;
struct device *dev;
bool mux_locked;
void *priv;
int (*select)(struct i2c_mux_core *, u32 chan_id);
int (*deselect)(struct i2c_mux_core *, u32 chan_id);
int num_adapters;
int max_adapters;
struct i2c_adapter *adapter[0];
};
struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent,
struct device *dev, int max_adapters,
int sizeof_priv, u32 flags,
int (*select)(struct i2c_mux_core *, u32),
int (*deselect)(struct i2c_mux_core *, u32));
/* flags for i2c_mux_alloc */
#define I2C_MUX_LOCKED BIT(0)
static inline void *i2c_mux_priv(struct i2c_mux_core *muxc)
{
return muxc->priv;
}
struct i2c_adapter *i2c_root_adapter(struct device *dev);
/*
* Called to create an i2c bus on a multiplexed bus segment.
* The chan_id parameter is passed to the select and deselect
* callback functions to perform hardware-specific mux control.
*/
int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
u32 force_nr, u32 chan_id,
unsigned int class);
void i2c_mux_del_adapters(struct i2c_mux_core *muxc);
#endif /* __KERNEL__ */

View File

@ -524,6 +524,7 @@ struct i2c_adapter {
/* data fields that are valid for all devices */
struct rt_mutex bus_lock;
struct rt_mutex mux_lock;
int timeout; /* in jiffies */
int retries;
@ -538,6 +539,10 @@ struct i2c_adapter {
struct i2c_bus_recovery_info *bus_recovery_info;
const struct i2c_adapter_quirks *quirks;
void (*lock_bus)(struct i2c_adapter *, unsigned int flags);
int (*trylock_bus)(struct i2c_adapter *, unsigned int flags);
void (*unlock_bus)(struct i2c_adapter *, unsigned int flags);
};
#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
@ -567,8 +572,44 @@ i2c_parent_is_i2c_adapter(const struct i2c_adapter *adapter)
int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *));
/* Adapter locking functions, exported for shared pin cases */
void i2c_lock_adapter(struct i2c_adapter *);
void i2c_unlock_adapter(struct i2c_adapter *);
#define I2C_LOCK_ROOT_ADAPTER BIT(0)
#define I2C_LOCK_SEGMENT BIT(1)
/**
* i2c_lock_bus - Get exclusive access to an I2C bus segment
* @adapter: Target I2C bus segment
* @flags: I2C_LOCK_ROOT_ADAPTER locks the root i2c adapter, I2C_LOCK_SEGMENT
* locks only this branch in the adapter tree
*/
static inline void
i2c_lock_bus(struct i2c_adapter *adapter, unsigned int flags)
{
adapter->lock_bus(adapter, flags);
}
/**
* i2c_unlock_bus - Release exclusive access to an I2C bus segment
* @adapter: Target I2C bus segment
* @flags: I2C_LOCK_ROOT_ADAPTER unlocks the root i2c adapter, I2C_LOCK_SEGMENT
* unlocks only this branch in the adapter tree
*/
static inline void
i2c_unlock_bus(struct i2c_adapter *adapter, unsigned int flags)
{
adapter->unlock_bus(adapter, flags);
}
static inline void
i2c_lock_adapter(struct i2c_adapter *adapter)
{
i2c_lock_bus(adapter, I2C_LOCK_ROOT_ADAPTER);
}
static inline void
i2c_unlock_adapter(struct i2c_adapter *adapter)
{
i2c_unlock_bus(adapter, I2C_LOCK_ROOT_ADAPTER);
}
/*flags for the client struct: */
#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */
@ -654,6 +695,11 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap)
return adap->nr;
}
static inline u8 i2c_8bit_addr_from_msg(const struct i2c_msg *msg)
{
return (msg->addr << 1) | (msg->flags & I2C_M_RD ? 1 : 0);
}
/**
* module_i2c_driver() - Helper macro for registering a modular I2C driver
* @__i2c_driver: i2c_driver struct

View File

@ -68,14 +68,15 @@
struct i2c_msg {
__u16 addr; /* slave address */
__u16 flags;
#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
#define I2C_M_RD 0x0001 /* read data, from slave to master */
#define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */
#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
/* I2C_M_RD is guaranteed to be 0x0001! */
#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */
#define I2C_M_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */
__u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */
};