Merge branch 'i2c/for-5.6' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: "i2c core: - huge improvements and refactorizations of the Linux I2C documentation (lots of thanks to Luca for doing it and Jean for the careful review) - subsystem wide API conversion to i2c_new_client_device() - remove obsolete parport-light driver - smaller core updates (removal of 'extern', enabling more compile testing, use more helper macros) - and quite a bunch of driver updates (new IDs, simplifications, better PM, support of atomic transfers and other improvements) i2c-mux: - The main feature is the idle-state rework of the pca954x driver from Biwen Li at24 driver: - minor maintenance: update the license tag, sort headers - move support for the write-protect pin into nvmem core - add a reference to the new wp-gpios property in nvmem to at25 bindings - add support for regulator and pm_runtime control" * 'i2c/for-5.6' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (91 commits) i2c: cros-ec-tunnel: Fix ACPI identifier i2c: cros-ec-tunnel: Fix slave device enumeration i2c: stm32f7: add PM_SLEEP suspend/resume support i2c: cadence: Fix wording in i2c-cadence driver i2c: cadence: Fix power management order of operations i2c: cadence: Fix error printing in case of defer i2c: cadence: Handle transfer_size rollover i2c: i801: Add support for Intel Comet Lake PCH-V docs: i2c: writing-clients: properly name the stop condition docs: i2c: i2c-protocol: use same wording as smbus-protocol docs: i2c: rename sections so the overall picture is clearer docs: i2c: old-module-parameters: use monospace instead of "" docs: i2c: old-module-parameters: clarify this is for obsolete kernels docs: i2c: old-module-parameters: fix internal hyperlink docs: i2c: instantiating-devices: use monospace for sysfs attributes docs: i2c: instantiating-devices: rearrange static instatiation docs: i2c: instantiating-devices: fix internal hyperlink docs: i2c: smbus-protocol: improve I2C Block transactions description docs: i2c: smbus-protocol: fix punctuation docs: i2c: smbus-protocol: fix typo ...
This commit is contained in:
Коммит
11777ee8b0
|
@ -145,10 +145,7 @@ properties:
|
|||
over reads to the next slave address. Please consult the manual of
|
||||
your device.
|
||||
|
||||
wp-gpios:
|
||||
description:
|
||||
GPIO to which the write-protect pin of the chip is connected.
|
||||
maxItems: 1
|
||||
wp-gpios: true
|
||||
|
||||
address-width:
|
||||
allOf:
|
||||
|
@ -167,6 +164,10 @@ properties:
|
|||
minimum: 1
|
||||
maximum: 8
|
||||
|
||||
vcc-supply:
|
||||
description:
|
||||
phandle of the regulator that provides the supply voltage.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
|
@ -20,6 +20,7 @@ Optional properties:
|
|||
- spi-cpha : SPI shifted clock phase, as per spi-bus bindings.
|
||||
- spi-cpol : SPI inverse clock polarity, as per spi-bus bindings.
|
||||
- read-only : this parameter-less property disables writes to the eeprom
|
||||
- wp-gpios : GPIO to which the write-protect pin of the chip is connected
|
||||
|
||||
Obsolete legacy properties can be used in place of "size", "pagesize",
|
||||
"address-width", and "read-only":
|
||||
|
@ -36,6 +37,7 @@ Example:
|
|||
spi-max-frequency = <5000000>;
|
||||
spi-cpha;
|
||||
spi-cpol;
|
||||
wp-gpios = <&gpio1 3 0>;
|
||||
|
||||
pagesize = <64>;
|
||||
size = <32768>;
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
I2C for Atmel platforms
|
||||
|
||||
Required properties :
|
||||
- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c",
|
||||
"atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c",
|
||||
"atmel,at91sam9x5-i2c", "atmel,sama5d4-i2c", "atmel,sama5d2-i2c" or
|
||||
"microchip,sam9x60-i2c"
|
||||
- compatible : Must be one of:
|
||||
"atmel,at91rm9200-i2c",
|
||||
"atmel,at91sam9261-i2c",
|
||||
"atmel,at91sam9260-i2c",
|
||||
"atmel,at91sam9g20-i2c",
|
||||
"atmel,at91sam9g10-i2c",
|
||||
"atmel,at91sam9x5-i2c",
|
||||
"atmel,sama5d4-i2c",
|
||||
"atmel,sama5d2-i2c",
|
||||
"microchip,sam9x60-i2c".
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: interrupt number to the cpu.
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
* Ingenic JZ4780 I2C Bus controller
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "ingenic,jz4780-i2c"
|
||||
- compatible: should be one of the following:
|
||||
- "ingenic,jz4780-i2c" for the JZ4780
|
||||
- "ingenic,x1000-i2c" for the X1000
|
||||
- reg: Should contain the address & size of the I2C controller registers.
|
||||
- interrupts: Should specify the interrupt provided by parent.
|
||||
- clocks: Should contain a single clock specifier for the JZ4780 I2C clock.
|
||||
|
|
|
@ -25,6 +25,8 @@ Required Properties:
|
|||
Optional Properties:
|
||||
|
||||
- reset-gpios: Reference to the GPIO connected to the reset input.
|
||||
- idle-state: if present, overrides i2c-mux-idle-disconnect,
|
||||
Please refer to Documentation/devicetree/bindings/mux/mux-controller.txt
|
||||
- i2c-mux-idle-disconnect: Boolean; if defined, forces mux to disconnect all
|
||||
children in idle state. This is necessary for example, if there are several
|
||||
multiplexers on the bus and the devices behind them use same I2C addresses.
|
||||
|
|
|
@ -17,7 +17,8 @@ Required properties:
|
|||
"renesas,i2c-r8a7793" if the device is a part of a R8A7793 SoC.
|
||||
"renesas,i2c-r8a7794" if the device is a part of a R8A7794 SoC.
|
||||
"renesas,i2c-r8a7795" if the device is a part of a R8A7795 SoC.
|
||||
"renesas,i2c-r8a7796" if the device is a part of a R8A7796 SoC.
|
||||
"renesas,i2c-r8a7796" if the device is a part of a R8A77960 SoC.
|
||||
"renesas,i2c-r8a77961" if the device is a part of a R8A77961 SoC.
|
||||
"renesas,i2c-r8a77965" if the device is a part of a R8A77965 SoC.
|
||||
"renesas,i2c-r8a77970" if the device is a part of a R8A77970 SoC.
|
||||
"renesas,i2c-r8a77980" if the device is a part of a R8A77980 SoC.
|
||||
|
|
|
@ -17,6 +17,7 @@ Required properties:
|
|||
- "renesas,iic-r8a7794" (R-Car E2)
|
||||
- "renesas,iic-r8a7795" (R-Car H3)
|
||||
- "renesas,iic-r8a7796" (R-Car M3-W)
|
||||
- "renesas,iic-r8a77961" (R-Car M3-W+)
|
||||
- "renesas,iic-r8a77965" (R-Car M3-N)
|
||||
- "renesas,iic-r8a77990" (R-Car E3)
|
||||
- "renesas,iic-sh73a0" (SH-Mobile AG5)
|
||||
|
|
|
@ -34,6 +34,14 @@ properties:
|
|||
description:
|
||||
Mark the provider as read only.
|
||||
|
||||
wp-gpios:
|
||||
description:
|
||||
GPIO to which the write-protect pin of the chip is connected.
|
||||
The write-protect GPIO is asserted, when it's driven high
|
||||
(logical '1') to block the write operation. It's deasserted,
|
||||
when it's driven low (logical '0') to allow writing.
|
||||
maxItems: 1
|
||||
|
||||
patternProperties:
|
||||
"^.*@[0-9a-f]+$":
|
||||
type: object
|
||||
|
@ -63,9 +71,12 @@ patternProperties:
|
|||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
qfprom: eeprom@700000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
wp-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
/* ... */
|
||||
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
===============================
|
||||
Kernel driver i2c-parport-light
|
||||
===============================
|
||||
|
||||
Author: Jean Delvare <jdelvare@suse.de>
|
||||
|
||||
This driver is a light version of i2c-parport. It doesn't depend
|
||||
on the parport driver, and uses direct I/O access instead. This might be
|
||||
preferred on embedded systems where wasting memory for the clean but heavy
|
||||
parport handling is not an option. The drawback is a reduced portability
|
||||
and the impossibility to daisy-chain other parallel port devices.
|
||||
|
||||
Please see i2c-parport for documentation.
|
||||
|
||||
Module parameters:
|
||||
|
||||
* type: type of adapter (see i2c-parport or modinfo)
|
||||
|
||||
* base: base I/O address
|
||||
Default is 0x378 which is fairly common for parallel ports, at least on PC.
|
||||
|
||||
* irq: optional IRQ
|
||||
This must be passed if you want SMBus alert support, assuming your adapter
|
||||
actually supports this.
|
|
@ -20,7 +20,6 @@ I2C Bus Drivers
|
|||
i2c-nforce2
|
||||
i2c-nvidia-gpu
|
||||
i2c-ocores
|
||||
i2c-parport-light
|
||||
i2c-parport
|
||||
i2c-pca-isa
|
||||
i2c-piix4
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
====================
|
||||
I2C Device Interface
|
||||
====================
|
||||
============================================
|
||||
Implementing I2C device drivers in userspace
|
||||
============================================
|
||||
|
||||
Usually, i2c devices are controlled by a kernel driver. But it is also
|
||||
Usually, I2C devices are controlled by a kernel driver. But it is also
|
||||
possible to access all devices on an adapter from userspace, through
|
||||
the /dev interface. You need to load module i2c-dev for this.
|
||||
|
||||
Each registered i2c adapter gets a number, counting from 0. You can
|
||||
Each registered I2C adapter gets a number, counting from 0. You can
|
||||
examine /sys/class/i2c-dev/ to see what number corresponds to which adapter.
|
||||
Alternatively, you can run "i2cdetect -l" to obtain a formatted list of all
|
||||
i2c adapters present on your system at a given time. i2cdetect is part of
|
||||
I2C adapters present on your system at a given time. i2cdetect is part of
|
||||
the i2c-tools package.
|
||||
|
||||
I2C device files are character device files with major device number 89
|
||||
and a minor device number corresponding to the number assigned as
|
||||
explained above. They should be called "i2c-%d" (i2c-0, i2c-1, ...,
|
||||
i2c-10, ...). All 256 minor device numbers are reserved for i2c.
|
||||
i2c-10, ...). All 256 minor device numbers are reserved for I2C.
|
||||
|
||||
|
||||
C example
|
||||
=========
|
||||
|
||||
So let's say you want to access an i2c adapter from a C program.
|
||||
So let's say you want to access an I2C adapter from a C program.
|
||||
First, you need to include these two headers::
|
||||
|
||||
#include <linux/i2c-dev.h>
|
||||
|
@ -66,7 +66,7 @@ the device supports them. Both are illustrated below::
|
|||
/* Using SMBus commands */
|
||||
res = i2c_smbus_read_word_data(file, reg);
|
||||
if (res < 0) {
|
||||
/* ERROR HANDLING: i2c transaction failed */
|
||||
/* ERROR HANDLING: I2C transaction failed */
|
||||
} else {
|
||||
/* res contains the read word */
|
||||
}
|
||||
|
@ -79,12 +79,12 @@ the device supports them. Both are illustrated below::
|
|||
buf[1] = 0x43;
|
||||
buf[2] = 0x65;
|
||||
if (write(file, buf, 3) != 3) {
|
||||
/* ERROR HANDLING: i2c transaction failed */
|
||||
/* ERROR HANDLING: I2C transaction failed */
|
||||
}
|
||||
|
||||
/* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */
|
||||
if (read(file, buf, 1) != 1) {
|
||||
/* ERROR HANDLING: i2c transaction failed */
|
||||
/* ERROR HANDLING: I2C transaction failed */
|
||||
} else {
|
||||
/* buf[0] contains the read byte */
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ The following IOCTLs are defined:
|
|||
If possible, use the provided ``i2c_smbus_*`` methods described below instead
|
||||
of issuing direct ioctls.
|
||||
|
||||
You can do plain i2c transactions by using read(2) and write(2) calls.
|
||||
You can do plain I2C transactions by using read(2) and write(2) calls.
|
||||
You do not need to pass the address byte; instead, set it through
|
||||
ioctl I2C_SLAVE before you try to access the device.
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Linux I2C and DMA
|
||||
=================
|
||||
|
||||
Given that i2c is a low-speed bus, over which the majority of messages
|
||||
Given that I2C is a low-speed bus, over which the majority of messages
|
||||
transferred are small, it is not considered a prime user of DMA access. At this
|
||||
time of writing, only 10% of I2C bus master drivers have DMA support
|
||||
implemented. And the vast majority of transactions are so small that setting up
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
============
|
||||
I2C Protocol
|
||||
============
|
||||
================
|
||||
The I2C Protocol
|
||||
================
|
||||
|
||||
This document describes the i2c protocol. Or will, when it is finished :-)
|
||||
This document describes the I2C protocol. Or will, when it is finished :-)
|
||||
|
||||
Key to symbols
|
||||
==============
|
||||
|
||||
=============== =============================================================
|
||||
S (1 bit) : Start bit
|
||||
P (1 bit) : Stop bit
|
||||
Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
|
||||
A, NA (1 bit) : Accept and reverse accept bit.
|
||||
Addr (7 bits): I2C 7 bit address. Note that this can be expanded as usual to
|
||||
S Start condition
|
||||
P Stop condition
|
||||
Rd/Wr (1 bit) Read/Write bit. Rd equals 1, Wr equals 0.
|
||||
A, NA (1 bit) Acknowledge (ACK) and Not Acknowledge (NACK) bit
|
||||
Addr (7 bits) I2C 7 bit address. Note that this can be expanded as usual to
|
||||
get a 10 bit I2C address.
|
||||
Comm (8 bits): Command byte, a data byte which often selects a register on
|
||||
Comm (8 bits) Command byte, a data byte which often selects a register on
|
||||
the device.
|
||||
Data (8 bits): A plain data byte. Sometimes, I write DataLow, DataHigh
|
||||
Data (8 bits) A plain data byte. Sometimes, I write DataLow, DataHigh
|
||||
for 16 bit data.
|
||||
Count (8 bits): A data byte containing the length of a block operation.
|
||||
Count (8 bits) A data byte containing the length of a block operation.
|
||||
|
||||
[..]: Data sent by I2C device, as opposed to data sent by the
|
||||
[..] Data sent by I2C device, as opposed to data sent by the
|
||||
host adapter.
|
||||
=============== =============================================================
|
||||
|
||||
|
@ -28,7 +28,7 @@ Count (8 bits): A data byte containing the length of a block operation.
|
|||
Simple send transaction
|
||||
=======================
|
||||
|
||||
This corresponds to i2c_master_send::
|
||||
Implemented by i2c_master_send()::
|
||||
|
||||
S Addr Wr [A] Data [A] Data [A] ... [A] Data [A] P
|
||||
|
||||
|
@ -36,7 +36,7 @@ This corresponds to i2c_master_send::
|
|||
Simple receive transaction
|
||||
==========================
|
||||
|
||||
This corresponds to i2c_master_recv::
|
||||
Implemented by i2c_master_recv()::
|
||||
|
||||
S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P
|
||||
|
||||
|
@ -44,11 +44,11 @@ This corresponds to i2c_master_recv::
|
|||
Combined transactions
|
||||
=====================
|
||||
|
||||
This corresponds to i2c_transfer
|
||||
Implemented by i2c_transfer().
|
||||
|
||||
They are just like the above transactions, but instead of a stop bit P
|
||||
a start bit S is sent and the transaction continues. An example of
|
||||
a byte read, followed by a byte write::
|
||||
They are just like the above transactions, but instead of a stop
|
||||
condition P a start condition S is sent and the transaction continues.
|
||||
An example of a byte read, followed by a byte write::
|
||||
|
||||
S Addr Rd [A] [Data] NA S Addr Wr [A] Data [A] P
|
||||
|
||||
|
@ -57,7 +57,7 @@ Modified transactions
|
|||
=====================
|
||||
|
||||
The following modifications to the I2C protocol can also be generated by
|
||||
setting these flags for i2c messages. With the exception of I2C_M_NOSTART, they
|
||||
setting these flags for I2C messages. With the exception of I2C_M_NOSTART, they
|
||||
are usually only needed to work around device issues:
|
||||
|
||||
I2C_M_IGNORE_NAK:
|
||||
|
@ -77,8 +77,9 @@ I2C_M_NOSTART:
|
|||
S Addr Rd [A] [Data] NA Data [A] P
|
||||
|
||||
If you set the I2C_M_NOSTART variable for the first partial message,
|
||||
we do not generate Addr, but we do generate the startbit S. This will
|
||||
probably confuse all other clients on your bus, so don't try this.
|
||||
we do not generate Addr, but we do generate the start condition S.
|
||||
This will probably confuse all other clients on your bus, so don't
|
||||
try this.
|
||||
|
||||
This is often used to gather transmits from multiple data buffers in
|
||||
system memory into something that appears as a single transfer to the
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
============
|
||||
I2C topology
|
||||
============
|
||||
================================
|
||||
I2C muxes and complex topologies
|
||||
================================
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
|
@ -11,20 +11,20 @@ than a straight-forward i2c bus with one adapter and one or more devices.
|
|||
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
|
||||
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
|
||||
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"
|
||||
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
|
||||
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
|
||||
|
@ -34,7 +34,7 @@ optional) deselect is called after the transfer.
|
|||
Locking
|
||||
=======
|
||||
|
||||
There are two variants of locking available to i2c muxes, they can be
|
||||
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:
|
||||
|
@ -45,7 +45,7 @@ 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.
|
||||
same I2C root adapter that they mux.
|
||||
i2c-mux-gpmux Normally parent-locked, mux-locked iff
|
||||
specified in device-tree.
|
||||
i2c-mux-ltc4306 Mux-locked
|
||||
|
@ -54,7 +54,7 @@ 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.
|
||||
by the same I2C root adapter that they mux.
|
||||
i2c-mux-reg Parent-locked
|
||||
====================== =============================================
|
||||
|
||||
|
@ -83,9 +83,9 @@ 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
|
||||
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
|
||||
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.
|
||||
|
||||
|
@ -109,14 +109,14 @@ ML2. It is not safe to build arbitrary topologies with two (or more)
|
|||
|
||||
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
|
||||
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,
|
||||
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.
|
||||
behind the mux, when an unrelated I2C transfer is in flight during
|
||||
the non-I2C mux-changing operation.
|
||||
==== =====================================================================
|
||||
|
||||
|
||||
|
@ -137,14 +137,14 @@ Mux-locked Example
|
|||
|
||||
When there is an access to D1, this happens:
|
||||
|
||||
1. Someone issues an i2c-transfer to D1.
|
||||
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
|
||||
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.
|
||||
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.
|
||||
|
@ -159,8 +159,8 @@ 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.
|
||||
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.
|
||||
|
||||
|
@ -169,12 +169,12 @@ 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).
|
||||
and the parent mux issues 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
|
||||
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.
|
||||
|
@ -197,15 +197,15 @@ Parent-locked Example
|
|||
|
||||
When there is an access to D1, this happens:
|
||||
|
||||
1. Someone issues an i2c-transfer to D1.
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
@ -240,7 +240,7 @@ 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
|
||||
issues any unlocked I2C transfers on the root adapter that may leak
|
||||
through and be seen by the M2 adapter, thus closing M2 prematurely.
|
||||
|
||||
|
||||
|
@ -286,14 +286,14 @@ 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
|
||||
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
|
||||
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.
|
||||
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.
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
После Ширина: | Высота: | Размер: 55 KiB |
|
@ -4,30 +4,66 @@
|
|||
I2C/SMBus Subsystem
|
||||
===================
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
summary
|
||||
i2c-protocol
|
||||
smbus-protocol
|
||||
instantiating-devices
|
||||
busses/index
|
||||
i2c-topology
|
||||
muxes/i2c-mux-gpio
|
||||
|
||||
Writing device drivers
|
||||
======================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
writing-clients
|
||||
dev-interface
|
||||
dma-considerations
|
||||
fault-codes
|
||||
functionality
|
||||
|
||||
Debugging
|
||||
=========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
gpio-fault-injection
|
||||
i2c-protocol
|
||||
i2c-stub
|
||||
i2c-topology
|
||||
instantiating-devices
|
||||
old-module-parameters
|
||||
slave-eeprom-backend
|
||||
|
||||
Slave I2C
|
||||
=========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
slave-interface
|
||||
smbus-protocol
|
||||
summary
|
||||
slave-eeprom-backend
|
||||
|
||||
Advanced topics
|
||||
===============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
ten-bit-addresses
|
||||
|
||||
Legacy documentation
|
||||
====================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
upgrading-clients
|
||||
writing-clients
|
||||
|
||||
muxes/i2c-mux-gpio
|
||||
|
||||
busses/index
|
||||
old-module-parameters
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
|
|
|
@ -9,14 +9,67 @@ reason, the kernel code must instantiate I2C devices explicitly. There are
|
|||
several ways to achieve this, depending on the context and requirements.
|
||||
|
||||
|
||||
Method 1a: Declare the I2C devices by bus number
|
||||
------------------------------------------------
|
||||
Method 1: Declare the I2C devices statically
|
||||
--------------------------------------------
|
||||
|
||||
This method is appropriate when the I2C bus is a system bus as is the case
|
||||
for many embedded systems. On such systems, each I2C bus has a number
|
||||
which is known in advance. It is thus possible to pre-declare the I2C
|
||||
devices which live on this bus. This is done with an array of struct
|
||||
i2c_board_info which is registered by calling i2c_register_board_info().
|
||||
for many embedded systems. On such systems, each I2C bus has a number which
|
||||
is known in advance. It is thus possible to pre-declare the I2C devices
|
||||
which live on this bus.
|
||||
|
||||
This information is provided to the kernel in a different way on different
|
||||
architectures: device tree, ACPI or board files.
|
||||
|
||||
When the I2C bus in question is registered, the I2C devices will be
|
||||
instantiated automatically by i2c-core. The devices will be automatically
|
||||
unbound and destroyed when the I2C bus they sit on goes away (if ever).
|
||||
|
||||
|
||||
Declare the I2C devices via devicetree
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
On platforms using devicetree, the declaration of I2C devices is done in
|
||||
subnodes of the master controller.
|
||||
|
||||
Example::
|
||||
|
||||
i2c1: i2c@400a0000 {
|
||||
/* ... master properties skipped ... */
|
||||
clock-frequency = <100000>;
|
||||
|
||||
flash@50 {
|
||||
compatible = "atmel,24c256";
|
||||
reg = <0x50>;
|
||||
};
|
||||
|
||||
pca9532: gpio@60 {
|
||||
compatible = "nxp,pca9532";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
reg = <0x60>;
|
||||
};
|
||||
};
|
||||
|
||||
Here, two devices are attached to the bus using a speed of 100kHz. For
|
||||
additional properties which might be needed to set up the device, please refer
|
||||
to its devicetree documentation in Documentation/devicetree/bindings/.
|
||||
|
||||
|
||||
Declare the I2C devices via ACPI
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
ACPI can also describe I2C devices. There is special documentation for this
|
||||
which is currently located at :doc:`../firmware-guide/acpi/enumeration`.
|
||||
|
||||
|
||||
Declare the I2C devices in board files
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In many embedded architectures, devicetree has replaced the old hardware
|
||||
description based on board files, but the latter are still used in old
|
||||
code. Instantiating I2C devices via board files is done with an array of
|
||||
struct i2c_board_info which is registered by calling
|
||||
i2c_register_board_info().
|
||||
|
||||
Example (from omap2 h4)::
|
||||
|
||||
|
@ -44,49 +97,7 @@ Example (from omap2 h4)::
|
|||
}
|
||||
|
||||
The above code declares 3 devices on I2C bus 1, including their respective
|
||||
addresses and custom data needed by their drivers. When the I2C bus in
|
||||
question is registered, the I2C devices will be instantiated automatically
|
||||
by i2c-core.
|
||||
|
||||
The devices will be automatically unbound and destroyed when the I2C bus
|
||||
they sit on goes away (if ever.)
|
||||
|
||||
|
||||
Method 1b: Declare the I2C devices via devicetree
|
||||
-------------------------------------------------
|
||||
|
||||
This method has the same implications as method 1a. The declaration of I2C
|
||||
devices is here done via devicetree as subnodes of the master controller.
|
||||
|
||||
Example::
|
||||
|
||||
i2c1: i2c@400a0000 {
|
||||
/* ... master properties skipped ... */
|
||||
clock-frequency = <100000>;
|
||||
|
||||
flash@50 {
|
||||
compatible = "atmel,24c256";
|
||||
reg = <0x50>;
|
||||
};
|
||||
|
||||
pca9532: gpio@60 {
|
||||
compatible = "nxp,pca9532";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
reg = <0x60>;
|
||||
};
|
||||
};
|
||||
|
||||
Here, two devices are attached to the bus using a speed of 100kHz. For
|
||||
additional properties which might be needed to set up the device, please refer
|
||||
to its devicetree documentation in Documentation/devicetree/bindings/.
|
||||
|
||||
|
||||
Method 1c: Declare the I2C devices via ACPI
|
||||
-------------------------------------------
|
||||
|
||||
ACPI can also describe I2C devices. There is special documentation for this
|
||||
which is currently located at Documentation/firmware-guide/acpi/enumeration.rst.
|
||||
addresses and custom data needed by their drivers.
|
||||
|
||||
|
||||
Method 2: Instantiate the devices explicitly
|
||||
|
@ -98,7 +109,7 @@ tuner, a video decoder, an audio decoder, etc. usually connected to the
|
|||
main chip by the means of an I2C bus. You won't know the number of the I2C
|
||||
bus in advance, so the method 1 described above can't be used. Instead,
|
||||
you can instantiate your I2C devices explicitly. This is done by filling
|
||||
a struct i2c_board_info and calling i2c_new_device().
|
||||
a struct i2c_board_info and calling i2c_new_client_device().
|
||||
|
||||
Example (from the sfe4001 network driver)::
|
||||
|
||||
|
@ -110,7 +121,7 @@ Example (from the sfe4001 network driver)::
|
|||
{
|
||||
(...)
|
||||
efx->board_info.hwmon_client =
|
||||
i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info);
|
||||
i2c_new_client_device(&efx->i2c_adap, &sfe4001_hwmon_info);
|
||||
|
||||
(...)
|
||||
}
|
||||
|
@ -123,7 +134,7 @@ present or not (for example for an optional feature which is not present
|
|||
on cheap variants of a board but you have no way to tell them apart), or
|
||||
it may have different addresses from one board to the next (manufacturer
|
||||
changing its design without notice). In this case, you can call
|
||||
i2c_new_scanned_device() instead of i2c_new_device().
|
||||
i2c_new_scanned_device() instead of i2c_new_client_device().
|
||||
|
||||
Example (from the nxp OHCI driver)::
|
||||
|
||||
|
@ -152,7 +163,7 @@ simply gives up.
|
|||
|
||||
The driver which instantiated the I2C device is responsible for destroying
|
||||
it on cleanup. This is done by calling i2c_unregister_device() on the
|
||||
pointer that was earlier returned by i2c_new_device() or
|
||||
pointer that was earlier returned by i2c_new_client_device() or
|
||||
i2c_new_scanned_device().
|
||||
|
||||
|
||||
|
@ -188,7 +199,7 @@ destroyed automatically when the driver which detected them is removed,
|
|||
or when the underlying I2C bus is itself destroyed, whichever happens
|
||||
first.
|
||||
|
||||
Those of you familiar with the i2c subsystem of 2.4 kernels and early 2.6
|
||||
Those of you familiar with the I2C subsystem of 2.4 kernels and early 2.6
|
||||
kernels will find out that this method 3 is essentially similar to what
|
||||
was done there. Two significant differences are:
|
||||
|
||||
|
@ -214,15 +225,15 @@ In general, the kernel should know which I2C devices are connected and
|
|||
what addresses they live at. However, in certain cases, it does not, so a
|
||||
sysfs interface was added to let the user provide the information. This
|
||||
interface is made of 2 attribute files which are created in every I2C bus
|
||||
directory: new_device and delete_device. Both files are write only and you
|
||||
must write the right parameters to them in order to properly instantiate,
|
||||
respectively delete, an I2C device.
|
||||
directory: ``new_device`` and ``delete_device``. Both files are write
|
||||
only and you must write the right parameters to them in order to properly
|
||||
instantiate, respectively delete, an I2C device.
|
||||
|
||||
File new_device takes 2 parameters: the name of the I2C device (a string)
|
||||
and the address of the I2C device (a number, typically expressed in
|
||||
hexadecimal starting with 0x, but can also be expressed in decimal.)
|
||||
File ``new_device`` takes 2 parameters: the name of the I2C device (a
|
||||
string) and the address of the I2C device (a number, typically expressed
|
||||
in hexadecimal starting with 0x, but can also be expressed in decimal.)
|
||||
|
||||
File delete_device takes a single parameter: the address of the I2C
|
||||
File ``delete_device`` takes a single parameter: the address of the I2C
|
||||
device. As no two devices can live at the same address on a given I2C
|
||||
segment, the address is sufficient to uniquely identify the device to be
|
||||
deleted.
|
||||
|
|
|
@ -1,19 +1,24 @@
|
|||
=================================================
|
||||
I2C device driver binding control from user-space
|
||||
=================================================
|
||||
================================================================
|
||||
I2C device driver binding control from user-space in old kernels
|
||||
================================================================
|
||||
|
||||
Up to kernel 2.6.32, many i2c drivers used helper macros provided by
|
||||
.. NOTE::
|
||||
Note: this section is only relevant if you are handling some old code
|
||||
found in kernel 2.6. If you work with more recent kernels, you can
|
||||
safely skip this section.
|
||||
|
||||
Up to kernel 2.6.32, many I2C drivers used helper macros provided by
|
||||
<linux/i2c.h> which created standard module parameters to let the user
|
||||
control how the driver would probe i2c buses and attach to devices. These
|
||||
parameters were known as "probe" (to let the driver probe for an extra
|
||||
address), "force" (to forcibly attach the driver to a given device) and
|
||||
"ignore" (to prevent a driver from probing a given address).
|
||||
control how the driver would probe I2C buses and attach to devices. These
|
||||
parameters were known as ``probe`` (to let the driver probe for an extra
|
||||
address), ``force`` (to forcibly attach the driver to a given device) and
|
||||
``ignore`` (to prevent a driver from probing a given address).
|
||||
|
||||
With the conversion of the i2c subsystem to the standard device driver
|
||||
With the conversion of the I2C subsystem to the standard device driver
|
||||
binding model, it became clear that these per-module parameters were no
|
||||
longer needed, and that a centralized implementation was possible. The new,
|
||||
sysfs-based interface is described in the documentation file
|
||||
"instantiating-devices", section "Method 4: Instantiate from user-space".
|
||||
sysfs-based interface is described in :doc:`instantiating-devices`, section
|
||||
"Method 4: Instantiate from user-space".
|
||||
|
||||
Below is a mapping from the old module parameters to the new interface.
|
||||
|
||||
|
@ -42,8 +47,8 @@ New method (sysfs interface)::
|
|||
# echo dummy 0x2f > /sys/bus/i2c/devices/i2c-1/new_device
|
||||
# modprobe <driver>
|
||||
|
||||
Of course, it is important to instantiate the "dummy" device before loading
|
||||
Of course, it is important to instantiate the ``dummy`` device before loading
|
||||
the driver. The dummy device will be handled by i2c-core itself, preventing
|
||||
other drivers from binding to it later on. If there is a real device at the
|
||||
problematic address, and you want another driver to bind to it, then simply
|
||||
pass the name of the device in question instead of "dummy".
|
||||
pass the name of the device in question instead of ``dummy``.
|
||||
|
|
|
@ -59,7 +59,7 @@ The bus driver sends an event to the backend using the following function::
|
|||
|
||||
ret = i2c_slave_event(client, event, &val)
|
||||
|
||||
'client' describes the i2c slave device. 'event' is one of the special event
|
||||
'client' describes the I2C slave device. 'event' is one of the special event
|
||||
types described hereafter. 'val' holds an u8 value for the data byte to be
|
||||
read/written and is thus bidirectional. The pointer to val must always be
|
||||
provided even if val is not used for an event, i.e. don't use NULL here. 'ret'
|
||||
|
@ -143,7 +143,7 @@ Bus driver support
|
|||
If you want to add slave support to the bus driver:
|
||||
|
||||
* implement calls to register/unregister the slave and add those to the
|
||||
struct i2c_algorithm. When registering, you probably need to set the i2c
|
||||
struct i2c_algorithm. When registering, you probably need to set the I2C
|
||||
slave address and enable slave specific interrupts. If you use runtime pm, you
|
||||
should use pm_runtime_get_sync() because your device usually needs to be
|
||||
powered on always to be able to detect its slave address. When unregistering,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
======================
|
||||
SMBus Protocol Summary
|
||||
======================
|
||||
==================
|
||||
The SMBus Protocol
|
||||
==================
|
||||
|
||||
The following is a summary of the SMBus protocol. It applies to
|
||||
all revisions of the protocol (1.0, 1.1, and 2.0).
|
||||
|
@ -27,27 +27,27 @@ a different protocol operation entirely.
|
|||
Each transaction type corresponds to a functionality flag. Before calling a
|
||||
transaction function, a device driver should always check (just once) for
|
||||
the corresponding functionality flag to ensure that the underlying I2C
|
||||
adapter supports the transaction in question. See
|
||||
<file:Documentation/i2c/functionality.rst> for the details.
|
||||
adapter supports the transaction in question. See :doc:`functionality` for
|
||||
the details.
|
||||
|
||||
|
||||
Key to symbols
|
||||
==============
|
||||
|
||||
=============== =============================================================
|
||||
S (1 bit) : Start bit
|
||||
P (1 bit) : Stop bit
|
||||
Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
|
||||
A, NA (1 bit) : Accept and reverse accept bit.
|
||||
Addr (7 bits): I2C 7 bit address. Note that this can be expanded as usual to
|
||||
S Start condition
|
||||
P Stop condition
|
||||
Rd/Wr (1 bit) Read/Write bit. Rd equals 1, Wr equals 0.
|
||||
A, NA (1 bit) Acknowledge (ACK) and Not Acknowledge (NACK) bit
|
||||
Addr (7 bits) I2C 7 bit address. Note that this can be expanded as usual to
|
||||
get a 10 bit I2C address.
|
||||
Comm (8 bits): Command byte, a data byte which often selects a register on
|
||||
Comm (8 bits) Command byte, a data byte which often selects a register on
|
||||
the device.
|
||||
Data (8 bits): A plain data byte. Sometimes, I write DataLow, DataHigh
|
||||
Data (8 bits) A plain data byte. Sometimes, I write DataLow, DataHigh
|
||||
for 16 bit data.
|
||||
Count (8 bits): A data byte containing the length of a block operation.
|
||||
Count (8 bits) A data byte containing the length of a block operation.
|
||||
|
||||
[..]: Data sent by I2C device, as opposed to data sent by the host
|
||||
[..] Data sent by I2C device, as opposed to data sent by the host
|
||||
adapter.
|
||||
=============== =============================================================
|
||||
|
||||
|
@ -62,8 +62,10 @@ This sends a single bit to the device, at the place of the Rd/Wr bit::
|
|||
Functionality flag: I2C_FUNC_SMBUS_QUICK
|
||||
|
||||
|
||||
SMBus Receive Byte: i2c_smbus_read_byte()
|
||||
==========================================
|
||||
SMBus Receive Byte
|
||||
==================
|
||||
|
||||
Implemented by i2c_smbus_read_byte()
|
||||
|
||||
This reads a single byte from a device, without specifying a device
|
||||
register. Some devices are so simple that this interface is enough; for
|
||||
|
@ -75,8 +77,10 @@ the previous SMBus command::
|
|||
Functionality flag: I2C_FUNC_SMBUS_READ_BYTE
|
||||
|
||||
|
||||
SMBus Send Byte: i2c_smbus_write_byte()
|
||||
========================================
|
||||
SMBus Send Byte
|
||||
===============
|
||||
|
||||
Implemented by i2c_smbus_write_byte()
|
||||
|
||||
This operation is the reverse of Receive Byte: it sends a single byte
|
||||
to a device. See Receive Byte for more information.
|
||||
|
@ -88,8 +92,10 @@ to a device. See Receive Byte for more information.
|
|||
Functionality flag: I2C_FUNC_SMBUS_WRITE_BYTE
|
||||
|
||||
|
||||
SMBus Read Byte: i2c_smbus_read_byte_data()
|
||||
============================================
|
||||
SMBus Read Byte
|
||||
===============
|
||||
|
||||
Implemented by i2c_smbus_read_byte_data()
|
||||
|
||||
This reads a single byte from a device, from a designated register.
|
||||
The register is specified through the Comm byte::
|
||||
|
@ -99,8 +105,10 @@ The register is specified through the Comm byte::
|
|||
Functionality flag: I2C_FUNC_SMBUS_READ_BYTE_DATA
|
||||
|
||||
|
||||
SMBus Read Word: i2c_smbus_read_word_data()
|
||||
============================================
|
||||
SMBus Read Word
|
||||
===============
|
||||
|
||||
Implemented by i2c_smbus_read_word_data()
|
||||
|
||||
This operation is very like Read Byte; again, data is read from a
|
||||
device, from a designated register that is specified through the Comm
|
||||
|
@ -110,13 +118,15 @@ byte. But this time, the data is a complete word (16 bits)::
|
|||
|
||||
Functionality flag: I2C_FUNC_SMBUS_READ_WORD_DATA
|
||||
|
||||
Note the convenience function i2c_smbus_read_word_swapped is
|
||||
Note the convenience function i2c_smbus_read_word_swapped() is
|
||||
available for reads where the two data bytes are the other way
|
||||
around (not SMBus compliant, but very popular.)
|
||||
|
||||
|
||||
SMBus Write Byte: i2c_smbus_write_byte_data()
|
||||
==============================================
|
||||
SMBus Write Byte
|
||||
================
|
||||
|
||||
Implemented by i2c_smbus_write_byte_data()
|
||||
|
||||
This writes a single byte to a device, to a designated register. The
|
||||
register is specified through the Comm byte. This is the opposite of
|
||||
|
@ -129,24 +139,26 @@ the Read Byte operation.
|
|||
Functionality flag: I2C_FUNC_SMBUS_WRITE_BYTE_DATA
|
||||
|
||||
|
||||
SMBus Write Word: i2c_smbus_write_word_data()
|
||||
==============================================
|
||||
SMBus Write Word
|
||||
================
|
||||
|
||||
Implemented by i2c_smbus_write_word_data()
|
||||
|
||||
This is the opposite of the Read Word operation. 16 bits
|
||||
of data is written to a device, to the designated register that is
|
||||
specified through the Comm byte.::
|
||||
of data are written to a device, to the designated register that is
|
||||
specified through the Comm byte::
|
||||
|
||||
S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P
|
||||
|
||||
Functionality flag: I2C_FUNC_SMBUS_WRITE_WORD_DATA
|
||||
|
||||
Note the convenience function i2c_smbus_write_word_swapped is
|
||||
Note the convenience function i2c_smbus_write_word_swapped() is
|
||||
available for writes where the two data bytes are the other way
|
||||
around (not SMBus compliant, but very popular.)
|
||||
|
||||
|
||||
SMBus Process Call:
|
||||
===================
|
||||
SMBus Process Call
|
||||
==================
|
||||
|
||||
This command selects a device register (through the Comm byte), sends
|
||||
16 bits of data to it, and reads 16 bits of data in return::
|
||||
|
@ -157,8 +169,10 @@ This command selects a device register (through the Comm byte), sends
|
|||
Functionality flag: I2C_FUNC_SMBUS_PROC_CALL
|
||||
|
||||
|
||||
SMBus Block Read: i2c_smbus_read_block_data()
|
||||
==============================================
|
||||
SMBus Block Read
|
||||
================
|
||||
|
||||
Implemented by i2c_smbus_read_block_data()
|
||||
|
||||
This command reads a block of up to 32 bytes from a device, from a
|
||||
designated register that is specified through the Comm byte. The amount
|
||||
|
@ -172,8 +186,10 @@ of data is specified by the device in the Count byte.
|
|||
Functionality flag: I2C_FUNC_SMBUS_READ_BLOCK_DATA
|
||||
|
||||
|
||||
SMBus Block Write: i2c_smbus_write_block_data()
|
||||
================================================
|
||||
SMBus Block Write
|
||||
=================
|
||||
|
||||
Implemented by i2c_smbus_write_block_data()
|
||||
|
||||
The opposite of the Block Read command, this writes up to 32 bytes to
|
||||
a device, to a designated register that is specified through the
|
||||
|
@ -266,16 +282,19 @@ This is implemented the following way in the Linux kernel:
|
|||
I2C Block Transactions
|
||||
======================
|
||||
|
||||
The following I2C block transactions are supported by the
|
||||
SMBus layer and are described here for completeness.
|
||||
They are *NOT* defined by the SMBus specification.
|
||||
The following I2C block transactions are similar to the SMBus Block Read
|
||||
and Write operations, except these do not have a Count byte. They are
|
||||
supported by the SMBus layer and are described here for completeness, but
|
||||
they are *NOT* defined by the SMBus specification.
|
||||
|
||||
I2C block transactions do not limit the number of bytes transferred
|
||||
but the SMBus layer places a limit of 32 bytes.
|
||||
|
||||
|
||||
I2C Block Read: i2c_smbus_read_i2c_block_data()
|
||||
================================================
|
||||
I2C Block Read
|
||||
==============
|
||||
|
||||
Implemented by i2c_smbus_read_i2c_block_data()
|
||||
|
||||
This command reads a block of bytes from a device, from a
|
||||
designated register that is specified through the Comm byte::
|
||||
|
@ -286,8 +305,10 @@ designated register that is specified through the Comm byte::
|
|||
Functionality flag: I2C_FUNC_SMBUS_READ_I2C_BLOCK
|
||||
|
||||
|
||||
I2C Block Write: i2c_smbus_write_i2c_block_data()
|
||||
==================================================
|
||||
I2C Block Write
|
||||
===============
|
||||
|
||||
Implemented by i2c_smbus_write_i2c_block_data()
|
||||
|
||||
The opposite of the Block Read command, this writes bytes to
|
||||
a device, to a designated register that is specified through the
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
=============
|
||||
I2C and SMBus
|
||||
=============
|
||||
=============================
|
||||
Introduction to I2C and SMBus
|
||||
=============================
|
||||
|
||||
I2C (pronounce: I squared C) is a protocol developed by Philips. It is a
|
||||
slow two-wire protocol (variable speed, up to 400 kHz), with a high speed
|
||||
extension (3.4 MHz). It provides an inexpensive bus for connecting many
|
||||
types of devices with infrequent or low bandwidth communications needs.
|
||||
I2C is widely used with embedded systems. Some systems use variants that
|
||||
don't meet branding requirements, and so are not advertised as being I2C.
|
||||
I²C (pronounce: I squared C and written I2C in the kernel documentation) is
|
||||
a protocol developed by Philips. It is a slow two-wire protocol (variable
|
||||
speed, up to 400 kHz), with a high speed extension (3.4 MHz). It provides
|
||||
an inexpensive bus for connecting many types of devices with infrequent or
|
||||
low bandwidth communications needs. I2C is widely used with embedded
|
||||
systems. Some systems use variants that don't meet branding requirements,
|
||||
and so are not advertised as being I2C but come under different names,
|
||||
e.g. TWI (Two Wire Interface), IIC.
|
||||
|
||||
The official I2C specification is the `"I2C-bus specification and user
|
||||
manual" (UM10204) <https://www.nxp.com/docs/en/user-guide/UM10204.pdf>`_
|
||||
published by NXP Semiconductors.
|
||||
|
||||
SMBus (System Management Bus) is based on the I2C protocol, and is mostly
|
||||
a subset of I2C protocols and signaling. Many I2C devices will work on an
|
||||
|
@ -25,21 +31,29 @@ implement all the common SMBus protocol semantics or messages.
|
|||
Terminology
|
||||
===========
|
||||
|
||||
When we talk about I2C, we use the following terms::
|
||||
Using the terminology from the official documentation, the I2C bus connects
|
||||
one or more *master* chips and one or more *slave* chips.
|
||||
|
||||
Bus -> Algorithm
|
||||
Adapter
|
||||
Device -> Driver
|
||||
Client
|
||||
.. kernel-figure:: i2c.svg
|
||||
:alt: Simple I2C bus with one master and 3 slaves
|
||||
|
||||
An Algorithm driver contains general code that can be used for a whole class
|
||||
of I2C adapters. Each specific adapter driver either depends on one algorithm
|
||||
driver, or includes its own implementation.
|
||||
Simple I2C bus
|
||||
|
||||
A Driver driver (yes, this sounds ridiculous, sorry) contains the general
|
||||
code to access some type of device. Each detected device gets its own
|
||||
data in the Client structure. Usually, Driver and Client are more closely
|
||||
integrated than Algorithm and Adapter.
|
||||
A **master** chip is a node that starts communications with slaves. In the
|
||||
Linux kernel implementation it is called an **adapter** or bus. Adapter
|
||||
drivers are in the ``drivers/i2c/busses/`` subdirectory.
|
||||
|
||||
For a given configuration, you will need a driver for your I2C bus, and
|
||||
drivers for your I2C devices (usually one driver for each device).
|
||||
An **algorithm** contains general code that can be used to implement a
|
||||
whole class of I2C adapters. Each specific adapter driver either depends on
|
||||
an algorithm driver in the ``drivers/i2c/algos/`` subdirectory, or includes
|
||||
its own implementation.
|
||||
|
||||
A **slave** chip is a node that responds to communications when addressed
|
||||
by the master. In Linux it is called a **client**. Client drivers are kept
|
||||
in a directory specific to the feature they provide, for example
|
||||
``drivers/media/gpio/`` for GPIO expanders and ``drivers/media/i2c/`` for
|
||||
video-related chips.
|
||||
|
||||
For the example configuration in figure, you will need a driver for your
|
||||
I2C adapter, and drivers for your I2C devices (usually one driver for each
|
||||
device).
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
===================
|
||||
Writing I2C Clients
|
||||
===================
|
||||
===============================
|
||||
Implementing I2C device drivers
|
||||
===============================
|
||||
|
||||
This is a small guide for those who want to write kernel drivers for I2C
|
||||
or SMBus devices, using Linux as the protocol host/master (not slave).
|
||||
|
@ -95,7 +95,7 @@ to gather information from the client, or write new information to the
|
|||
client.
|
||||
|
||||
I have found it useful to define foo_read and foo_write functions for this.
|
||||
For some cases, it will be easier to call the i2c functions directly,
|
||||
For some cases, it will be easier to call the I2C functions directly,
|
||||
but many chips have some kind of register-value idea that can easily
|
||||
be encapsulated.
|
||||
|
||||
|
@ -175,8 +175,8 @@ Device Creation
|
|||
If you know for a fact that an I2C device is connected to a given I2C bus,
|
||||
you can instantiate that device by simply filling an i2c_board_info
|
||||
structure with the device address and driver name, and calling
|
||||
i2c_new_device(). This will create the device, then the driver core will
|
||||
take care of finding the right driver and will call its probe() method.
|
||||
i2c_new_client_device(). This will create the device, then the driver core
|
||||
will take care of finding the right driver and will call its probe() method.
|
||||
If a driver supports different device types, you can specify the type you
|
||||
want using the type field. You can also specify an IRQ and platform data
|
||||
if needed.
|
||||
|
@ -186,14 +186,14 @@ don't know the exact address it uses. This happens on TV adapters for
|
|||
example, where the same driver supports dozens of slightly different
|
||||
models, and I2C device addresses change from one model to the next. In
|
||||
that case, you can use the i2c_new_scanned_device() variant, which is
|
||||
similar to i2c_new_device(), except that it takes an additional list of
|
||||
possible I2C addresses to probe. A device is created for the first
|
||||
similar to i2c_new_client_device(), except that it takes an additional list
|
||||
of possible I2C addresses to probe. A device is created for the first
|
||||
responsive address in the list. If you expect more than one device to be
|
||||
present in the address range, simply call i2c_new_scanned_device() that
|
||||
many times.
|
||||
|
||||
The call to i2c_new_device() or i2c_new_scanned_device() typically happens
|
||||
in the I2C bus driver. You may want to save the returned i2c_client
|
||||
The call to i2c_new_client_device() or i2c_new_scanned_device() typically
|
||||
happens in the I2C bus driver. You may want to save the returned i2c_client
|
||||
reference for later use.
|
||||
|
||||
|
||||
|
@ -236,11 +236,11 @@ possible.
|
|||
Device Deletion
|
||||
---------------
|
||||
|
||||
Each I2C device which has been created using i2c_new_device() or
|
||||
i2c_new_scanned_device() can be unregistered by calling
|
||||
Each I2C device which has been created using i2c_new_client_device()
|
||||
or i2c_new_scanned_device() can be unregistered by calling
|
||||
i2c_unregister_device(). If you don't call it explicitly, it will be
|
||||
called automatically before the underlying I2C bus itself is removed, as a
|
||||
device can't survive its parent in the device driver model.
|
||||
called automatically before the underlying I2C bus itself is removed,
|
||||
as a device can't survive its parent in the device driver model.
|
||||
|
||||
|
||||
Initializing the driver
|
||||
|
@ -344,7 +344,7 @@ Plain I2C communication
|
|||
int i2c_master_recv(struct i2c_client *client, char *buf, int count);
|
||||
|
||||
These routines read and write some bytes from/to a client. The client
|
||||
contains the i2c address, so you do not have to include it. The second
|
||||
contains the I2C address, so you do not have to include it. The second
|
||||
parameter contains the bytes to read/write, the third the number of bytes
|
||||
to read/write (must be less than the length of the buffer, also should be
|
||||
less than 64k since msg.len is u16.) Returned is the actual number of bytes
|
||||
|
@ -357,9 +357,9 @@ read/written.
|
|||
|
||||
This sends a series of messages. Each message can be a read or write,
|
||||
and they can be mixed in any way. The transactions are combined: no
|
||||
stop bit is sent between transaction. The i2c_msg structure contains
|
||||
for each message the client address, the number of bytes of the message
|
||||
and the message data itself.
|
||||
stop condition is issued between transaction. The i2c_msg structure
|
||||
contains for each message the client address, the number of bytes of the
|
||||
message and the message data itself.
|
||||
|
||||
You can read the file ``i2c-protocol`` for more information about the
|
||||
actual I2C protocol.
|
||||
|
|
|
@ -7814,9 +7814,7 @@ M: Jean Delvare <jdelvare@suse.com>
|
|||
L: linux-i2c@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/i2c/busses/i2c-parport.rst
|
||||
F: Documentation/i2c/busses/i2c-parport-light.rst
|
||||
F: drivers/i2c/busses/i2c-parport.c
|
||||
F: drivers/i2c/busses/i2c-parport-light.c
|
||||
|
||||
I2C SUBSYSTEM
|
||||
M: Wolfram Sang <wsa@the-dreams.de>
|
||||
|
|
|
@ -367,7 +367,8 @@ comment "I2C system bus drivers (mostly embedded / system-on-chip)"
|
|||
|
||||
config I2C_ALTERA
|
||||
tristate "Altera Soft IP I2C"
|
||||
depends on (ARCH_SOCFPGA || NIOS2) && OF
|
||||
depends on ARCH_SOCFPGA || NIOS2 || COMPILE_TEST
|
||||
depends on OF
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
Altera Soft IP I2C interfaces on SoCFPGA and Nios2 architectures.
|
||||
|
@ -387,7 +388,7 @@ config I2C_ASPEED
|
|||
|
||||
config I2C_AT91
|
||||
tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
|
||||
depends on ARCH_AT91
|
||||
depends on ARCH_AT91 || COMPILE_TEST
|
||||
help
|
||||
This supports the use of the I2C interface on Atmel AT91
|
||||
processors.
|
||||
|
@ -440,7 +441,8 @@ config I2C_AXXIA
|
|||
|
||||
config I2C_BCM2835
|
||||
tristate "Broadcom BCM2835 I2C controller"
|
||||
depends on ARCH_BCM2835 || ARCH_BRCMSTB
|
||||
depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST
|
||||
depends on COMMON_CLK
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
BCM2835 I2C controller.
|
||||
|
@ -463,8 +465,8 @@ config I2C_BCM_IPROC
|
|||
|
||||
config I2C_BCM_KONA
|
||||
tristate "BCM Kona I2C adapter"
|
||||
depends on ARCH_BCM_MOBILE
|
||||
default y
|
||||
depends on ARCH_BCM_MOBILE || COMPILE_TEST
|
||||
default y if ARCH_BCM_MOBILE
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
I2C interface on the Broadcom Kona family of processors.
|
||||
|
@ -511,7 +513,7 @@ config I2C_CPM
|
|||
|
||||
config I2C_DAVINCI
|
||||
tristate "DaVinci I2C driver"
|
||||
depends on ARCH_DAVINCI || ARCH_KEYSTONE
|
||||
depends on ARCH_DAVINCI || ARCH_KEYSTONE || COMPILE_TEST
|
||||
help
|
||||
Support for TI DaVinci I2C controller driver.
|
||||
|
||||
|
@ -572,7 +574,7 @@ config I2C_DESIGNWARE_BAYTRAIL
|
|||
|
||||
config I2C_DIGICOLOR
|
||||
tristate "Conexant Digicolor I2C driver"
|
||||
depends on ARCH_DIGICOLOR
|
||||
depends on ARCH_DIGICOLOR || COMPILE_TEST
|
||||
help
|
||||
Support for Conexant Digicolor SoCs (CX92755) I2C controller driver.
|
||||
|
||||
|
@ -610,11 +612,12 @@ config I2C_EMEV2
|
|||
I2C interface on the Renesas Electronics EM/EV family of processors.
|
||||
|
||||
config I2C_EXYNOS5
|
||||
tristate "Exynos5 high-speed I2C driver"
|
||||
depends on ARCH_EXYNOS && OF
|
||||
default y
|
||||
tristate "Exynos high-speed I2C driver"
|
||||
depends on OF
|
||||
depends on ARCH_EXYNOS || COMPILE_TEST
|
||||
default y if ARCH_EXYNOS
|
||||
help
|
||||
High-speed I2C controller on Exynos5 based Samsung SoCs.
|
||||
High-speed I2C controller on Exynos5 and newer Samsung SoCs.
|
||||
|
||||
config I2C_GPIO
|
||||
tristate "GPIO-based bitbanging I2C"
|
||||
|
@ -634,7 +637,7 @@ config I2C_GPIO_FAULT_INJECTOR
|
|||
|
||||
config I2C_HIGHLANDER
|
||||
tristate "Highlander FPGA SMBus interface"
|
||||
depends on SH_HIGHLANDER
|
||||
depends on SH_HIGHLANDER || COMPILE_TEST
|
||||
help
|
||||
If you say yes to this option, support will be included for
|
||||
the SMBus interface located in the FPGA on various Highlander
|
||||
|
@ -686,7 +689,7 @@ config I2C_IMX_LPI2C
|
|||
|
||||
config I2C_IOP3XX
|
||||
tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
|
||||
depends on ARCH_IOP32X || ARCH_IXP4XX
|
||||
depends on ARCH_IOP32X || ARCH_IXP4XX || COMPILE_TEST
|
||||
help
|
||||
Say Y here if you want to use the IIC bus controller on
|
||||
the Intel IOPx3xx I/O Processors or IXP4xx Network Processors.
|
||||
|
@ -726,6 +729,7 @@ config I2C_LPC2K
|
|||
config I2C_MESON
|
||||
tristate "Amlogic Meson I2C controller"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
depends on COMMON_CLK
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
I2C interface on the Amlogic Meson family of SoCs.
|
||||
|
@ -759,7 +763,7 @@ config I2C_MT7621
|
|||
|
||||
config I2C_MV64XXX
|
||||
tristate "Marvell mv64xxx I2C Controller"
|
||||
depends on MV64X60 || PLAT_ORION || ARCH_SUNXI || ARCH_MVEBU
|
||||
depends on MV64X60 || PLAT_ORION || ARCH_SUNXI || ARCH_MVEBU || COMPILE_TEST
|
||||
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.
|
||||
|
@ -770,7 +774,7 @@ config I2C_MV64XXX
|
|||
|
||||
config I2C_MXS
|
||||
tristate "Freescale i.MX28 I2C interface"
|
||||
depends on SOC_IMX28
|
||||
depends on SOC_IMX28 || COMPILE_TEST
|
||||
select STMP_DEVICE
|
||||
help
|
||||
Say Y here if you want to use the I2C bus controller on
|
||||
|
@ -799,7 +803,7 @@ config I2C_OCORES
|
|||
|
||||
config I2C_OMAP
|
||||
tristate "OMAP I2C adapter"
|
||||
depends on ARCH_OMAP || ARCH_K3
|
||||
depends on ARCH_OMAP || ARCH_K3 || COMPILE_TEST
|
||||
default y if MACH_OMAP_H3 || MACH_OMAP_OSK
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
|
@ -833,7 +837,7 @@ config I2C_PCA_PLATFORM
|
|||
|
||||
config I2C_PMCMSP
|
||||
tristate "PMC MSP I2C TWI Controller"
|
||||
depends on PMC_MSP
|
||||
depends on PMC_MSP || COMPILE_TEST
|
||||
help
|
||||
This driver supports the PMC TWI controller on MSP devices.
|
||||
|
||||
|
@ -842,7 +846,7 @@ config I2C_PMCMSP
|
|||
|
||||
config I2C_PNX
|
||||
tristate "I2C bus support for Philips PNX and NXP LPC targets"
|
||||
depends on ARCH_LPC32XX
|
||||
depends on ARCH_LPC32XX || COMPILE_TEST
|
||||
help
|
||||
This driver supports the Philips IP3204 I2C IP block master and/or
|
||||
slave controller
|
||||
|
@ -863,7 +867,7 @@ config I2C_PUV3
|
|||
|
||||
config I2C_PXA
|
||||
tristate "Intel PXA2XX I2C adapter"
|
||||
depends on ARCH_PXA || ARCH_MMP || ARCH_MVEBU || (X86_32 && PCI && OF)
|
||||
depends on ARCH_PXA || ARCH_MMP || ARCH_MVEBU || (X86_32 && PCI && OF) || COMPILE_TEST
|
||||
help
|
||||
If you have devices in the PXA I2C bus, say yes to this option.
|
||||
This driver can also be built as a module. If so, the module
|
||||
|
@ -932,11 +936,11 @@ config HAVE_S3C2410_I2C
|
|||
respective Kconfig file.
|
||||
|
||||
config I2C_S3C2410
|
||||
tristate "S3C2410 I2C Driver"
|
||||
depends on HAVE_S3C2410_I2C
|
||||
tristate "S3C/Exynos I2C Driver"
|
||||
depends on HAVE_S3C2410_I2C || COMPILE_TEST
|
||||
help
|
||||
Say Y here to include support for I2C controller in the
|
||||
Samsung SoCs.
|
||||
Samsung SoCs (S3C, S5Pv210, Exynos).
|
||||
|
||||
config I2C_SH7760
|
||||
tristate "Renesas SH7760 I2C Controller"
|
||||
|
@ -971,7 +975,7 @@ config I2C_SIMTEC
|
|||
|
||||
config I2C_SIRF
|
||||
tristate "CSR SiRFprimaII I2C interface"
|
||||
depends on ARCH_SIRF
|
||||
depends on ARCH_SIRF || COMPILE_TEST
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
CSR SiRFprimaII I2C interface.
|
||||
|
@ -981,14 +985,14 @@ config I2C_SIRF
|
|||
|
||||
config I2C_SPRD
|
||||
tristate "Spreadtrum I2C interface"
|
||||
depends on I2C=y && ARCH_SPRD
|
||||
depends on I2C=y && (ARCH_SPRD || COMPILE_TEST)
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
Spreadtrum I2C interface.
|
||||
|
||||
config I2C_ST
|
||||
tristate "STMicroelectronics SSC I2C support"
|
||||
depends on ARCH_STI
|
||||
depends on ARCH_STI || COMPILE_TEST
|
||||
help
|
||||
Enable this option to add support for STMicroelectronics SoCs
|
||||
hardware SSC (Synchronous Serial Controller) as an I2C controller.
|
||||
|
@ -1019,7 +1023,7 @@ config I2C_STM32F7
|
|||
|
||||
config I2C_STU300
|
||||
tristate "ST Microelectronics DDC I2C interface"
|
||||
depends on MACH_U300
|
||||
depends on MACH_U300 || COMPILE_TEST
|
||||
default y if MACH_U300
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
|
@ -1055,15 +1059,16 @@ config I2C_SYNQUACER
|
|||
|
||||
config I2C_TEGRA
|
||||
tristate "NVIDIA Tegra internal I2C controller"
|
||||
depends on ARCH_TEGRA
|
||||
depends on ARCH_TEGRA || (COMPILE_TEST && (ARC || ARM || ARM64 || M68K || RISCV || SUPERH || SPARC))
|
||||
# COMPILE_TEST needs architectures with readsX()/writesX() primitives
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
I2C controller embedded in NVIDIA Tegra SOCs
|
||||
|
||||
config I2C_TEGRA_BPMP
|
||||
tristate "NVIDIA Tegra BPMP I2C controller"
|
||||
depends on TEGRA_BPMP
|
||||
default y
|
||||
depends on TEGRA_BPMP || COMPILE_TEST
|
||||
default y if TEGRA_BPMP
|
||||
help
|
||||
If you say yes to this option, support will be included for the I2C
|
||||
controller embedded in NVIDIA Tegra SoCs accessed via the BPMP.
|
||||
|
@ -1101,7 +1106,7 @@ config I2C_VERSATILE
|
|||
|
||||
config I2C_WMT
|
||||
tristate "Wondermedia WM8xxx SoC I2C bus support"
|
||||
depends on ARCH_VT8500
|
||||
depends on ARCH_VT8500 || COMPILE_TEST
|
||||
help
|
||||
Say yes if you want to support the I2C bus on Wondermedia 8xxx-series
|
||||
SoCs.
|
||||
|
@ -1142,7 +1147,7 @@ config I2C_XILINX
|
|||
|
||||
config I2C_XLR
|
||||
tristate "Netlogic XLR and Sigma Designs I2C support"
|
||||
depends on CPU_XLR || ARCH_TANGO
|
||||
depends on CPU_XLR || ARCH_TANGO || COMPILE_TEST
|
||||
help
|
||||
This driver enables support for the on-chip I2C interface of
|
||||
the Netlogic XLR/XLS MIPS processors and Sigma Designs SOCs.
|
||||
|
@ -1202,46 +1207,12 @@ config I2C_PARPORT
|
|||
This supports parallel port I2C adapters such as the ones made by
|
||||
Philips or Velleman, Analog Devices evaluation boards, and more.
|
||||
Basically any adapter using the parallel port as an I2C bus with
|
||||
no extra chipset is supported by this driver, or could be.
|
||||
|
||||
This driver is a replacement for (and was inspired by) an older
|
||||
driver named i2c-philips-par. The new driver supports more devices,
|
||||
and makes it easier to add support for new devices.
|
||||
|
||||
An adapter type parameter is now mandatory. Please read the file
|
||||
Documentation/i2c/busses/i2c-parport.rst for details.
|
||||
|
||||
Another driver exists, named i2c-parport-light, which doesn't depend
|
||||
on the parport driver. This is meant for embedded systems. Don't say
|
||||
Y here if you intend to say Y or M there.
|
||||
no extra chipset is supported by this driver, or could be. Please
|
||||
read the file Documentation/i2c/busses/i2c-parport.rst for details.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-parport.
|
||||
|
||||
config I2C_PARPORT_LIGHT
|
||||
tristate "Parallel port adapter (light)"
|
||||
select I2C_ALGOBIT
|
||||
select I2C_SMBUS
|
||||
help
|
||||
This supports parallel port I2C adapters such as the ones made by
|
||||
Philips or Velleman, Analog Devices evaluation boards, and more.
|
||||
Basically any adapter using the parallel port as an I2C bus with
|
||||
no extra chipset is supported by this driver, or could be.
|
||||
|
||||
This driver is a light version of i2c-parport. It doesn't depend
|
||||
on the parport driver, and uses direct I/O access instead. This
|
||||
might be preferred on embedded systems where wasting memory for
|
||||
the clean but heavy parport handling is not an option. The
|
||||
drawback is a reduced portability and the impossibility to
|
||||
daisy-chain other parallel port devices.
|
||||
|
||||
Don't say Y here if you said Y or M to i2c-parport. Saying M to
|
||||
both is possible but both modules should not be loaded at the same
|
||||
time.
|
||||
|
||||
This support is also available as a module. If so, the module
|
||||
will be called i2c-parport-light.
|
||||
|
||||
config I2C_ROBOTFUZZ_OSIF
|
||||
tristate "RobotFuzz Open Source InterFace USB adapter"
|
||||
depends on USB
|
||||
|
@ -1328,7 +1299,7 @@ config I2C_ICY
|
|||
|
||||
config I2C_MLXCPLD
|
||||
tristate "Mellanox I2C driver"
|
||||
depends on X86_64
|
||||
depends on X86_64 || COMPILE_TEST
|
||||
help
|
||||
This exposes the Mellanox platform I2C busses to the linux I2C layer
|
||||
for X86 based systems.
|
||||
|
|
|
@ -128,7 +128,6 @@ obj-$(CONFIG_I2C_ZX2967) += i2c-zx2967.o
|
|||
obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
|
||||
obj-$(CONFIG_I2C_DLN2) += i2c-dln2.o
|
||||
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
|
||||
obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
|
||||
obj-$(CONFIG_I2C_ROBOTFUZZ_OSIF) += i2c-robotfuzz-osif.o
|
||||
obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o
|
||||
obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o
|
||||
|
|
|
@ -66,55 +66,26 @@ static struct at91_twi_pdata at91rm9200_config = {
|
|||
.clk_max_div = 5,
|
||||
.clk_offset = 3,
|
||||
.has_unre_flag = true,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
.has_dig_filtr = false,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata at91sam9261_config = {
|
||||
.clk_max_div = 5,
|
||||
.clk_offset = 4,
|
||||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
.has_dig_filtr = false,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata at91sam9260_config = {
|
||||
.clk_max_div = 7,
|
||||
.clk_offset = 4,
|
||||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
.has_dig_filtr = false,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata at91sam9g20_config = {
|
||||
.clk_max_div = 7,
|
||||
.clk_offset = 4,
|
||||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
.has_dig_filtr = false,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata at91sam9g10_config = {
|
||||
.clk_max_div = 7,
|
||||
.clk_offset = 4,
|
||||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
.has_dig_filtr = false,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static const struct platform_device_id at91_twi_devtypes[] = {
|
||||
|
@ -142,23 +113,13 @@ static const struct platform_device_id at91_twi_devtypes[] = {
|
|||
static struct at91_twi_pdata at91sam9x5_config = {
|
||||
.clk_max_div = 7,
|
||||
.clk_offset = 4,
|
||||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = false,
|
||||
.has_dig_filtr = false,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata sama5d4_config = {
|
||||
.clk_max_div = 7,
|
||||
.clk_offset = 4,
|
||||
.has_unre_flag = false,
|
||||
.has_alt_cmd = false,
|
||||
.has_hold_field = true,
|
||||
.has_dig_filtr = true,
|
||||
.has_adv_dig_filtr = false,
|
||||
.has_ana_filtr = false,
|
||||
};
|
||||
|
||||
static struct at91_twi_pdata sama5d2_config = {
|
||||
|
|
|
@ -208,6 +208,7 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
|
|||
|
||||
isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
|
||||
cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
|
||||
id->err_status = 0;
|
||||
|
||||
/* Handling nack and arbitration lost interrupt */
|
||||
if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) {
|
||||
|
@ -241,10 +242,17 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
|
|||
!id->bus_hold_flag)
|
||||
cdns_i2c_clear_bus_hold(id);
|
||||
|
||||
*(id->p_recv_buf)++ =
|
||||
cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
|
||||
id->recv_count--;
|
||||
id->curr_recv_count--;
|
||||
if (id->recv_count > 0) {
|
||||
*(id->p_recv_buf)++ =
|
||||
cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
|
||||
id->recv_count--;
|
||||
id->curr_recv_count--;
|
||||
} else {
|
||||
dev_err(id->adap.dev.parent,
|
||||
"xfer_size reg rollover. xfer aborted!\n");
|
||||
id->err_status |= CDNS_I2C_IXR_TO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cdns_is_holdquirk(id, hold_quirk))
|
||||
break;
|
||||
|
@ -342,7 +350,7 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
|
|||
}
|
||||
|
||||
/* Update the status for errors */
|
||||
id->err_status = isr_status & CDNS_I2C_IXR_ERR_INTR_MASK;
|
||||
id->err_status |= isr_status & CDNS_I2C_IXR_ERR_INTR_MASK;
|
||||
if (id->err_status)
|
||||
status = IRQ_HANDLED;
|
||||
|
||||
|
@ -500,7 +508,7 @@ static void cdns_i2c_master_reset(struct i2c_adapter *adap)
|
|||
cdns_i2c_writereg(regval, CDNS_I2C_CR_OFFSET);
|
||||
/* Update the transfercount register to zero */
|
||||
cdns_i2c_writereg(0, CDNS_I2C_XFER_SIZE_OFFSET);
|
||||
/* Clear the interupt status register */
|
||||
/* Clear the interrupt status register */
|
||||
regval = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
|
||||
cdns_i2c_writereg(regval, CDNS_I2C_ISR_OFFSET);
|
||||
/* Clear the status register */
|
||||
|
@ -921,17 +929,18 @@ static int cdns_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
id->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(id->clk)) {
|
||||
dev_err(&pdev->dev, "input clock not found.\n");
|
||||
if (PTR_ERR(id->clk) != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "input clock not found.\n");
|
||||
return PTR_ERR(id->clk);
|
||||
}
|
||||
ret = clk_prepare_enable(id->clk);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "Unable to enable clock.\n");
|
||||
|
||||
pm_runtime_enable(id->dev);
|
||||
pm_runtime_set_autosuspend_delay(id->dev, CNDS_I2C_PM_TIMEOUT);
|
||||
pm_runtime_use_autosuspend(id->dev);
|
||||
pm_runtime_set_active(id->dev);
|
||||
pm_runtime_enable(id->dev);
|
||||
|
||||
id->clk_rate_change_nb.notifier_call = cdns_i2c_clk_notifier_cb;
|
||||
if (clk_notifier_register(id->clk, &id->clk_rate_change_nb))
|
||||
|
@ -980,8 +989,8 @@ static int cdns_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
err_clk_dis:
|
||||
clk_disable_unprepare(id->clk);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -997,10 +1006,13 @@ static int cdns_i2c_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct cdns_i2c *id = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
|
||||
i2c_del_adapter(&id->adap);
|
||||
clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
|
||||
clk_disable_unprepare(id->clk);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -388,9 +388,9 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
|
|||
*/
|
||||
if (acpi_dev_present("INT33FE", NULL, -1)) {
|
||||
board_info.irq = adap->client_irq;
|
||||
adap->client = i2c_new_device(&adap->adapter, &board_info);
|
||||
if (!adap->client) {
|
||||
ret = -ENOMEM;
|
||||
adap->client = i2c_new_client_device(&adap->adapter, &board_info);
|
||||
if (IS_ERR(adap->client)) {
|
||||
ret = PTR_ERR(adap->client);
|
||||
goto del_adapter;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -273,6 +273,7 @@ static int ec_i2c_probe(struct platform_device *pdev)
|
|||
bus->adap.dev.parent = &pdev->dev;
|
||||
bus->adap.dev.of_node = pdev->dev.of_node;
|
||||
bus->adap.retries = I2C_MAX_RETRIES;
|
||||
ACPI_COMPANION_SET(&bus->adap.dev, ACPI_COMPANION(&pdev->dev));
|
||||
|
||||
err = i2c_add_adapter(&bus->adap);
|
||||
if (err)
|
||||
|
@ -298,7 +299,7 @@ static const struct of_device_id cros_ec_i2c_of_match[] = {
|
|||
MODULE_DEVICE_TABLE(of, cros_ec_i2c_of_match);
|
||||
|
||||
static const struct acpi_device_id cros_ec_i2c_tunnel_acpi_id[] = {
|
||||
{ "GOOG001A", 0 },
|
||||
{ "GOOG0012", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, cros_ec_i2c_tunnel_acpi_id);
|
||||
|
|
|
@ -322,7 +322,7 @@ static int highlander_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr,
|
|||
tmp |= (SMMR_MODE0 | SMMR_MODE1);
|
||||
break;
|
||||
default:
|
||||
dev_err(dev->dev, "unsupported xfer size %d\n", dev->buf_len);
|
||||
dev_err(dev->dev, "unsupported xfer size %zu\n", dev->buf_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
* Elkhart Lake (PCH) 0x4b23 32 hard yes yes yes
|
||||
* Tiger Lake-LP (PCH) 0xa0a3 32 hard yes yes yes
|
||||
* Jasper Lake (SOC) 0x4da3 32 hard yes yes yes
|
||||
* Comet Lake-V (PCH) 0xa3a3 32 hard yes yes yes
|
||||
*
|
||||
* Features supported by this driver:
|
||||
* Software PEC no
|
||||
|
@ -244,6 +245,7 @@
|
|||
#define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS 0xa223
|
||||
#define PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS 0xa2a3
|
||||
#define PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS 0xa323
|
||||
#define PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS 0xa3a3
|
||||
|
||||
struct i801_mux_config {
|
||||
char *gpio_chip;
|
||||
|
@ -1074,6 +1076,7 @@ static const struct pci_device_id i801_ids[] = {
|
|||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS) },
|
||||
|
@ -1142,7 +1145,7 @@ static void dmi_check_onboard_device(u8 type, const char *name,
|
|||
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||
info.addr = dmi_devices[i].i2c_addr;
|
||||
strlcpy(info.type, dmi_devices[i].i2c_type, I2C_NAME_SIZE);
|
||||
i2c_new_device(adap, &info);
|
||||
i2c_new_client_device(adap, &info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1296,7 +1299,7 @@ static void register_dell_lis3lv02d_i2c_device(struct i801_priv *priv)
|
|||
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||
info.addr = dell_lis3lv02d_devices[i].i2c_addr;
|
||||
strlcpy(info.type, "lis3lv02d", I2C_NAME_SIZE);
|
||||
i2c_new_device(&priv->adapter, &info);
|
||||
i2c_new_client_device(&priv->adapter, &info);
|
||||
}
|
||||
|
||||
/* Register optional slaves */
|
||||
|
@ -1312,7 +1315,7 @@ static void i801_probe_optional_slaves(struct i801_priv *priv)
|
|||
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||
info.addr = apanel_addr;
|
||||
strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
|
||||
i2c_new_device(&priv->adapter, &info);
|
||||
i2c_new_client_device(&priv->adapter, &info);
|
||||
}
|
||||
|
||||
if (dmi_name_in_vendors("FUJITSU"))
|
||||
|
@ -1742,6 +1745,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||
case PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_DNV_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS:
|
||||
case PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS:
|
||||
priv->features |= FEATURE_BLOCK_PROC;
|
||||
priv->features |= FEATURE_I2C_BLOCK_READ;
|
||||
priv->features |= FEATURE_IRQ;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*
|
||||
* Copyright (C) 2006 - 2009 Ingenic Semiconductor Inc.
|
||||
* Copyright (C) 2015 Imagination Technologies
|
||||
* Copyright (C) 2019 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
|
@ -17,6 +18,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -55,6 +57,7 @@
|
|||
#define JZ4780_I2C_ACKGC 0x98
|
||||
#define JZ4780_I2C_ENSTA 0x9C
|
||||
#define JZ4780_I2C_SDAHD 0xD0
|
||||
#define X1000_I2C_SDAHD 0x7C
|
||||
|
||||
#define JZ4780_I2C_CTRL_STPHLD BIT(7)
|
||||
#define JZ4780_I2C_CTRL_SLVDIS BIT(6)
|
||||
|
@ -73,6 +76,8 @@
|
|||
#define JZ4780_I2C_STA_TFNF BIT(1)
|
||||
#define JZ4780_I2C_STA_ACT BIT(0)
|
||||
|
||||
#define X1000_I2C_DC_STOP BIT(9)
|
||||
|
||||
static const char * const jz4780_i2c_abrt_src[] = {
|
||||
"ABRT_7B_ADDR_NOACK",
|
||||
"ABRT_10ADDR1_NOACK",
|
||||
|
@ -130,18 +135,33 @@ static const char * const jz4780_i2c_abrt_src[] = {
|
|||
#define JZ4780_I2CFLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1))
|
||||
|
||||
#define JZ4780_I2C_FIFO_LEN 16
|
||||
#define TX_LEVEL 3
|
||||
#define RX_LEVEL (JZ4780_I2C_FIFO_LEN - TX_LEVEL - 1)
|
||||
|
||||
#define X1000_I2C_FIFO_LEN 64
|
||||
|
||||
#define JZ4780_I2C_TIMEOUT 300
|
||||
|
||||
#define BUFSIZE 200
|
||||
|
||||
enum ingenic_i2c_version {
|
||||
ID_JZ4780,
|
||||
ID_X1000,
|
||||
};
|
||||
|
||||
/* ingenic_i2c_config: SoC specific config data. */
|
||||
struct ingenic_i2c_config {
|
||||
enum ingenic_i2c_version version;
|
||||
|
||||
int fifosize;
|
||||
int tx_level;
|
||||
int rx_level;
|
||||
};
|
||||
|
||||
struct jz4780_i2c {
|
||||
void __iomem *iomem;
|
||||
int irq;
|
||||
struct clk *clk;
|
||||
struct i2c_adapter adap;
|
||||
const struct ingenic_i2c_config *cdata;
|
||||
|
||||
/* lock to protect rbuf and wbuf between xfer_rd/wr and irq handler */
|
||||
spinlock_t lock;
|
||||
|
@ -340,11 +360,18 @@ static int jz4780_i2c_set_speed(struct jz4780_i2c *i2c)
|
|||
|
||||
if (hold_time >= 0) {
|
||||
/*i2c hold time enable */
|
||||
hold_time |= JZ4780_I2C_SDAHD_HDENB;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, hold_time);
|
||||
if (i2c->cdata->version >= ID_X1000) {
|
||||
jz4780_i2c_writew(i2c, X1000_I2C_SDAHD, hold_time);
|
||||
} else {
|
||||
hold_time |= JZ4780_I2C_SDAHD_HDENB;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, hold_time);
|
||||
}
|
||||
} else {
|
||||
/* disable hold time */
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, 0);
|
||||
if (i2c->cdata->version >= ID_X1000)
|
||||
jz4780_i2c_writew(i2c, X1000_I2C_SDAHD, 0);
|
||||
else
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -359,9 +386,11 @@ static int jz4780_i2c_cleanup(struct jz4780_i2c *i2c)
|
|||
spin_lock_irqsave(&i2c->lock, flags);
|
||||
|
||||
/* can send stop now if need */
|
||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||
if (i2c->cdata->version < ID_X1000) {
|
||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||
}
|
||||
|
||||
/* disable all interrupts first */
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0);
|
||||
|
@ -399,11 +428,19 @@ static int jz4780_i2c_prepare(struct jz4780_i2c *i2c)
|
|||
return jz4780_i2c_enable(i2c);
|
||||
}
|
||||
|
||||
static void jz4780_i2c_send_rcmd(struct jz4780_i2c *i2c, int cmd_count)
|
||||
static void jz4780_i2c_send_rcmd(struct jz4780_i2c *i2c,
|
||||
int cmd_count,
|
||||
int cmd_left)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cmd_count; i++)
|
||||
for (i = 0; i < cmd_count - 1; i++)
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_DC, JZ4780_I2C_DC_READ);
|
||||
|
||||
if ((cmd_left == 0) && (i2c->cdata->version >= ID_X1000))
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_DC,
|
||||
JZ4780_I2C_DC_READ | X1000_I2C_DC_STOP);
|
||||
else
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_DC, JZ4780_I2C_DC_READ);
|
||||
}
|
||||
|
||||
|
@ -458,37 +495,44 @@ static irqreturn_t jz4780_i2c_irq(int irqno, void *dev_id)
|
|||
|
||||
rd_left = i2c->rd_total_len - i2c->rd_data_xfered;
|
||||
|
||||
if (rd_left <= JZ4780_I2C_FIFO_LEN)
|
||||
if (rd_left <= i2c->cdata->fifosize)
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, rd_left - 1);
|
||||
}
|
||||
|
||||
if (intst & JZ4780_I2C_INTST_TXEMP) {
|
||||
if (i2c->is_write == 0) {
|
||||
int cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered;
|
||||
int max_send = (JZ4780_I2C_FIFO_LEN - 1)
|
||||
int max_send = (i2c->cdata->fifosize - 1)
|
||||
- (i2c->rd_cmd_xfered
|
||||
- i2c->rd_data_xfered);
|
||||
int cmd_to_send = min(cmd_left, max_send);
|
||||
|
||||
if (i2c->rd_cmd_xfered != 0)
|
||||
cmd_to_send = min(cmd_to_send,
|
||||
JZ4780_I2C_FIFO_LEN
|
||||
- TX_LEVEL - 1);
|
||||
i2c->cdata->fifosize
|
||||
- i2c->cdata->tx_level - 1);
|
||||
|
||||
if (cmd_to_send) {
|
||||
jz4780_i2c_send_rcmd(i2c, cmd_to_send);
|
||||
i2c->rd_cmd_xfered += cmd_to_send;
|
||||
cmd_left = i2c->rd_total_len -
|
||||
i2c->rd_cmd_xfered;
|
||||
jz4780_i2c_send_rcmd(i2c,
|
||||
cmd_to_send, cmd_left);
|
||||
|
||||
}
|
||||
|
||||
cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered;
|
||||
if (cmd_left == 0) {
|
||||
intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM);
|
||||
intmsk &= ~JZ4780_I2C_INTM_MTXEMP;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, intmsk);
|
||||
|
||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||
if (i2c->cdata->version < ID_X1000) {
|
||||
tmp = jz4780_i2c_readw(i2c,
|
||||
JZ4780_I2C_CTRL);
|
||||
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c,
|
||||
JZ4780_I2C_CTRL, tmp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unsigned short data;
|
||||
|
@ -497,23 +541,26 @@ static irqreturn_t jz4780_i2c_irq(int irqno, void *dev_id)
|
|||
i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
|
||||
|
||||
while ((i2c_sta & JZ4780_I2C_STA_TFNF) &&
|
||||
(i2c->wt_len > 0)) {
|
||||
(i2c->wt_len > 0)) {
|
||||
i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
|
||||
data = *i2c->wbuf;
|
||||
data &= ~JZ4780_I2C_DC_READ;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_DC,
|
||||
data);
|
||||
if ((!i2c->stop_hold) && (i2c->cdata->version >=
|
||||
ID_X1000))
|
||||
data |= X1000_I2C_DC_STOP;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_DC, data);
|
||||
i2c->wbuf++;
|
||||
i2c->wt_len--;
|
||||
}
|
||||
|
||||
if (i2c->wt_len == 0) {
|
||||
if (!i2c->stop_hold) {
|
||||
if ((!i2c->stop_hold) && (i2c->cdata->version <
|
||||
ID_X1000)) {
|
||||
tmp = jz4780_i2c_readw(i2c,
|
||||
JZ4780_I2C_CTRL);
|
||||
JZ4780_I2C_CTRL);
|
||||
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL,
|
||||
tmp);
|
||||
jz4780_i2c_writew(i2c,
|
||||
JZ4780_I2C_CTRL, tmp);
|
||||
}
|
||||
|
||||
jz4780_i2c_trans_done(i2c);
|
||||
|
@ -567,20 +614,22 @@ static inline int jz4780_i2c_xfer_read(struct jz4780_i2c *i2c,
|
|||
i2c->rd_data_xfered = 0;
|
||||
i2c->rd_cmd_xfered = 0;
|
||||
|
||||
if (len <= JZ4780_I2C_FIFO_LEN)
|
||||
if (len <= i2c->cdata->fifosize)
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, len - 1);
|
||||
else
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, RX_LEVEL);
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, i2c->cdata->rx_level);
|
||||
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, TX_LEVEL);
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, i2c->cdata->tx_level);
|
||||
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM,
|
||||
JZ4780_I2C_INTM_MRXFL | JZ4780_I2C_INTM_MTXEMP
|
||||
| JZ4780_I2C_INTM_MTXABT | JZ4780_I2C_INTM_MRXOF);
|
||||
|
||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||
tmp |= JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||
if (i2c->cdata->version < ID_X1000) {
|
||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||
tmp |= JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&i2c->lock, flags);
|
||||
|
||||
|
@ -626,14 +675,16 @@ static inline int jz4780_i2c_xfer_write(struct jz4780_i2c *i2c,
|
|||
i2c->wbuf = buf;
|
||||
i2c->wt_len = len;
|
||||
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, TX_LEVEL);
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, i2c->cdata->tx_level);
|
||||
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, JZ4780_I2C_INTM_MTXEMP
|
||||
| JZ4780_I2C_INTM_MTXABT);
|
||||
|
||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||
tmp |= JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||
if (i2c->cdata->version < ID_X1000) {
|
||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||
tmp |= JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&i2c->lock, flags);
|
||||
|
||||
|
@ -716,8 +767,25 @@ static const struct i2c_algorithm jz4780_i2c_algorithm = {
|
|||
.functionality = jz4780_i2c_functionality,
|
||||
};
|
||||
|
||||
static const struct ingenic_i2c_config jz4780_i2c_config = {
|
||||
.version = ID_JZ4780,
|
||||
|
||||
.fifosize = JZ4780_I2C_FIFO_LEN,
|
||||
.tx_level = JZ4780_I2C_FIFO_LEN / 2,
|
||||
.rx_level = JZ4780_I2C_FIFO_LEN / 2 - 1,
|
||||
};
|
||||
|
||||
static const struct ingenic_i2c_config x1000_i2c_config = {
|
||||
.version = ID_X1000,
|
||||
|
||||
.fifosize = X1000_I2C_FIFO_LEN,
|
||||
.tx_level = X1000_I2C_FIFO_LEN / 2,
|
||||
.rx_level = X1000_I2C_FIFO_LEN / 2 - 1,
|
||||
};
|
||||
|
||||
static const struct of_device_id jz4780_i2c_of_matches[] = {
|
||||
{ .compatible = "ingenic,jz4780-i2c", },
|
||||
{ .compatible = "ingenic,jz4780-i2c", .data = &jz4780_i2c_config },
|
||||
{ .compatible = "ingenic,x1000-i2c", .data = &x1000_i2c_config },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, jz4780_i2c_of_matches);
|
||||
|
@ -734,6 +802,12 @@ static int jz4780_i2c_probe(struct platform_device *pdev)
|
|||
if (!i2c)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c->cdata = device_get_match_data(&pdev->dev);
|
||||
if (!i2c->cdata) {
|
||||
dev_err(&pdev->dev, "Error: No device match found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
i2c->adap.owner = THIS_MODULE;
|
||||
i2c->adap.algo = &jz4780_i2c_algorithm;
|
||||
i2c->adap.algo_data = i2c;
|
||||
|
@ -777,9 +851,11 @@ static int jz4780_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
dev_info(&pdev->dev, "Bus frequency is %d KHz\n", i2c->speed);
|
||||
|
||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||
if (i2c->cdata->version < ID_X1000) {
|
||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||
}
|
||||
|
||||
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0x0);
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
|
@ -213,6 +214,30 @@ static void meson_i2c_prepare_xfer(struct meson_i2c *i2c)
|
|||
writel(i2c->tokens[1], i2c->regs + REG_TOK_LIST1);
|
||||
}
|
||||
|
||||
static void meson_i2c_transfer_complete(struct meson_i2c *i2c, u32 ctrl)
|
||||
{
|
||||
if (ctrl & REG_CTRL_ERROR) {
|
||||
/*
|
||||
* The bit is set when the IGNORE_NAK bit is cleared
|
||||
* and the device didn't respond. In this case, the
|
||||
* I2C controller automatically generates a STOP
|
||||
* condition.
|
||||
*/
|
||||
dev_dbg(i2c->dev, "error bit set\n");
|
||||
i2c->error = -ENXIO;
|
||||
i2c->state = STATE_IDLE;
|
||||
} else {
|
||||
if (i2c->state == STATE_READ && i2c->count)
|
||||
meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos,
|
||||
i2c->count);
|
||||
|
||||
i2c->pos += i2c->count;
|
||||
|
||||
if (i2c->pos >= i2c->msg->len)
|
||||
i2c->state = STATE_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t meson_i2c_irq(int irqno, void *dev_id)
|
||||
{
|
||||
struct meson_i2c *i2c = dev_id;
|
||||
|
@ -232,27 +257,9 @@ static irqreturn_t meson_i2c_irq(int irqno, void *dev_id)
|
|||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (ctrl & REG_CTRL_ERROR) {
|
||||
/*
|
||||
* The bit is set when the IGNORE_NAK bit is cleared
|
||||
* and the device didn't respond. In this case, the
|
||||
* I2C controller automatically generates a STOP
|
||||
* condition.
|
||||
*/
|
||||
dev_dbg(i2c->dev, "error bit set\n");
|
||||
i2c->error = -ENXIO;
|
||||
i2c->state = STATE_IDLE;
|
||||
complete(&i2c->done);
|
||||
goto out;
|
||||
}
|
||||
meson_i2c_transfer_complete(i2c, ctrl);
|
||||
|
||||
if (i2c->state == STATE_READ && i2c->count)
|
||||
meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos, i2c->count);
|
||||
|
||||
i2c->pos += i2c->count;
|
||||
|
||||
if (i2c->pos >= i2c->msg->len) {
|
||||
i2c->state = STATE_IDLE;
|
||||
if (i2c->state == STATE_IDLE) {
|
||||
complete(&i2c->done);
|
||||
goto out;
|
||||
}
|
||||
|
@ -279,10 +286,11 @@ static void meson_i2c_do_start(struct meson_i2c *i2c, struct i2c_msg *msg)
|
|||
}
|
||||
|
||||
static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg,
|
||||
int last)
|
||||
int last, bool atomic)
|
||||
{
|
||||
unsigned long time_left, flags;
|
||||
int ret = 0;
|
||||
u32 ctrl;
|
||||
|
||||
i2c->msg = msg;
|
||||
i2c->last = last;
|
||||
|
@ -300,13 +308,24 @@ static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg,
|
|||
|
||||
i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
|
||||
meson_i2c_prepare_xfer(i2c);
|
||||
reinit_completion(&i2c->done);
|
||||
|
||||
if (!atomic)
|
||||
reinit_completion(&i2c->done);
|
||||
|
||||
/* Start the transfer */
|
||||
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, REG_CTRL_START);
|
||||
|
||||
time_left = msecs_to_jiffies(I2C_TIMEOUT_MS);
|
||||
time_left = wait_for_completion_timeout(&i2c->done, time_left);
|
||||
if (atomic) {
|
||||
ret = readl_poll_timeout_atomic(i2c->regs + REG_CTRL, ctrl,
|
||||
!(ctrl & REG_CTRL_STATUS),
|
||||
10, I2C_TIMEOUT_MS * 1000);
|
||||
} else {
|
||||
time_left = msecs_to_jiffies(I2C_TIMEOUT_MS);
|
||||
time_left = wait_for_completion_timeout(&i2c->done, time_left);
|
||||
|
||||
if (!time_left)
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Protect access to i2c struct and registers from interrupt
|
||||
|
@ -315,13 +334,14 @@ static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg,
|
|||
*/
|
||||
spin_lock_irqsave(&i2c->lock, flags);
|
||||
|
||||
if (atomic && !ret)
|
||||
meson_i2c_transfer_complete(i2c, ctrl);
|
||||
|
||||
/* Abort any active operation */
|
||||
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0);
|
||||
|
||||
if (!time_left) {
|
||||
if (ret)
|
||||
i2c->state = STATE_IDLE;
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (i2c->error)
|
||||
ret = i2c->error;
|
||||
|
@ -331,8 +351,8 @@ static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
int num)
|
||||
static int meson_i2c_xfer_messages(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msgs, int num, bool atomic)
|
||||
{
|
||||
struct meson_i2c *i2c = adap->algo_data;
|
||||
int i, ret = 0;
|
||||
|
@ -340,7 +360,7 @@ static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
|||
clk_enable(i2c->clk);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
ret = meson_i2c_xfer_msg(i2c, msgs + i, i == num - 1);
|
||||
ret = meson_i2c_xfer_msg(i2c, msgs + i, i == num - 1, atomic);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
@ -350,14 +370,27 @@ static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
|||
return ret ?: i;
|
||||
}
|
||||
|
||||
static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
return meson_i2c_xfer_messages(adap, msgs, num, false);
|
||||
}
|
||||
|
||||
static int meson_i2c_xfer_atomic(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
return meson_i2c_xfer_messages(adap, msgs, num, true);
|
||||
}
|
||||
|
||||
static u32 meson_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm meson_i2c_algorithm = {
|
||||
.master_xfer = meson_i2c_xfer,
|
||||
.functionality = meson_i2c_func,
|
||||
.master_xfer = meson_i2c_xfer,
|
||||
.master_xfer_atomic = meson_i2c_xfer_atomic,
|
||||
.functionality = meson_i2c_func,
|
||||
};
|
||||
|
||||
static int meson_i2c_probe(struct platform_device *pdev)
|
||||
|
|
|
@ -280,9 +280,9 @@ static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq)
|
|||
i2cd->gpu_ccgx_ucsi->addr = 0x8;
|
||||
i2cd->gpu_ccgx_ucsi->irq = irq;
|
||||
i2cd->gpu_ccgx_ucsi->properties = ccgx_props;
|
||||
i2cd->ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
|
||||
if (!i2cd->ccgx_client)
|
||||
return -ENODEV;
|
||||
i2cd->ccgx_client = i2c_new_client_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
|
||||
if (IS_ERR(i2cd->ccgx_client))
|
||||
return PTR_ERR(i2cd->ccgx_client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -731,7 +731,7 @@ static int ocores_i2c_probe(struct platform_device *pdev)
|
|||
/* add in known devices to the bus */
|
||||
if (pdata) {
|
||||
for (i = 0; i < pdata->num_devices; i++)
|
||||
i2c_new_device(&i2c->adap, pdata->devices + i);
|
||||
i2c_new_client_device(&i2c->adap, pdata->devices + i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -1,267 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* ------------------------------------------------------------------------ *
|
||||
* i2c-parport-light.c I2C bus over parallel port *
|
||||
* ------------------------------------------------------------------------ *
|
||||
Copyright (C) 2003-2010 Jean Delvare <jdelvare@suse.de>
|
||||
|
||||
Based on older i2c-velleman.c driver
|
||||
Copyright (C) 1995-2000 Simon G. Vogl
|
||||
With some changes from:
|
||||
Frodo Looijaard <frodol@dds.nl>
|
||||
Kyösti Mälkki <kmalkki@cc.hut.fi>
|
||||
|
||||
* ------------------------------------------------------------------------ */
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
#include <linux/i2c-smbus.h>
|
||||
#include <linux/io.h>
|
||||
#include "i2c-parport.h"
|
||||
|
||||
#define DEFAULT_BASE 0x378
|
||||
#define DRVNAME "i2c-parport-light"
|
||||
|
||||
static struct platform_device *pdev;
|
||||
|
||||
static u16 base;
|
||||
module_param_hw(base, ushort, ioport, 0);
|
||||
MODULE_PARM_DESC(base, "Base I/O address");
|
||||
|
||||
static int irq;
|
||||
module_param_hw(irq, int, irq, 0);
|
||||
MODULE_PARM_DESC(irq, "IRQ (optional)");
|
||||
|
||||
/* ----- Low-level parallel port access ----------------------------------- */
|
||||
|
||||
static inline void port_write(unsigned char p, unsigned char d)
|
||||
{
|
||||
outb(d, base+p);
|
||||
}
|
||||
|
||||
static inline unsigned char port_read(unsigned char p)
|
||||
{
|
||||
return inb(base+p);
|
||||
}
|
||||
|
||||
/* ----- Unified line operation functions --------------------------------- */
|
||||
|
||||
static inline void line_set(int state, const struct lineop *op)
|
||||
{
|
||||
u8 oldval = port_read(op->port);
|
||||
|
||||
/* Touch only the bit(s) needed */
|
||||
if ((op->inverted && !state) || (!op->inverted && state))
|
||||
port_write(op->port, oldval | op->val);
|
||||
else
|
||||
port_write(op->port, oldval & ~op->val);
|
||||
}
|
||||
|
||||
static inline int line_get(const struct lineop *op)
|
||||
{
|
||||
u8 oldval = port_read(op->port);
|
||||
|
||||
return ((op->inverted && (oldval & op->val) != op->val)
|
||||
|| (!op->inverted && (oldval & op->val) == op->val));
|
||||
}
|
||||
|
||||
/* ----- I2C algorithm call-back functions and structures ----------------- */
|
||||
|
||||
static void parport_setscl(void *data, int state)
|
||||
{
|
||||
line_set(state, &adapter_parm[type].setscl);
|
||||
}
|
||||
|
||||
static void parport_setsda(void *data, int state)
|
||||
{
|
||||
line_set(state, &adapter_parm[type].setsda);
|
||||
}
|
||||
|
||||
static int parport_getscl(void *data)
|
||||
{
|
||||
return line_get(&adapter_parm[type].getscl);
|
||||
}
|
||||
|
||||
static int parport_getsda(void *data)
|
||||
{
|
||||
return line_get(&adapter_parm[type].getsda);
|
||||
}
|
||||
|
||||
/* Encapsulate the functions above in the correct structure
|
||||
Note that getscl will be set to NULL by the attaching code for adapters
|
||||
that cannot read SCL back */
|
||||
static struct i2c_algo_bit_data parport_algo_data = {
|
||||
.setsda = parport_setsda,
|
||||
.setscl = parport_setscl,
|
||||
.getsda = parport_getsda,
|
||||
.getscl = parport_getscl,
|
||||
.udelay = 50,
|
||||
.timeout = HZ,
|
||||
};
|
||||
|
||||
/* ----- Driver registration ---------------------------------------------- */
|
||||
|
||||
static struct i2c_adapter parport_adapter = {
|
||||
.owner = THIS_MODULE,
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.algo_data = &parport_algo_data,
|
||||
.name = "Parallel port adapter (light)",
|
||||
};
|
||||
|
||||
/* SMBus alert support */
|
||||
static struct i2c_smbus_alert_setup alert_data = {
|
||||
};
|
||||
static struct i2c_client *ara;
|
||||
static struct lineop parport_ctrl_irq = {
|
||||
.val = (1 << 4),
|
||||
.port = PORT_CTRL,
|
||||
};
|
||||
|
||||
static int i2c_parport_probe(struct platform_device *pdev)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Reset hardware to a sane state (SCL and SDA high) */
|
||||
parport_setsda(NULL, 1);
|
||||
parport_setscl(NULL, 1);
|
||||
/* Other init if needed (power on...) */
|
||||
if (adapter_parm[type].init.val) {
|
||||
line_set(1, &adapter_parm[type].init);
|
||||
/* Give powered devices some time to settle */
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
parport_adapter.dev.parent = &pdev->dev;
|
||||
err = i2c_bit_add_bus(&parport_adapter);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Unable to register with I2C\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Setup SMBus alert if supported */
|
||||
if (adapter_parm[type].smbus_alert && irq) {
|
||||
alert_data.irq = irq;
|
||||
ara = i2c_setup_smbus_alert(&parport_adapter, &alert_data);
|
||||
if (ara)
|
||||
line_set(1, &parport_ctrl_irq);
|
||||
else
|
||||
dev_warn(&pdev->dev, "Failed to register ARA client\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_parport_remove(struct platform_device *pdev)
|
||||
{
|
||||
if (ara) {
|
||||
line_set(0, &parport_ctrl_irq);
|
||||
i2c_unregister_device(ara);
|
||||
ara = NULL;
|
||||
}
|
||||
i2c_del_adapter(&parport_adapter);
|
||||
|
||||
/* Un-init if needed (power off...) */
|
||||
if (adapter_parm[type].init.val)
|
||||
line_set(0, &adapter_parm[type].init);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver i2c_parport_driver = {
|
||||
.driver = {
|
||||
.name = DRVNAME,
|
||||
},
|
||||
.probe = i2c_parport_probe,
|
||||
.remove = i2c_parport_remove,
|
||||
};
|
||||
|
||||
static int __init i2c_parport_device_add(u16 address)
|
||||
{
|
||||
int err;
|
||||
|
||||
pdev = platform_device_alloc(DRVNAME, -1);
|
||||
if (!pdev) {
|
||||
err = -ENOMEM;
|
||||
printk(KERN_ERR DRVNAME ": Device allocation failed\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = platform_device_add(pdev);
|
||||
if (err) {
|
||||
printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
|
||||
err);
|
||||
goto exit_device_put;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_device_put:
|
||||
platform_device_put(pdev);
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __init i2c_parport_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (type < 0) {
|
||||
printk(KERN_ERR DRVNAME ": adapter type unspecified\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (type >= ARRAY_SIZE(adapter_parm)) {
|
||||
printk(KERN_ERR DRVNAME ": invalid type (%d)\n", type);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (base == 0) {
|
||||
pr_info(DRVNAME ": using default base 0x%x\n", DEFAULT_BASE);
|
||||
base = DEFAULT_BASE;
|
||||
}
|
||||
|
||||
if (!request_region(base, 3, DRVNAME))
|
||||
return -EBUSY;
|
||||
|
||||
if (irq != 0)
|
||||
pr_info(DRVNAME ": using irq %d\n", irq);
|
||||
|
||||
if (!adapter_parm[type].getscl.val)
|
||||
parport_algo_data.getscl = NULL;
|
||||
|
||||
/* Sets global pdev as a side effect */
|
||||
err = i2c_parport_device_add(base);
|
||||
if (err)
|
||||
goto exit_release;
|
||||
|
||||
err = platform_driver_register(&i2c_parport_driver);
|
||||
if (err)
|
||||
goto exit_device;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_device:
|
||||
platform_device_unregister(pdev);
|
||||
exit_release:
|
||||
release_region(base, 3);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit i2c_parport_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&i2c_parport_driver);
|
||||
platform_device_unregister(pdev);
|
||||
release_region(base, 3);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
|
||||
MODULE_DESCRIPTION("I2C bus over parallel port (light)");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(i2c_parport_init);
|
||||
module_exit(i2c_parport_exit);
|
|
@ -25,7 +25,90 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include "i2c-parport.h"
|
||||
|
||||
#define PORT_DATA 0
|
||||
#define PORT_STAT 1
|
||||
#define PORT_CTRL 2
|
||||
|
||||
struct lineop {
|
||||
u8 val;
|
||||
u8 port;
|
||||
u8 inverted;
|
||||
};
|
||||
|
||||
struct adapter_parm {
|
||||
struct lineop setsda;
|
||||
struct lineop setscl;
|
||||
struct lineop getsda;
|
||||
struct lineop getscl;
|
||||
struct lineop init;
|
||||
unsigned int smbus_alert:1;
|
||||
};
|
||||
|
||||
static const struct adapter_parm adapter_parm[] = {
|
||||
/* type 0: Philips adapter */
|
||||
{
|
||||
.setsda = { 0x80, PORT_DATA, 1 },
|
||||
.setscl = { 0x08, PORT_CTRL, 0 },
|
||||
.getsda = { 0x80, PORT_STAT, 0 },
|
||||
.getscl = { 0x08, PORT_STAT, 0 },
|
||||
},
|
||||
/* type 1: home brew teletext adapter */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 0 },
|
||||
.setscl = { 0x01, PORT_DATA, 0 },
|
||||
.getsda = { 0x80, PORT_STAT, 1 },
|
||||
},
|
||||
/* type 2: Velleman K8000 adapter */
|
||||
{
|
||||
.setsda = { 0x02, PORT_CTRL, 1 },
|
||||
.setscl = { 0x08, PORT_CTRL, 1 },
|
||||
.getsda = { 0x10, PORT_STAT, 0 },
|
||||
},
|
||||
/* type 3: ELV adapter */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x40, PORT_STAT, 1 },
|
||||
.getscl = { 0x08, PORT_STAT, 1 },
|
||||
},
|
||||
/* type 4: ADM1032 evaluation board */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x10, PORT_STAT, 1 },
|
||||
.init = { 0xf0, PORT_DATA, 0 },
|
||||
.smbus_alert = 1,
|
||||
},
|
||||
/* type 5: ADM1025, ADM1030 and ADM1031 evaluation boards */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x10, PORT_STAT, 1 },
|
||||
},
|
||||
/* type 6: Barco LPT->DVI (K5800236) adapter */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x20, PORT_STAT, 0 },
|
||||
.getscl = { 0x40, PORT_STAT, 0 },
|
||||
.init = { 0xfc, PORT_DATA, 0 },
|
||||
},
|
||||
/* type 7: One For All JP1 parallel port adapter */
|
||||
{
|
||||
.setsda = { 0x01, PORT_DATA, 0 },
|
||||
.setscl = { 0x02, PORT_DATA, 0 },
|
||||
.getsda = { 0x80, PORT_STAT, 1 },
|
||||
.init = { 0x04, PORT_DATA, 1 },
|
||||
},
|
||||
/* type 8: VCT-jig */
|
||||
{
|
||||
.setsda = { 0x04, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x40, PORT_STAT, 0 },
|
||||
.getscl = { 0x80, PORT_STAT, 1 },
|
||||
},
|
||||
};
|
||||
|
||||
/* ----- Device list ------------------------------------------------------ */
|
||||
|
||||
|
@ -40,9 +123,30 @@ struct i2c_par {
|
|||
|
||||
static LIST_HEAD(adapter_list);
|
||||
static DEFINE_MUTEX(adapter_list_lock);
|
||||
|
||||
#define MAX_DEVICE 4
|
||||
static int parport[MAX_DEVICE] = {0, -1, -1, -1};
|
||||
module_param_array(parport, int, NULL, 0);
|
||||
MODULE_PARM_DESC(parport,
|
||||
"List of parallel ports to bind to, by index.\n"
|
||||
" At most " __stringify(MAX_DEVICE) " devices are supported.\n"
|
||||
" Default is one device connected to parport0.\n"
|
||||
);
|
||||
|
||||
static int type = -1;
|
||||
module_param(type, int, 0);
|
||||
MODULE_PARM_DESC(type,
|
||||
"Type of adapter:\n"
|
||||
" 0 = Philips adapter\n"
|
||||
" 1 = home brew teletext adapter\n"
|
||||
" 2 = Velleman K8000 adapter\n"
|
||||
" 3 = ELV adapter\n"
|
||||
" 4 = ADM1032 evaluation board\n"
|
||||
" 5 = ADM1025, ADM1030 and ADM1031 evaluation boards\n"
|
||||
" 6 = Barco LPT->DVI (K5800236) adapter\n"
|
||||
" 7 = One For All JP1 parallel port adapter\n"
|
||||
" 8 = VCT-jig\n"
|
||||
);
|
||||
|
||||
/* ----- Low-level parallel port access ----------------------------------- */
|
||||
|
||||
|
@ -311,12 +415,5 @@ MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
|
|||
MODULE_DESCRIPTION("I2C bus over parallel port");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_param_array(parport, int, NULL, 0);
|
||||
MODULE_PARM_DESC(parport,
|
||||
"List of parallel ports to bind to, by index.\n"
|
||||
" Atmost " __stringify(MAX_DEVICE) " devices are supported.\n"
|
||||
" Default is one device connected to parport0.\n"
|
||||
);
|
||||
|
||||
module_init(i2c_parport_init);
|
||||
module_exit(i2c_parport_exit);
|
||||
|
|
|
@ -1,106 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* ------------------------------------------------------------------------ *
|
||||
* i2c-parport.h I2C bus over parallel port *
|
||||
* ------------------------------------------------------------------------ *
|
||||
Copyright (C) 2003-2010 Jean Delvare <jdelvare@suse.de>
|
||||
|
||||
* ------------------------------------------------------------------------ */
|
||||
|
||||
#define PORT_DATA 0
|
||||
#define PORT_STAT 1
|
||||
#define PORT_CTRL 2
|
||||
|
||||
struct lineop {
|
||||
u8 val;
|
||||
u8 port;
|
||||
u8 inverted;
|
||||
};
|
||||
|
||||
struct adapter_parm {
|
||||
struct lineop setsda;
|
||||
struct lineop setscl;
|
||||
struct lineop getsda;
|
||||
struct lineop getscl;
|
||||
struct lineop init;
|
||||
unsigned int smbus_alert:1;
|
||||
};
|
||||
|
||||
static const struct adapter_parm adapter_parm[] = {
|
||||
/* type 0: Philips adapter */
|
||||
{
|
||||
.setsda = { 0x80, PORT_DATA, 1 },
|
||||
.setscl = { 0x08, PORT_CTRL, 0 },
|
||||
.getsda = { 0x80, PORT_STAT, 0 },
|
||||
.getscl = { 0x08, PORT_STAT, 0 },
|
||||
},
|
||||
/* type 1: home brew teletext adapter */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 0 },
|
||||
.setscl = { 0x01, PORT_DATA, 0 },
|
||||
.getsda = { 0x80, PORT_STAT, 1 },
|
||||
},
|
||||
/* type 2: Velleman K8000 adapter */
|
||||
{
|
||||
.setsda = { 0x02, PORT_CTRL, 1 },
|
||||
.setscl = { 0x08, PORT_CTRL, 1 },
|
||||
.getsda = { 0x10, PORT_STAT, 0 },
|
||||
},
|
||||
/* type 3: ELV adapter */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x40, PORT_STAT, 1 },
|
||||
.getscl = { 0x08, PORT_STAT, 1 },
|
||||
},
|
||||
/* type 4: ADM1032 evaluation board */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x10, PORT_STAT, 1 },
|
||||
.init = { 0xf0, PORT_DATA, 0 },
|
||||
.smbus_alert = 1,
|
||||
},
|
||||
/* type 5: ADM1025, ADM1030 and ADM1031 evaluation boards */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x10, PORT_STAT, 1 },
|
||||
},
|
||||
/* type 6: Barco LPT->DVI (K5800236) adapter */
|
||||
{
|
||||
.setsda = { 0x02, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x20, PORT_STAT, 0 },
|
||||
.getscl = { 0x40, PORT_STAT, 0 },
|
||||
.init = { 0xfc, PORT_DATA, 0 },
|
||||
},
|
||||
/* type 7: One For All JP1 parallel port adapter */
|
||||
{
|
||||
.setsda = { 0x01, PORT_DATA, 0 },
|
||||
.setscl = { 0x02, PORT_DATA, 0 },
|
||||
.getsda = { 0x80, PORT_STAT, 1 },
|
||||
.init = { 0x04, PORT_DATA, 1 },
|
||||
},
|
||||
/* type 8: VCT-jig */
|
||||
{
|
||||
.setsda = { 0x04, PORT_DATA, 1 },
|
||||
.setscl = { 0x01, PORT_DATA, 1 },
|
||||
.getsda = { 0x40, PORT_STAT, 0 },
|
||||
.getscl = { 0x80, PORT_STAT, 1 },
|
||||
},
|
||||
};
|
||||
|
||||
static int type = -1;
|
||||
module_param(type, int, 0);
|
||||
MODULE_PARM_DESC(type,
|
||||
"Type of adapter:\n"
|
||||
" 0 = Philips adapter\n"
|
||||
" 1 = home brew teletext adapter\n"
|
||||
" 2 = Velleman K8000 adapter\n"
|
||||
" 3 = ELV adapter\n"
|
||||
" 4 = ADM1032 evaluation board\n"
|
||||
" 5 = ADM1025, ADM1030 and ADM1031 evaluation boards\n"
|
||||
" 6 = Barco LPT->DVI (K5800236) adapter\n"
|
||||
" 7 = One For All JP1 parallel port adapter\n"
|
||||
" 8 = VCT-jig\n"
|
||||
);
|
|
@ -274,8 +274,8 @@ static int pmcmsptwi_probe(struct platform_device *pldev)
|
|||
if (!request_mem_region(res->start, resource_size(res),
|
||||
pldev->name)) {
|
||||
dev_err(&pldev->dev,
|
||||
"Unable to get memory/io address region 0x%08x\n",
|
||||
res->start);
|
||||
"Unable to get memory/io address region %pap\n",
|
||||
&res->start);
|
||||
rc = -EBUSY;
|
||||
goto ret_err;
|
||||
}
|
||||
|
@ -285,7 +285,7 @@ static int pmcmsptwi_probe(struct platform_device *pldev)
|
|||
resource_size(res));
|
||||
if (!pmcmsptwi_data.iobase) {
|
||||
dev_err(&pldev->dev,
|
||||
"Unable to ioremap address 0x%08x\n", res->start);
|
||||
"Unable to ioremap address %pap\n", &res->start);
|
||||
rc = -EIO;
|
||||
goto ret_unreserve;
|
||||
}
|
||||
|
|
|
@ -734,8 +734,8 @@ static int i2c_pnx_probe(struct platform_device *pdev)
|
|||
if (ret < 0)
|
||||
goto out_clock;
|
||||
|
||||
dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n",
|
||||
alg_data->adapter.name, res->start, alg_data->irq);
|
||||
dev_dbg(&pdev->dev, "%s: Master at %pap, irq %d.\n",
|
||||
alg_data->adapter.name, &res->start, alg_data->irq);
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -240,8 +240,8 @@ static void i2c_powermac_create_one(struct i2c_adapter *adap,
|
|||
|
||||
strncpy(info.type, type, sizeof(info.type));
|
||||
info.addr = addr;
|
||||
newdev = i2c_new_device(adap, &info);
|
||||
if (!newdev)
|
||||
newdev = i2c_new_client_device(adap, &info);
|
||||
if (IS_ERR(newdev))
|
||||
dev_err(&adap->dev,
|
||||
"i2c-powermac: Failure to register missing %s\n",
|
||||
type);
|
||||
|
@ -359,8 +359,8 @@ static void i2c_powermac_register_devices(struct i2c_adapter *adap,
|
|||
info.irq = irq_of_parse_and_map(node, 0);
|
||||
info.of_node = of_node_get(node);
|
||||
|
||||
newdev = i2c_new_device(adap, &info);
|
||||
if (!newdev) {
|
||||
newdev = i2c_new_client_device(adap, &info);
|
||||
if (IS_ERR(newdev)) {
|
||||
dev_err(&adap->dev, "i2c-powermac: Failure to register"
|
||||
" %pOF\n", node);
|
||||
of_node_put(node);
|
||||
|
|
|
@ -168,6 +168,24 @@
|
|||
|
||||
#define STM32F7_AUTOSUSPEND_DELAY (HZ / 100)
|
||||
|
||||
/**
|
||||
* struct stm32f7_i2c_regs - i2c f7 registers backup
|
||||
* @cr1: Control register 1
|
||||
* @cr2: Control register 2
|
||||
* @oar1: Own address 1 register
|
||||
* @oar2: Own address 2 register
|
||||
* @pecr: PEC register
|
||||
* @tmgr: Timing register
|
||||
*/
|
||||
struct stm32f7_i2c_regs {
|
||||
u32 cr1;
|
||||
u32 cr2;
|
||||
u32 oar1;
|
||||
u32 oar2;
|
||||
u32 pecr;
|
||||
u32 tmgr;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct stm32f7_i2c_spec - private i2c specification timing
|
||||
* @rate: I2C bus speed (Hz)
|
||||
|
@ -276,6 +294,7 @@ struct stm32f7_i2c_msg {
|
|||
* @timing: I2C computed timings
|
||||
* @slave: list of slave devices registered on the I2C bus
|
||||
* @slave_running: slave device currently used
|
||||
* @backup_regs: backup of i2c controller registers (for suspend/resume)
|
||||
* @slave_dir: transfer direction for the current slave device
|
||||
* @master_mode: boolean to know in which mode the I2C is running (master or
|
||||
* slave)
|
||||
|
@ -298,6 +317,7 @@ struct stm32f7_i2c_dev {
|
|||
struct stm32f7_i2c_timings timing;
|
||||
struct i2c_client *slave[STM32F7_I2C_MAX_SLAVE];
|
||||
struct i2c_client *slave_running;
|
||||
struct stm32f7_i2c_regs backup_regs;
|
||||
u32 slave_dir;
|
||||
bool master_mode;
|
||||
struct stm32_i2c_dma *dma;
|
||||
|
@ -2027,8 +2047,7 @@ static int stm32f7_i2c_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int stm32f7_i2c_runtime_suspend(struct device *dev)
|
||||
static int __maybe_unused stm32f7_i2c_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
|
||||
|
@ -2038,7 +2057,7 @@ static int stm32f7_i2c_runtime_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int stm32f7_i2c_runtime_resume(struct device *dev)
|
||||
static int __maybe_unused stm32f7_i2c_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
@ -2053,11 +2072,101 @@ static int stm32f7_i2c_runtime_resume(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __maybe_unused
|
||||
stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev)
|
||||
{
|
||||
int ret;
|
||||
struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs;
|
||||
|
||||
ret = pm_runtime_get_sync(i2c_dev->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
backup_regs->cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1);
|
||||
backup_regs->cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2);
|
||||
backup_regs->oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1);
|
||||
backup_regs->oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2);
|
||||
backup_regs->pecr = readl_relaxed(i2c_dev->base + STM32F7_I2C_PECR);
|
||||
backup_regs->tmgr = readl_relaxed(i2c_dev->base + STM32F7_I2C_TIMINGR);
|
||||
|
||||
pm_runtime_put_sync(i2c_dev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused
|
||||
stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev)
|
||||
{
|
||||
u32 cr1;
|
||||
int ret;
|
||||
struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs;
|
||||
|
||||
ret = pm_runtime_get_sync(i2c_dev->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1);
|
||||
if (cr1 & STM32F7_I2C_CR1_PE)
|
||||
stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
|
||||
STM32F7_I2C_CR1_PE);
|
||||
|
||||
writel_relaxed(backup_regs->tmgr, i2c_dev->base + STM32F7_I2C_TIMINGR);
|
||||
writel_relaxed(backup_regs->cr1 & ~STM32F7_I2C_CR1_PE,
|
||||
i2c_dev->base + STM32F7_I2C_CR1);
|
||||
if (backup_regs->cr1 & STM32F7_I2C_CR1_PE)
|
||||
stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
|
||||
STM32F7_I2C_CR1_PE);
|
||||
writel_relaxed(backup_regs->cr2, i2c_dev->base + STM32F7_I2C_CR2);
|
||||
writel_relaxed(backup_regs->oar1, i2c_dev->base + STM32F7_I2C_OAR1);
|
||||
writel_relaxed(backup_regs->oar2, i2c_dev->base + STM32F7_I2C_OAR2);
|
||||
writel_relaxed(backup_regs->pecr, i2c_dev->base + STM32F7_I2C_PECR);
|
||||
|
||||
pm_runtime_put_sync(i2c_dev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused stm32f7_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
i2c_mark_adapter_suspended(&i2c_dev->adap);
|
||||
ret = stm32f7_i2c_regs_backup(i2c_dev);
|
||||
if (ret < 0) {
|
||||
i2c_mark_adapter_resumed(&i2c_dev->adap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pinctrl_pm_select_sleep_state(dev);
|
||||
pm_runtime_force_suspend(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused stm32f7_i2c_resume(struct device *dev)
|
||||
{
|
||||
struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_force_resume(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
pinctrl_pm_select_default_state(dev);
|
||||
|
||||
ret = stm32f7_i2c_regs_restore(i2c_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
i2c_mark_adapter_resumed(&i2c_dev->adap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops stm32f7_i2c_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(stm32f7_i2c_runtime_suspend,
|
||||
stm32f7_i2c_runtime_resume, NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(stm32f7_i2c_suspend, stm32f7_i2c_resume)
|
||||
};
|
||||
|
||||
static const struct of_device_id stm32f7_i2c_match[] = {
|
||||
|
|
|
@ -444,7 +444,7 @@ static int stu300_wait_while_busy(struct stu300_dev *dev)
|
|||
"Attempt: %d\n", i+1);
|
||||
|
||||
dev_err(&dev->pdev->dev, "base address = "
|
||||
"0x%08x, reinit hardware\n", (u32) dev->virtbase);
|
||||
"0x%p, reinit hardware\n", dev->virtbase);
|
||||
|
||||
(void) stu300_init_hw(dev);
|
||||
}
|
||||
|
|
|
@ -49,10 +49,10 @@ static struct i2c_client *taos_instantiate_device(struct i2c_adapter *adapter)
|
|||
if (!strncmp(adapter->name, "TAOS TSL2550 EVM", 16)) {
|
||||
dev_info(&adapter->dev, "Instantiating device %s at 0x%02x\n",
|
||||
tsl2550_info.type, tsl2550_info.addr);
|
||||
return i2c_new_device(adapter, &tsl2550_info);
|
||||
return i2c_new_client_device(adapter, &tsl2550_info);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
|
@ -129,11 +131,12 @@
|
|||
#define I2C_PACKET_HEADER_SIZE 12
|
||||
|
||||
/*
|
||||
* Upto I2C_PIO_MODE_MAX_LEN bytes, controller will use PIO mode,
|
||||
* above this, controller will use DMA to fill FIFO.
|
||||
* MAX PIO len is 20 bytes excluding packet header.
|
||||
* I2C Controller will use PIO mode for transfers up to 32 bytes in order to
|
||||
* avoid DMA overhead, otherwise external APB DMA controller will be used.
|
||||
* Note that the actual MAX PIO length is 20 bytes because 32 bytes include
|
||||
* I2C_PACKET_HEADER_SIZE.
|
||||
*/
|
||||
#define I2C_PIO_MODE_MAX_LEN 32
|
||||
#define I2C_PIO_MODE_PREFERRED_LEN 32
|
||||
|
||||
/*
|
||||
* msg_end_type: The bus control which need to be send at end of transfer.
|
||||
|
@ -230,7 +233,6 @@ struct tegra_i2c_hw_feature {
|
|||
* @base_phys: physical base address of the I2C controller
|
||||
* @cont_id: I2C controller ID, used for packet header
|
||||
* @irq: IRQ number of transfer complete interrupt
|
||||
* @irq_disabled: used to track whether or not the interrupt is enabled
|
||||
* @is_dvc: identifies the DVC I2C controller, has a different register layout
|
||||
* @msg_complete: transfer completion notifier
|
||||
* @msg_err: error code for completed message
|
||||
|
@ -240,7 +242,6 @@ struct tegra_i2c_hw_feature {
|
|||
* @bus_clk_rate: current I2C bus clock rate
|
||||
* @clk_divisor_non_hs_mode: clock divider for non-high-speed modes
|
||||
* @is_multimaster_mode: track if I2C controller is in multi-master mode
|
||||
* @xfer_lock: lock to serialize transfer submission and processing
|
||||
* @tx_dma_chan: DMA transmit channel
|
||||
* @rx_dma_chan: DMA receive channel
|
||||
* @dma_phys: handle to DMA resources
|
||||
|
@ -248,6 +249,7 @@ struct tegra_i2c_hw_feature {
|
|||
* @dma_buf_size: DMA buffer size
|
||||
* @is_curr_dma_xfer: indicates active DMA transfer
|
||||
* @dma_complete: DMA completion notifier
|
||||
* @is_curr_atomic_xfer: indicates active atomic transfer
|
||||
*/
|
||||
struct tegra_i2c_dev {
|
||||
struct device *dev;
|
||||
|
@ -260,7 +262,6 @@ struct tegra_i2c_dev {
|
|||
phys_addr_t base_phys;
|
||||
int cont_id;
|
||||
int irq;
|
||||
bool irq_disabled;
|
||||
int is_dvc;
|
||||
struct completion msg_complete;
|
||||
int msg_err;
|
||||
|
@ -270,8 +271,6 @@ struct tegra_i2c_dev {
|
|||
u32 bus_clk_rate;
|
||||
u16 clk_divisor_non_hs_mode;
|
||||
bool is_multimaster_mode;
|
||||
/* xfer_lock: lock to serialize transfer submission and processing */
|
||||
spinlock_t xfer_lock;
|
||||
struct dma_chan *tx_dma_chan;
|
||||
struct dma_chan *rx_dma_chan;
|
||||
dma_addr_t dma_phys;
|
||||
|
@ -279,17 +278,18 @@ struct tegra_i2c_dev {
|
|||
unsigned int dma_buf_size;
|
||||
bool is_curr_dma_xfer;
|
||||
struct completion dma_complete;
|
||||
bool is_curr_atomic_xfer;
|
||||
};
|
||||
|
||||
static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
|
||||
unsigned long reg)
|
||||
{
|
||||
writel(val, i2c_dev->base + reg);
|
||||
writel_relaxed(val, i2c_dev->base + reg);
|
||||
}
|
||||
|
||||
static u32 dvc_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
|
||||
{
|
||||
return readl(i2c_dev->base + reg);
|
||||
return readl_relaxed(i2c_dev->base + reg);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -307,16 +307,16 @@ static unsigned long tegra_i2c_reg_addr(struct tegra_i2c_dev *i2c_dev,
|
|||
static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
|
||||
unsigned long reg)
|
||||
{
|
||||
writel(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
|
||||
writel_relaxed(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
|
||||
|
||||
/* Read back register to make sure that register writes completed */
|
||||
if (reg != I2C_TX_FIFO)
|
||||
readl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
|
||||
readl_relaxed(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
|
||||
}
|
||||
|
||||
static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
|
||||
{
|
||||
return readl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
|
||||
return readl_relaxed(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
|
||||
}
|
||||
|
||||
static void i2c_writesl(struct tegra_i2c_dev *i2c_dev, void *data,
|
||||
|
@ -687,13 +687,15 @@ static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev)
|
|||
reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_CONFIG_LOAD);
|
||||
addr = i2c_dev->base + reg_offset;
|
||||
i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD);
|
||||
if (in_interrupt())
|
||||
err = readl_poll_timeout_atomic(addr, val, val == 0,
|
||||
1000,
|
||||
I2C_CONFIG_LOAD_TIMEOUT);
|
||||
|
||||
if (i2c_dev->is_curr_atomic_xfer)
|
||||
err = readl_relaxed_poll_timeout_atomic(
|
||||
addr, val, val == 0, 1000,
|
||||
I2C_CONFIG_LOAD_TIMEOUT);
|
||||
else
|
||||
err = readl_poll_timeout(addr, val, val == 0, 1000,
|
||||
I2C_CONFIG_LOAD_TIMEOUT);
|
||||
err = readl_relaxed_poll_timeout(
|
||||
addr, val, val == 0, 1000,
|
||||
I2C_CONFIG_LOAD_TIMEOUT);
|
||||
|
||||
if (err) {
|
||||
dev_warn(i2c_dev->dev,
|
||||
|
@ -790,11 +792,6 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev, bool clk_reinit)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (i2c_dev->irq_disabled) {
|
||||
i2c_dev->irq_disabled = false;
|
||||
enable_irq(i2c_dev->irq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -825,18 +822,12 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
|
|||
|
||||
status = i2c_readl(i2c_dev, I2C_INT_STATUS);
|
||||
|
||||
spin_lock(&i2c_dev->xfer_lock);
|
||||
if (status == 0) {
|
||||
dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
|
||||
i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
|
||||
i2c_readl(i2c_dev, I2C_STATUS),
|
||||
i2c_readl(i2c_dev, I2C_CNFG));
|
||||
i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT;
|
||||
|
||||
if (!i2c_dev->irq_disabled) {
|
||||
disable_irq_nosync(i2c_dev->irq);
|
||||
i2c_dev->irq_disabled = true;
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
@ -925,7 +916,6 @@ err:
|
|||
|
||||
complete(&i2c_dev->msg_complete);
|
||||
done:
|
||||
spin_unlock(&i2c_dev->xfer_lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -999,6 +989,64 @@ out:
|
|||
i2c_writel(i2c_dev, val, reg);
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
tegra_i2c_poll_completion_timeout(struct tegra_i2c_dev *i2c_dev,
|
||||
struct completion *complete,
|
||||
unsigned int timeout_ms)
|
||||
{
|
||||
ktime_t ktime = ktime_get();
|
||||
ktime_t ktimeout = ktime_add_ms(ktime, timeout_ms);
|
||||
|
||||
do {
|
||||
u32 status = i2c_readl(i2c_dev, I2C_INT_STATUS);
|
||||
|
||||
if (status) {
|
||||
tegra_i2c_isr(i2c_dev->irq, i2c_dev);
|
||||
|
||||
if (completion_done(complete)) {
|
||||
s64 delta = ktime_ms_delta(ktimeout, ktime);
|
||||
|
||||
return msecs_to_jiffies(delta) ?: 1;
|
||||
}
|
||||
}
|
||||
|
||||
ktime = ktime_get();
|
||||
|
||||
} while (ktime_before(ktime, ktimeout));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
tegra_i2c_wait_completion_timeout(struct tegra_i2c_dev *i2c_dev,
|
||||
struct completion *complete,
|
||||
unsigned int timeout_ms)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
if (i2c_dev->is_curr_atomic_xfer) {
|
||||
ret = tegra_i2c_poll_completion_timeout(i2c_dev, complete,
|
||||
timeout_ms);
|
||||
} else {
|
||||
enable_irq(i2c_dev->irq);
|
||||
ret = wait_for_completion_timeout(complete,
|
||||
msecs_to_jiffies(timeout_ms));
|
||||
disable_irq(i2c_dev->irq);
|
||||
|
||||
/*
|
||||
* There is a chance that completion may happen after IRQ
|
||||
* synchronization, which is done by disable_irq().
|
||||
*/
|
||||
if (ret == 0 && completion_done(complete)) {
|
||||
dev_warn(i2c_dev->dev,
|
||||
"completion done after timeout\n");
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
|
||||
|
@ -1020,8 +1068,8 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
|
|||
i2c_writel(i2c_dev, reg, I2C_BUS_CLEAR_CNFG);
|
||||
tegra_i2c_unmask_irq(i2c_dev, I2C_INT_BUS_CLR_DONE);
|
||||
|
||||
time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
|
||||
msecs_to_jiffies(50));
|
||||
time_left = tegra_i2c_wait_completion_timeout(
|
||||
i2c_dev, &i2c_dev->msg_complete, 50);
|
||||
if (time_left == 0) {
|
||||
dev_err(i2c_dev->dev, "timed out for bus clear\n");
|
||||
return -ETIMEDOUT;
|
||||
|
@ -1044,7 +1092,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
|||
u32 packet_header;
|
||||
u32 int_mask;
|
||||
unsigned long time_left;
|
||||
unsigned long flags;
|
||||
size_t xfer_size;
|
||||
u32 *buffer = NULL;
|
||||
int err = 0;
|
||||
|
@ -1065,8 +1112,9 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
|||
xfer_size = msg->len + I2C_PACKET_HEADER_SIZE;
|
||||
|
||||
xfer_size = ALIGN(xfer_size, BYTES_PER_FIFO_WORD);
|
||||
i2c_dev->is_curr_dma_xfer = (xfer_size > I2C_PIO_MODE_MAX_LEN) &&
|
||||
i2c_dev->dma_buf;
|
||||
i2c_dev->is_curr_dma_xfer = (xfer_size > I2C_PIO_MODE_PREFERRED_LEN) &&
|
||||
i2c_dev->dma_buf &&
|
||||
!i2c_dev->is_curr_atomic_xfer;
|
||||
tegra_i2c_config_fifo_trig(i2c_dev, xfer_size);
|
||||
dma = i2c_dev->is_curr_dma_xfer;
|
||||
/*
|
||||
|
@ -1075,7 +1123,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
|||
*/
|
||||
xfer_time += DIV_ROUND_CLOSEST(((xfer_size * 9) + 2) * MSEC_PER_SEC,
|
||||
i2c_dev->bus_clk_rate);
|
||||
spin_lock_irqsave(&i2c_dev->xfer_lock, flags);
|
||||
|
||||
int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
|
||||
tegra_i2c_unmask_irq(i2c_dev, int_mask);
|
||||
|
@ -1090,7 +1137,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
|||
dev_err(i2c_dev->dev,
|
||||
"starting RX DMA failed, err %d\n",
|
||||
err);
|
||||
goto unlock;
|
||||
return err;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -1149,7 +1196,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
|||
dev_err(i2c_dev->dev,
|
||||
"starting TX DMA failed, err %d\n",
|
||||
err);
|
||||
goto unlock;
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
tegra_i2c_fill_tx_fifo(i2c_dev);
|
||||
|
@ -1169,20 +1216,16 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
|||
dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n",
|
||||
i2c_readl(i2c_dev, I2C_INT_MASK));
|
||||
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags);
|
||||
|
||||
if (dma) {
|
||||
if (err)
|
||||
return err;
|
||||
time_left = tegra_i2c_wait_completion_timeout(
|
||||
i2c_dev, &i2c_dev->dma_complete, xfer_time);
|
||||
|
||||
time_left = wait_for_completion_timeout(&i2c_dev->dma_complete,
|
||||
msecs_to_jiffies(xfer_time));
|
||||
if (time_left == 0) {
|
||||
dmaengine_terminate_sync(i2c_dev->msg_read ?
|
||||
i2c_dev->rx_dma_chan :
|
||||
i2c_dev->tx_dma_chan);
|
||||
|
||||
if (!time_left && !completion_done(&i2c_dev->dma_complete)) {
|
||||
dev_err(i2c_dev->dev, "DMA transfer timeout\n");
|
||||
dmaengine_terminate_sync(i2c_dev->msg_read ?
|
||||
i2c_dev->rx_dma_chan :
|
||||
i2c_dev->tx_dma_chan);
|
||||
tegra_i2c_init(i2c_dev, true);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
@ -1195,20 +1238,15 @@ unlock:
|
|||
memcpy(i2c_dev->msg_buf, i2c_dev->dma_buf,
|
||||
msg->len);
|
||||
}
|
||||
|
||||
if (i2c_dev->msg_err != I2C_ERR_NONE)
|
||||
dmaengine_synchronize(i2c_dev->msg_read ?
|
||||
i2c_dev->rx_dma_chan :
|
||||
i2c_dev->tx_dma_chan);
|
||||
}
|
||||
|
||||
time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
|
||||
msecs_to_jiffies(xfer_time));
|
||||
time_left = tegra_i2c_wait_completion_timeout(
|
||||
i2c_dev, &i2c_dev->msg_complete, xfer_time);
|
||||
|
||||
tegra_i2c_mask_irq(i2c_dev, int_mask);
|
||||
|
||||
if (time_left == 0) {
|
||||
dev_err(i2c_dev->dev, "i2c transfer timed out\n");
|
||||
|
||||
tegra_i2c_init(i2c_dev, true);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
@ -1270,6 +1308,19 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
|||
return ret ?: i;
|
||||
}
|
||||
|
||||
static int tegra_i2c_xfer_atomic(struct i2c_adapter *adap,
|
||||
struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
|
||||
int ret;
|
||||
|
||||
i2c_dev->is_curr_atomic_xfer = true;
|
||||
ret = tegra_i2c_xfer(adap, msgs, num);
|
||||
i2c_dev->is_curr_atomic_xfer = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 tegra_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
|
||||
|
@ -1297,8 +1348,9 @@ static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev)
|
|||
}
|
||||
|
||||
static const struct i2c_algorithm tegra_i2c_algo = {
|
||||
.master_xfer = tegra_i2c_xfer,
|
||||
.functionality = tegra_i2c_func,
|
||||
.master_xfer = tegra_i2c_xfer,
|
||||
.master_xfer_atomic = tegra_i2c_xfer_atomic,
|
||||
.functionality = tegra_i2c_func,
|
||||
};
|
||||
|
||||
/* payload size is only 12 bit */
|
||||
|
@ -1568,7 +1620,6 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
|||
I2C_PACKET_HEADER_SIZE;
|
||||
init_completion(&i2c_dev->msg_complete);
|
||||
init_completion(&i2c_dev->dma_complete);
|
||||
spin_lock_init(&i2c_dev->xfer_lock);
|
||||
|
||||
if (!i2c_dev->hw->has_single_clk_source) {
|
||||
fast_clk = devm_clk_get(&pdev->dev, "fast-clk");
|
||||
|
@ -1607,6 +1658,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
|||
goto unprepare_fast_clk;
|
||||
}
|
||||
|
||||
pm_runtime_irq_safe(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
if (!pm_runtime_enabled(&pdev->dev)) {
|
||||
ret = tegra_i2c_runtime_resume(&pdev->dev);
|
||||
|
@ -1644,6 +1696,8 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
|||
goto release_dma;
|
||||
}
|
||||
|
||||
irq_set_status_flags(i2c_dev->irq, IRQ_NOAUTOEN);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, i2c_dev->irq,
|
||||
tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev);
|
||||
if (ret) {
|
||||
|
|
|
@ -84,7 +84,7 @@ static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
|
|||
pmsg->buf, pmsg->len) != pmsg->len) {
|
||||
dev_err(&adapter->dev,
|
||||
"failure reading data\n");
|
||||
ret = -EREMOTEIO;
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
|
@ -94,7 +94,7 @@ static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
|
|||
pmsg->buf, pmsg->len) != pmsg->len) {
|
||||
dev_err(&adapter->dev,
|
||||
"failure writing data\n");
|
||||
ret = -EREMOTEIO;
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
@ -102,13 +102,13 @@ static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
|
|||
/* read status */
|
||||
if (usb_read(adapter, CMD_GET_STATUS, 0, 0, pstatus, 1) != 1) {
|
||||
dev_err(&adapter->dev, "failure reading status\n");
|
||||
ret = -EREMOTEIO;
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev_dbg(&adapter->dev, " status = %d\n", *pstatus);
|
||||
if (*pstatus == STATUS_ADDRESS_NAK) {
|
||||
ret = -EREMOTEIO;
|
||||
ret = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,6 +156,8 @@ struct xiic_i2c {
|
|||
#define XIIC_RESET_MASK 0xAUL
|
||||
|
||||
#define XIIC_PM_TIMEOUT 1000 /* ms */
|
||||
/* timeout waiting for the controller to respond */
|
||||
#define XIIC_I2C_TIMEOUT (msecs_to_jiffies(1000))
|
||||
/*
|
||||
* The following constant is used for the device global interrupt enable
|
||||
* register, to enable all interrupts for the device, this is the only bit
|
||||
|
@ -166,7 +168,7 @@ struct xiic_i2c {
|
|||
#define xiic_tx_space(i2c) ((i2c)->tx_msg->len - (i2c)->tx_pos)
|
||||
#define xiic_rx_space(i2c) ((i2c)->rx_msg->len - (i2c)->rx_pos)
|
||||
|
||||
static void xiic_start_xfer(struct xiic_i2c *i2c);
|
||||
static int xiic_start_xfer(struct xiic_i2c *i2c);
|
||||
static void __xiic_start_xfer(struct xiic_i2c *i2c);
|
||||
|
||||
/*
|
||||
|
@ -247,17 +249,29 @@ static inline void xiic_irq_clr_en(struct xiic_i2c *i2c, u32 mask)
|
|||
xiic_irq_en(i2c, mask);
|
||||
}
|
||||
|
||||
static void xiic_clear_rx_fifo(struct xiic_i2c *i2c)
|
||||
static int xiic_clear_rx_fifo(struct xiic_i2c *i2c)
|
||||
{
|
||||
u8 sr;
|
||||
unsigned long timeout;
|
||||
|
||||
timeout = jiffies + XIIC_I2C_TIMEOUT;
|
||||
for (sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET);
|
||||
!(sr & XIIC_SR_RX_FIFO_EMPTY_MASK);
|
||||
sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET))
|
||||
sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET)) {
|
||||
xiic_getreg8(i2c, XIIC_DRR_REG_OFFSET);
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_err(i2c->dev, "Failed to clear rx fifo\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xiic_reinit(struct xiic_i2c *i2c)
|
||||
static int xiic_reinit(struct xiic_i2c *i2c)
|
||||
{
|
||||
int ret;
|
||||
|
||||
xiic_setreg32(i2c, XIIC_RESETR_OFFSET, XIIC_RESET_MASK);
|
||||
|
||||
/* Set receive Fifo depth to maximum (zero based). */
|
||||
|
@ -270,12 +284,16 @@ static void xiic_reinit(struct xiic_i2c *i2c)
|
|||
xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, XIIC_CR_ENABLE_DEVICE_MASK);
|
||||
|
||||
/* make sure RX fifo is empty */
|
||||
xiic_clear_rx_fifo(i2c);
|
||||
ret = xiic_clear_rx_fifo(i2c);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable interrupts */
|
||||
xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
|
||||
|
||||
xiic_irq_clr_en(i2c, XIIC_INTR_ARB_LOST_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xiic_deinit(struct xiic_i2c *i2c)
|
||||
|
@ -655,12 +673,18 @@ static void __xiic_start_xfer(struct xiic_i2c *i2c)
|
|||
|
||||
}
|
||||
|
||||
static void xiic_start_xfer(struct xiic_i2c *i2c)
|
||||
static int xiic_start_xfer(struct xiic_i2c *i2c)
|
||||
{
|
||||
int ret;
|
||||
mutex_lock(&i2c->lock);
|
||||
xiic_reinit(i2c);
|
||||
__xiic_start_xfer(i2c);
|
||||
|
||||
ret = xiic_reinit(i2c);
|
||||
if (!ret)
|
||||
__xiic_start_xfer(i2c);
|
||||
|
||||
mutex_unlock(&i2c->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
|
@ -682,7 +706,11 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
|||
i2c->tx_msg = msgs;
|
||||
i2c->nmsgs = num;
|
||||
|
||||
xiic_start_xfer(i2c);
|
||||
err = xiic_start_xfer(i2c);
|
||||
if (err < 0) {
|
||||
dev_err(adap->dev.parent, "Error xiic_start_xfer\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
|
||||
(i2c->state == STATE_DONE), HZ)) {
|
||||
|
@ -760,7 +788,8 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
i2c->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(i2c->clk)) {
|
||||
dev_err(&pdev->dev, "input clock not found.\n");
|
||||
if (PTR_ERR(i2c->clk) != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "input clock not found.\n");
|
||||
return PTR_ERR(i2c->clk);
|
||||
}
|
||||
ret = clk_prepare_enable(i2c->clk);
|
||||
|
@ -769,10 +798,10 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
i2c->dev = &pdev->dev;
|
||||
pm_runtime_enable(i2c->dev);
|
||||
pm_runtime_set_autosuspend_delay(i2c->dev, XIIC_PM_TIMEOUT);
|
||||
pm_runtime_use_autosuspend(i2c->dev);
|
||||
pm_runtime_set_active(i2c->dev);
|
||||
pm_runtime_enable(i2c->dev);
|
||||
ret = devm_request_threaded_irq(&pdev->dev, irq, xiic_isr,
|
||||
xiic_process, IRQF_ONESHOT,
|
||||
pdev->name, i2c);
|
||||
|
@ -794,7 +823,11 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
|||
if (!(sr & XIIC_SR_TX_FIFO_EMPTY_MASK))
|
||||
i2c->endianness = BIG;
|
||||
|
||||
xiic_reinit(i2c);
|
||||
ret = xiic_reinit(i2c);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Cannot xiic_reinit\n");
|
||||
goto err_clk_dis;
|
||||
}
|
||||
|
||||
/* add i2c adapter to i2c tree */
|
||||
ret = i2c_add_adapter(&i2c->adap);
|
||||
|
@ -806,7 +839,7 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
|||
if (pdata) {
|
||||
/* add in known devices to the bus */
|
||||
for (i = 0; i < pdata->num_devices; i++)
|
||||
i2c_new_device(&i2c->adap, pdata->devices + i);
|
||||
i2c_new_client_device(&i2c->adap, pdata->devices + i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -826,14 +859,16 @@ static int xiic_i2c_remove(struct platform_device *pdev)
|
|||
/* remove adapter & data */
|
||||
i2c_del_adapter(&i2c->adap);
|
||||
|
||||
ret = clk_prepare_enable(i2c->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Unable to enable clock.\n");
|
||||
ret = pm_runtime_get_sync(i2c->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
xiic_deinit(i2c);
|
||||
pm_runtime_put_sync(i2c->dev);
|
||||
clk_disable_unprepare(i2c->clk);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -225,7 +225,7 @@ static void i2c_acpi_register_device(struct i2c_adapter *adapter,
|
|||
adev->power.flags.ignore_parent = true;
|
||||
acpi_device_set_enumerated(adev);
|
||||
|
||||
if (!i2c_new_device(adapter, info)) {
|
||||
if (IS_ERR(i2c_new_client_device(adapter, info))) {
|
||||
adev->power.flags.ignore_parent = false;
|
||||
dev_err(&adapter->dev,
|
||||
"failed to add I2C device %s from ACPI\n",
|
||||
|
@ -451,7 +451,8 @@ struct notifier_block i2c_acpi_notifier = {
|
|||
* resources, in that case this function can be used to create an i2c-client
|
||||
* for other I2cSerialBus resources in the Current Resource Settings table.
|
||||
*
|
||||
* Also see i2c_new_device, which this function calls to create the i2c-client.
|
||||
* Also see i2c_new_client_device, which this function calls to create the
|
||||
* i2c-client.
|
||||
*
|
||||
* Returns a pointer to the new i2c-client, or error pointer in case of failure.
|
||||
* Specifically, -EPROBE_DEFER is returned if the adapter is not found.
|
||||
|
@ -461,7 +462,6 @@ struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
|
|||
{
|
||||
struct i2c_acpi_lookup lookup;
|
||||
struct i2c_adapter *adapter;
|
||||
struct i2c_client *client;
|
||||
struct acpi_device *adev;
|
||||
LIST_HEAD(resource_list);
|
||||
int ret;
|
||||
|
@ -489,11 +489,7 @@ struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
|
|||
if (!adapter)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
client = i2c_new_device(adapter, info);
|
||||
if (!client)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
return client;
|
||||
return i2c_new_client_device(adapter, info);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_acpi_new_device);
|
||||
|
||||
|
|
|
@ -456,15 +456,15 @@ static void i2c_client_dev_release(struct device *dev)
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
show_name(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
name_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s\n", dev->type == &i2c_client_type ?
|
||||
to_i2c_client(dev)->name : to_i2c_adapter(dev)->name);
|
||||
}
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
||||
static DEVICE_ATTR_RO(name);
|
||||
|
||||
static ssize_t
|
||||
show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int len;
|
||||
|
@ -479,7 +479,7 @@ show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
|
||||
return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name);
|
||||
}
|
||||
static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static struct attribute *i2c_dev_attrs[] = {
|
||||
&dev_attr_name.attr,
|
||||
|
@ -831,8 +831,8 @@ EXPORT_SYMBOL_GPL(i2c_new_device);
|
|||
|
||||
|
||||
/**
|
||||
* i2c_unregister_device - reverse effect of i2c_new_device()
|
||||
* @client: value returned from i2c_new_device()
|
||||
* i2c_unregister_device - reverse effect of i2c_new_*_device()
|
||||
* @client: value returned from i2c_new_*_device()
|
||||
* Context: can sleep
|
||||
*/
|
||||
void i2c_unregister_device(struct i2c_client *client)
|
||||
|
@ -1023,8 +1023,8 @@ EXPORT_SYMBOL_GPL(i2c_adapter_depth);
|
|||
* the user to provide incorrect parameters.
|
||||
*/
|
||||
static ssize_t
|
||||
i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
new_device_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_adapter *adap = to_i2c_adapter(dev);
|
||||
struct i2c_board_info info;
|
||||
|
@ -1079,7 +1079,7 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr,
|
|||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
|
||||
static DEVICE_ATTR_WO(new_device);
|
||||
|
||||
/*
|
||||
* And of course let the users delete the devices they instantiated, if
|
||||
|
@ -1091,8 +1091,8 @@ static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
|
|||
* the user to delete the wrong device.
|
||||
*/
|
||||
static ssize_t
|
||||
i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
delete_device_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_adapter *adap = to_i2c_adapter(dev);
|
||||
struct i2c_client *client, *next;
|
||||
|
@ -1135,7 +1135,7 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr,
|
|||
return res;
|
||||
}
|
||||
static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, S_IWUSR, NULL,
|
||||
i2c_sysfs_delete_device);
|
||||
delete_device_store);
|
||||
|
||||
static struct attribute *i2c_adapter_attrs[] = {
|
||||
&dev_attr_name.attr,
|
||||
|
@ -1178,9 +1178,8 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
|
|||
|
||||
down_read(&__i2c_board_lock);
|
||||
list_for_each_entry(devinfo, &__i2c_board_list, list) {
|
||||
if (devinfo->busnum == adapter->nr
|
||||
&& !i2c_new_device(adapter,
|
||||
&devinfo->board_info))
|
||||
if (devinfo->busnum == adapter->nr &&
|
||||
IS_ERR(i2c_new_client_device(adapter, &devinfo->board_info)))
|
||||
dev_err(&adapter->dev,
|
||||
"Can't create device at 0x%02x\n",
|
||||
devinfo->board_info.addr);
|
||||
|
@ -2167,8 +2166,8 @@ static int i2c_detect_address(struct i2c_client *temp_client,
|
|||
|
||||
dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n",
|
||||
info.type, info.addr);
|
||||
client = i2c_new_device(adapter, &info);
|
||||
if (client)
|
||||
client = i2c_new_client_device(adapter, &info);
|
||||
if (!IS_ERR(client))
|
||||
list_add_tail(&client->detected, &driver->clients);
|
||||
else
|
||||
dev_err(&adapter->dev, "Failed creating %s at 0x%02x\n",
|
||||
|
|
|
@ -75,11 +75,10 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
|
|||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
client = i2c_new_device(adap, &info);
|
||||
if (!client) {
|
||||
client = i2c_new_client_device(adap, &info);
|
||||
if (IS_ERR(client))
|
||||
dev_err(&adap->dev, "of_i2c: Failure registering %pOF\n", node);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
|
@ -42,20 +43,20 @@
|
|||
#define PCA9541_CONTROL 0x01
|
||||
#define PCA9541_ISTAT 0x02
|
||||
|
||||
#define PCA9541_CTL_MYBUS (1 << 0)
|
||||
#define PCA9541_CTL_NMYBUS (1 << 1)
|
||||
#define PCA9541_CTL_BUSON (1 << 2)
|
||||
#define PCA9541_CTL_NBUSON (1 << 3)
|
||||
#define PCA9541_CTL_BUSINIT (1 << 4)
|
||||
#define PCA9541_CTL_TESTON (1 << 6)
|
||||
#define PCA9541_CTL_NTESTON (1 << 7)
|
||||
#define PCA9541_CTL_MYBUS BIT(0)
|
||||
#define PCA9541_CTL_NMYBUS BIT(1)
|
||||
#define PCA9541_CTL_BUSON BIT(2)
|
||||
#define PCA9541_CTL_NBUSON BIT(3)
|
||||
#define PCA9541_CTL_BUSINIT BIT(4)
|
||||
#define PCA9541_CTL_TESTON BIT(6)
|
||||
#define PCA9541_CTL_NTESTON BIT(7)
|
||||
|
||||
#define PCA9541_ISTAT_INTIN (1 << 0)
|
||||
#define PCA9541_ISTAT_BUSINIT (1 << 1)
|
||||
#define PCA9541_ISTAT_BUSOK (1 << 2)
|
||||
#define PCA9541_ISTAT_BUSLOST (1 << 3)
|
||||
#define PCA9541_ISTAT_MYTEST (1 << 6)
|
||||
#define PCA9541_ISTAT_NMYTEST (1 << 7)
|
||||
#define PCA9541_ISTAT_INTIN BIT(0)
|
||||
#define PCA9541_ISTAT_BUSINIT BIT(1)
|
||||
#define PCA9541_ISTAT_BUSOK BIT(2)
|
||||
#define PCA9541_ISTAT_BUSLOST BIT(3)
|
||||
#define PCA9541_ISTAT_MYTEST BIT(6)
|
||||
#define PCA9541_ISTAT_NMYTEST BIT(7)
|
||||
|
||||
#define BUSON (PCA9541_CTL_BUSON | PCA9541_CTL_NBUSON)
|
||||
#define MYBUS (PCA9541_CTL_MYBUS | PCA9541_CTL_NMYBUS)
|
||||
|
|
|
@ -86,7 +86,7 @@ struct pca954x {
|
|||
|
||||
u8 last_chan; /* last register value */
|
||||
/* MUX_IDLE_AS_IS, MUX_IDLE_DISCONNECT or >= 0 for channel */
|
||||
s8 idle_state;
|
||||
s32 idle_state;
|
||||
|
||||
struct i2c_client *client;
|
||||
|
||||
|
@ -229,20 +229,23 @@ static int pca954x_reg_write(struct i2c_adapter *adap,
|
|||
I2C_SMBUS_BYTE, &dummy);
|
||||
}
|
||||
|
||||
static u8 pca954x_regval(struct pca954x *data, u8 chan)
|
||||
{
|
||||
/* We make switches look like muxes, not sure how to be smarter. */
|
||||
if (data->chip->muxtype == pca954x_ismux)
|
||||
return chan | data->chip->enable;
|
||||
else
|
||||
return 1 << chan;
|
||||
}
|
||||
|
||||
static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
struct pca954x *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = data->client;
|
||||
const struct chip_desc *chip = data->chip;
|
||||
u8 regval;
|
||||
int ret = 0;
|
||||
|
||||
/* we make switches look like muxes, not sure how to be smarter */
|
||||
if (chip->muxtype == pca954x_ismux)
|
||||
regval = chan | chip->enable;
|
||||
else
|
||||
regval = 1 << chan;
|
||||
|
||||
regval = pca954x_regval(data, chan);
|
||||
/* Only select the channel if its different from the last channel */
|
||||
if (data->last_chan != regval) {
|
||||
ret = pca954x_reg_write(muxc->parent, client, regval);
|
||||
|
@ -256,7 +259,7 @@ static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
|
|||
{
|
||||
struct pca954x *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = data->client;
|
||||
s8 idle_state;
|
||||
s32 idle_state;
|
||||
|
||||
idle_state = READ_ONCE(data->idle_state);
|
||||
if (idle_state >= 0)
|
||||
|
@ -402,6 +405,22 @@ static void pca954x_cleanup(struct i2c_mux_core *muxc)
|
|||
i2c_mux_del_adapters(muxc);
|
||||
}
|
||||
|
||||
static int pca954x_init(struct i2c_client *client, struct pca954x *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (data->idle_state >= 0)
|
||||
data->last_chan = pca954x_regval(data, data->idle_state);
|
||||
else
|
||||
data->last_chan = 0; /* Disconnect multiplexer */
|
||||
|
||||
ret = i2c_smbus_write_byte(client, data->last_chan);
|
||||
if (ret < 0)
|
||||
data->last_chan = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* I2C init/probing/exit functions
|
||||
*/
|
||||
|
@ -411,7 +430,6 @@ static int pca954x_probe(struct i2c_client *client,
|
|||
struct i2c_adapter *adap = client->adapter;
|
||||
struct device *dev = &client->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
bool idle_disconnect_dt;
|
||||
struct gpio_desc *gpio;
|
||||
struct i2c_mux_core *muxc;
|
||||
struct pca954x *data;
|
||||
|
@ -462,23 +480,24 @@ static int pca954x_probe(struct i2c_client *client,
|
|||
}
|
||||
}
|
||||
|
||||
/* Write the mux register at addr to verify
|
||||
data->idle_state = MUX_IDLE_AS_IS;
|
||||
if (of_property_read_u32(np, "idle-state", &data->idle_state)) {
|
||||
if (np && of_property_read_bool(np, "i2c-mux-idle-disconnect"))
|
||||
data->idle_state = MUX_IDLE_DISCONNECT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the mux register at addr to verify
|
||||
* that the mux is in fact present. This also
|
||||
* initializes the mux to disconnected state.
|
||||
* initializes the mux to a channel
|
||||
* or disconnected state.
|
||||
*/
|
||||
if (i2c_smbus_write_byte(client, 0) < 0) {
|
||||
ret = pca954x_init(client, data);
|
||||
if (ret < 0) {
|
||||
dev_warn(dev, "probe failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
data->last_chan = 0; /* force the first selection */
|
||||
data->idle_state = MUX_IDLE_AS_IS;
|
||||
|
||||
idle_disconnect_dt = np &&
|
||||
of_property_read_bool(np, "i2c-mux-idle-disconnect");
|
||||
if (idle_disconnect_dt)
|
||||
data->idle_state = MUX_IDLE_DISCONNECT;
|
||||
|
||||
ret = pca954x_irq_setup(muxc);
|
||||
if (ret)
|
||||
goto fail_cleanup;
|
||||
|
@ -530,9 +549,13 @@ static int pca954x_resume(struct device *dev)
|
|||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct pca954x *data = i2c_mux_priv(muxc);
|
||||
int ret;
|
||||
|
||||
data->last_chan = 0;
|
||||
return i2c_smbus_write_byte(client, 0);
|
||||
ret = pca954x_init(client, data);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "failed to verify mux presence\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* at24.c - handle most I2C EEPROMs
|
||||
*
|
||||
|
@ -6,23 +6,23 @@
|
|||
* Copyright (C) 2008 Wolfram Sang, Pengutronix
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/nvmem-provider.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* Address pointer is 16 bit. */
|
||||
#define AT24_FLAG_ADDR16 BIT(7)
|
||||
|
@ -88,8 +88,7 @@ struct at24_data {
|
|||
u8 flags;
|
||||
|
||||
struct nvmem_device *nvmem;
|
||||
|
||||
struct gpio_desc *wp_gpio;
|
||||
struct regulator *vcc_reg;
|
||||
|
||||
/*
|
||||
* Some chips tie up multiple I2C addresses; dummy devices reserve
|
||||
|
@ -457,12 +456,10 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
|
|||
* from this host, but not from other I2C masters.
|
||||
*/
|
||||
mutex_lock(&at24->lock);
|
||||
gpiod_set_value_cansleep(at24->wp_gpio, 0);
|
||||
|
||||
while (count) {
|
||||
ret = at24_regmap_write(at24, buf, off, count);
|
||||
if (ret < 0) {
|
||||
gpiod_set_value_cansleep(at24->wp_gpio, 1);
|
||||
mutex_unlock(&at24->lock);
|
||||
pm_runtime_put(dev);
|
||||
return ret;
|
||||
|
@ -472,7 +469,6 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
|
|||
count -= ret;
|
||||
}
|
||||
|
||||
gpiod_set_value_cansleep(at24->wp_gpio, 1);
|
||||
mutex_unlock(&at24->lock);
|
||||
|
||||
pm_runtime_put(dev);
|
||||
|
@ -662,9 +658,9 @@ static int at24_probe(struct i2c_client *client)
|
|||
at24->client[0].client = client;
|
||||
at24->client[0].regmap = regmap;
|
||||
|
||||
at24->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(at24->wp_gpio))
|
||||
return PTR_ERR(at24->wp_gpio);
|
||||
at24->vcc_reg = devm_regulator_get(dev, "vcc");
|
||||
if (IS_ERR(at24->vcc_reg))
|
||||
return PTR_ERR(at24->vcc_reg);
|
||||
|
||||
writable = !(flags & AT24_FLAG_READONLY);
|
||||
if (writable) {
|
||||
|
@ -701,6 +697,12 @@ static int at24_probe(struct i2c_client *client)
|
|||
|
||||
i2c_set_clientdata(client, at24);
|
||||
|
||||
err = regulator_enable(at24->vcc_reg);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to enable vcc regulator\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* enable runtime pm */
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
@ -713,6 +715,7 @@ static int at24_probe(struct i2c_client *client)
|
|||
pm_runtime_idle(dev);
|
||||
if (err) {
|
||||
pm_runtime_disable(dev);
|
||||
regulator_disable(at24->vcc_reg);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -728,15 +731,42 @@ static int at24_probe(struct i2c_client *client)
|
|||
|
||||
static int at24_remove(struct i2c_client *client)
|
||||
{
|
||||
struct at24_data *at24 = i2c_get_clientdata(client);
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
if (!pm_runtime_status_suspended(&client->dev))
|
||||
regulator_disable(at24->vcc_reg);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused at24_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct at24_data *at24 = i2c_get_clientdata(client);
|
||||
|
||||
return regulator_disable(at24->vcc_reg);
|
||||
}
|
||||
|
||||
static int __maybe_unused at24_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct at24_data *at24 = i2c_get_clientdata(client);
|
||||
|
||||
return regulator_enable(at24->vcc_reg);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops at24_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(at24_suspend, at24_resume, NULL)
|
||||
};
|
||||
|
||||
static struct i2c_driver at24_driver = {
|
||||
.driver = {
|
||||
.name = "at24",
|
||||
.pm = &at24_pm_ops,
|
||||
.of_match_table = at24_of_match,
|
||||
.acpi_match_table = ACPI_PTR(at24_acpi_ids),
|
||||
},
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/nvmem-consumer.h>
|
||||
#include <linux/nvmem-provider.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/slab.h>
|
||||
#include "nvmem.h"
|
||||
|
@ -54,8 +55,14 @@ static int nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset,
|
|||
static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset,
|
||||
void *val, size_t bytes)
|
||||
{
|
||||
if (nvmem->reg_write)
|
||||
return nvmem->reg_write(nvmem->priv, offset, val, bytes);
|
||||
int ret;
|
||||
|
||||
if (nvmem->reg_write) {
|
||||
gpiod_set_value_cansleep(nvmem->wp_gpio, 0);
|
||||
ret = nvmem->reg_write(nvmem->priv, offset, val, bytes);
|
||||
gpiod_set_value_cansleep(nvmem->wp_gpio, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -340,6 +347,14 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
|
|||
kfree(nvmem);
|
||||
return ERR_PTR(rval);
|
||||
}
|
||||
if (config->wp_gpio)
|
||||
nvmem->wp_gpio = config->wp_gpio;
|
||||
else
|
||||
nvmem->wp_gpio = gpiod_get_optional(config->dev, "wp",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(nvmem->wp_gpio))
|
||||
return ERR_CAST(nvmem->wp_gpio);
|
||||
|
||||
|
||||
kref_init(&nvmem->refcnt);
|
||||
INIT_LIST_HEAD(&nvmem->cells);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/nvmem-consumer.h>
|
||||
#include <linux/nvmem-provider.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
struct nvmem_device {
|
||||
struct module *owner;
|
||||
|
@ -26,6 +27,7 @@ struct nvmem_device {
|
|||
struct list_head cells;
|
||||
nvmem_reg_read_t reg_read;
|
||||
nvmem_reg_write_t reg_write;
|
||||
struct gpio_desc *wp_gpio;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
|
|
|
@ -50,8 +50,8 @@ struct property_entry;
|
|||
* transmit an arbitrary number of messages without interruption.
|
||||
* @count must be be less than 64k since msg.len is u16.
|
||||
*/
|
||||
extern int i2c_transfer_buffer_flags(const struct i2c_client *client,
|
||||
char *buf, int count, u16 flags);
|
||||
int i2c_transfer_buffer_flags(const struct i2c_client *client,
|
||||
char *buf, int count, u16 flags);
|
||||
|
||||
/**
|
||||
* i2c_master_recv - issue a single I2C message in master receive mode
|
||||
|
@ -115,11 +115,9 @@ static inline int i2c_master_send_dmasafe(const struct i2c_client *client,
|
|||
|
||||
/* Transfer num messages.
|
||||
*/
|
||||
extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
int num);
|
||||
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
|
||||
/* Unlocked flavor */
|
||||
extern int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
int num);
|
||||
int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
|
||||
|
||||
/* This is the very generalized SMBus access routine. You probably do not
|
||||
want to use this, though; one of the functions below may be much easier,
|
||||
|
@ -138,16 +136,14 @@ s32 __i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
|
|||
/* Now follow the 'nice' access routines. These also document the calling
|
||||
conventions of i2c_smbus_xfer. */
|
||||
|
||||
extern s32 i2c_smbus_read_byte(const struct i2c_client *client);
|
||||
extern s32 i2c_smbus_write_byte(const struct i2c_client *client, u8 value);
|
||||
extern s32 i2c_smbus_read_byte_data(const struct i2c_client *client,
|
||||
u8 command);
|
||||
extern s32 i2c_smbus_write_byte_data(const struct i2c_client *client,
|
||||
u8 command, u8 value);
|
||||
extern s32 i2c_smbus_read_word_data(const struct i2c_client *client,
|
||||
u8 command);
|
||||
extern s32 i2c_smbus_write_word_data(const struct i2c_client *client,
|
||||
u8 command, u16 value);
|
||||
s32 i2c_smbus_read_byte(const struct i2c_client *client);
|
||||
s32 i2c_smbus_write_byte(const struct i2c_client *client, u8 value);
|
||||
s32 i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command);
|
||||
s32 i2c_smbus_write_byte_data(const struct i2c_client *client,
|
||||
u8 command, u8 value);
|
||||
s32 i2c_smbus_read_word_data(const struct i2c_client *client, u8 command);
|
||||
s32 i2c_smbus_write_word_data(const struct i2c_client *client,
|
||||
u8 command, u16 value);
|
||||
|
||||
static inline s32
|
||||
i2c_smbus_read_word_swapped(const struct i2c_client *client, u8 command)
|
||||
|
@ -165,19 +161,18 @@ i2c_smbus_write_word_swapped(const struct i2c_client *client,
|
|||
}
|
||||
|
||||
/* Returns the number of read bytes */
|
||||
extern s32 i2c_smbus_read_block_data(const struct i2c_client *client,
|
||||
u8 command, u8 *values);
|
||||
extern s32 i2c_smbus_write_block_data(const struct i2c_client *client,
|
||||
u8 command, u8 length, const u8 *values);
|
||||
s32 i2c_smbus_read_block_data(const struct i2c_client *client,
|
||||
u8 command, u8 *values);
|
||||
s32 i2c_smbus_write_block_data(const struct i2c_client *client,
|
||||
u8 command, u8 length, const u8 *values);
|
||||
/* Returns the number of read bytes */
|
||||
extern s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client,
|
||||
u8 command, u8 length, u8 *values);
|
||||
extern s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client,
|
||||
u8 command, u8 length,
|
||||
const u8 *values);
|
||||
extern s32
|
||||
i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client,
|
||||
u8 command, u8 length, u8 *values);
|
||||
s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client,
|
||||
u8 command, u8 length, u8 *values);
|
||||
s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client,
|
||||
u8 command, u8 length, const u8 *values);
|
||||
s32 i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client,
|
||||
u8 command, u8 length,
|
||||
u8 *values);
|
||||
int i2c_get_device_id(const struct i2c_client *client,
|
||||
struct i2c_device_identity *id);
|
||||
#endif /* I2C */
|
||||
|
@ -337,10 +332,10 @@ struct i2c_client {
|
|||
};
|
||||
#define to_i2c_client(d) container_of(d, struct i2c_client, dev)
|
||||
|
||||
extern struct i2c_client *i2c_verify_client(struct device *dev);
|
||||
extern struct i2c_adapter *i2c_verify_adapter(struct device *dev);
|
||||
extern const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
|
||||
const struct i2c_client *client);
|
||||
struct i2c_client *i2c_verify_client(struct device *dev);
|
||||
struct i2c_adapter *i2c_verify_adapter(struct device *dev);
|
||||
const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
|
||||
const struct i2c_client *client);
|
||||
|
||||
static inline struct i2c_client *kobj_to_i2c_client(struct kobject *kobj)
|
||||
{
|
||||
|
@ -369,9 +364,9 @@ enum i2c_slave_event {
|
|||
I2C_SLAVE_STOP,
|
||||
};
|
||||
|
||||
extern int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb);
|
||||
extern int i2c_slave_unregister(struct i2c_client *client);
|
||||
extern bool i2c_detect_slave_mode(struct device *dev);
|
||||
int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb);
|
||||
int i2c_slave_unregister(struct i2c_client *client);
|
||||
bool i2c_detect_slave_mode(struct device *dev);
|
||||
|
||||
static inline int i2c_slave_event(struct i2c_client *client,
|
||||
enum i2c_slave_event event, u8 *val)
|
||||
|
@ -440,10 +435,10 @@ struct i2c_board_info {
|
|||
* with integrated I2C, a config eeprom, sensors, and a codec that's
|
||||
* used in conjunction with the primary hardware.
|
||||
*/
|
||||
extern struct i2c_client *
|
||||
struct i2c_client *
|
||||
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);
|
||||
|
||||
extern struct i2c_client *
|
||||
struct i2c_client *
|
||||
i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *info);
|
||||
|
||||
/* If you don't know the exact address of an I2C device, use this variant
|
||||
|
@ -452,33 +447,33 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf
|
|||
* it must return 1 on successful probe, 0 otherwise. If it is not provided,
|
||||
* a default probing method is used.
|
||||
*/
|
||||
extern struct i2c_client *
|
||||
struct i2c_client *
|
||||
i2c_new_scanned_device(struct i2c_adapter *adap,
|
||||
struct i2c_board_info *info,
|
||||
unsigned short const *addr_list,
|
||||
int (*probe)(struct i2c_adapter *adap, unsigned short addr));
|
||||
|
||||
extern struct i2c_client *
|
||||
struct i2c_client *
|
||||
i2c_new_probed_device(struct i2c_adapter *adap,
|
||||
struct i2c_board_info *info,
|
||||
unsigned short const *addr_list,
|
||||
int (*probe)(struct i2c_adapter *adap, unsigned short addr));
|
||||
|
||||
/* Common custom probe functions */
|
||||
extern int i2c_probe_func_quick_read(struct i2c_adapter *adap, unsigned short addr);
|
||||
int i2c_probe_func_quick_read(struct i2c_adapter *adap, unsigned short addr);
|
||||
|
||||
extern struct i2c_client *
|
||||
struct i2c_client *
|
||||
i2c_new_dummy_device(struct i2c_adapter *adapter, u16 address);
|
||||
|
||||
extern struct i2c_client *
|
||||
struct i2c_client *
|
||||
devm_i2c_new_dummy_device(struct device *dev, struct i2c_adapter *adap, u16 address);
|
||||
|
||||
extern struct i2c_client *
|
||||
struct i2c_client *
|
||||
i2c_new_ancillary_device(struct i2c_client *client,
|
||||
const char *name,
|
||||
u16 default_addr);
|
||||
const char *name,
|
||||
u16 default_addr);
|
||||
|
||||
extern void i2c_unregister_device(struct i2c_client *client);
|
||||
void i2c_unregister_device(struct i2c_client *client);
|
||||
#endif /* I2C */
|
||||
|
||||
/* Mainboard arch_initcall() code should register all its I2C devices.
|
||||
|
@ -486,7 +481,7 @@ extern void i2c_unregister_device(struct i2c_client *client);
|
|||
* Modules for add-on boards must use other calls.
|
||||
*/
|
||||
#ifdef CONFIG_I2C_BOARDINFO
|
||||
extern int
|
||||
int
|
||||
i2c_register_board_info(int busnum, struct i2c_board_info const *info,
|
||||
unsigned n);
|
||||
#else
|
||||
|
@ -840,12 +835,12 @@ static inline void i2c_mark_adapter_resumed(struct i2c_adapter *adap)
|
|||
/* administration...
|
||||
*/
|
||||
#if IS_ENABLED(CONFIG_I2C)
|
||||
extern int i2c_add_adapter(struct i2c_adapter *adap);
|
||||
extern void i2c_del_adapter(struct i2c_adapter *adap);
|
||||
extern int i2c_add_numbered_adapter(struct i2c_adapter *adap);
|
||||
int i2c_add_adapter(struct i2c_adapter *adap);
|
||||
void i2c_del_adapter(struct i2c_adapter *adap);
|
||||
int i2c_add_numbered_adapter(struct i2c_adapter *adap);
|
||||
|
||||
extern int i2c_register_driver(struct module *owner, struct i2c_driver *driver);
|
||||
extern void i2c_del_driver(struct i2c_driver *driver);
|
||||
int i2c_register_driver(struct module *owner, struct i2c_driver *driver);
|
||||
void i2c_del_driver(struct i2c_driver *driver);
|
||||
|
||||
/* use a define to avoid include chaining to get THIS_MODULE */
|
||||
#define i2c_add_driver(driver) \
|
||||
|
@ -858,12 +853,12 @@ static inline bool i2c_client_has_driver(struct i2c_client *client)
|
|||
|
||||
/* call the i2c_client->command() of all attached clients with
|
||||
* the given arguments */
|
||||
extern void i2c_clients_command(struct i2c_adapter *adap,
|
||||
unsigned int cmd, void *arg);
|
||||
void i2c_clients_command(struct i2c_adapter *adap,
|
||||
unsigned int cmd, void *arg);
|
||||
|
||||
extern struct i2c_adapter *i2c_get_adapter(int nr);
|
||||
extern void i2c_put_adapter(struct i2c_adapter *adap);
|
||||
extern unsigned int i2c_adapter_depth(struct i2c_adapter *adapter);
|
||||
struct i2c_adapter *i2c_get_adapter(int nr);
|
||||
void i2c_put_adapter(struct i2c_adapter *adap);
|
||||
unsigned int i2c_adapter_depth(struct i2c_adapter *adapter);
|
||||
|
||||
void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t, bool use_defaults);
|
||||
|
||||
|
@ -935,15 +930,15 @@ int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr);
|
|||
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
/* must call put_device() when done with returned i2c_client device */
|
||||
extern struct i2c_client *of_find_i2c_device_by_node(struct device_node *node);
|
||||
struct i2c_client *of_find_i2c_device_by_node(struct device_node *node);
|
||||
|
||||
/* must call put_device() when done with returned i2c_adapter device */
|
||||
extern struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node);
|
||||
struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node);
|
||||
|
||||
/* must call i2c_put_adapter() when done with returned i2c_adapter device */
|
||||
struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node *node);
|
||||
|
||||
extern const struct of_device_id
|
||||
const struct of_device_id
|
||||
*i2c_of_match_device(const struct of_device_id *matches,
|
||||
struct i2c_client *client);
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
struct nvmem_device;
|
||||
struct nvmem_cell_info;
|
||||
|
@ -45,6 +46,7 @@ enum nvmem_type {
|
|||
* @word_size: Minimum read/write access granularity.
|
||||
* @stride: Minimum read/write access stride.
|
||||
* @priv: User context passed to read/write callbacks.
|
||||
* @wp-gpio: Write protect pin
|
||||
*
|
||||
* Note: A default "nvmem<id>" name will be assigned to the device if
|
||||
* no name is specified in its configuration. In such case "<id>" is
|
||||
|
@ -58,6 +60,7 @@ struct nvmem_config {
|
|||
const char *name;
|
||||
int id;
|
||||
struct module *owner;
|
||||
struct gpio_desc *wp_gpio;
|
||||
const struct nvmem_cell_info *cells;
|
||||
int ncells;
|
||||
enum nvmem_type type;
|
||||
|
|
Загрузка…
Ссылка в новой задаче