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