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:
commit
11777ee8b0
|
@ -145,10 +145,7 @@ properties:
|
||||||
over reads to the next slave address. Please consult the manual of
|
over reads to the next slave address. Please consult the manual of
|
||||||
your device.
|
your device.
|
||||||
|
|
||||||
wp-gpios:
|
wp-gpios: true
|
||||||
description:
|
|
||||||
GPIO to which the write-protect pin of the chip is connected.
|
|
||||||
maxItems: 1
|
|
||||||
|
|
||||||
address-width:
|
address-width:
|
||||||
allOf:
|
allOf:
|
||||||
|
@ -167,6 +164,10 @@ properties:
|
||||||
minimum: 1
|
minimum: 1
|
||||||
maximum: 8
|
maximum: 8
|
||||||
|
|
||||||
|
vcc-supply:
|
||||||
|
description:
|
||||||
|
phandle of the regulator that provides the supply voltage.
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
- reg
|
- reg
|
||||||
|
|
|
@ -20,6 +20,7 @@ Optional properties:
|
||||||
- spi-cpha : SPI shifted clock phase, as per spi-bus bindings.
|
- spi-cpha : SPI shifted clock phase, as per spi-bus bindings.
|
||||||
- spi-cpol : SPI inverse clock polarity, 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
|
- 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",
|
Obsolete legacy properties can be used in place of "size", "pagesize",
|
||||||
"address-width", and "read-only":
|
"address-width", and "read-only":
|
||||||
|
@ -36,6 +37,7 @@ Example:
|
||||||
spi-max-frequency = <5000000>;
|
spi-max-frequency = <5000000>;
|
||||||
spi-cpha;
|
spi-cpha;
|
||||||
spi-cpol;
|
spi-cpol;
|
||||||
|
wp-gpios = <&gpio1 3 0>;
|
||||||
|
|
||||||
pagesize = <64>;
|
pagesize = <64>;
|
||||||
size = <32768>;
|
size = <32768>;
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
I2C for Atmel platforms
|
I2C for Atmel platforms
|
||||||
|
|
||||||
Required properties :
|
Required properties :
|
||||||
- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c",
|
- compatible : Must be one of:
|
||||||
"atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c",
|
"atmel,at91rm9200-i2c",
|
||||||
"atmel,at91sam9x5-i2c", "atmel,sama5d4-i2c", "atmel,sama5d2-i2c" or
|
"atmel,at91sam9261-i2c",
|
||||||
"microchip,sam9x60-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
|
- reg: physical base address of the controller and length of memory mapped
|
||||||
region.
|
region.
|
||||||
- interrupts: interrupt number to the cpu.
|
- interrupts: interrupt number to the cpu.
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
* Ingenic JZ4780 I2C Bus controller
|
* Ingenic JZ4780 I2C Bus controller
|
||||||
|
|
||||||
Required properties:
|
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.
|
- reg: Should contain the address & size of the I2C controller registers.
|
||||||
- interrupts: Should specify the interrupt provided by parent.
|
- interrupts: Should specify the interrupt provided by parent.
|
||||||
- clocks: Should contain a single clock specifier for the JZ4780 I2C clock.
|
- clocks: Should contain a single clock specifier for the JZ4780 I2C clock.
|
||||||
|
|
|
@ -25,6 +25,8 @@ Required Properties:
|
||||||
Optional Properties:
|
Optional Properties:
|
||||||
|
|
||||||
- reset-gpios: Reference to the GPIO connected to the reset input.
|
- 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
|
- 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
|
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.
|
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-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-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-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-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-r8a77970" if the device is a part of a R8A77970 SoC.
|
||||||
"renesas,i2c-r8a77980" if the device is a part of a R8A77980 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-r8a7794" (R-Car E2)
|
||||||
- "renesas,iic-r8a7795" (R-Car H3)
|
- "renesas,iic-r8a7795" (R-Car H3)
|
||||||
- "renesas,iic-r8a7796" (R-Car M3-W)
|
- "renesas,iic-r8a7796" (R-Car M3-W)
|
||||||
|
- "renesas,iic-r8a77961" (R-Car M3-W+)
|
||||||
- "renesas,iic-r8a77965" (R-Car M3-N)
|
- "renesas,iic-r8a77965" (R-Car M3-N)
|
||||||
- "renesas,iic-r8a77990" (R-Car E3)
|
- "renesas,iic-r8a77990" (R-Car E3)
|
||||||
- "renesas,iic-sh73a0" (SH-Mobile AG5)
|
- "renesas,iic-sh73a0" (SH-Mobile AG5)
|
||||||
|
|
|
@ -34,6 +34,14 @@ properties:
|
||||||
description:
|
description:
|
||||||
Mark the provider as read only.
|
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:
|
patternProperties:
|
||||||
"^.*@[0-9a-f]+$":
|
"^.*@[0-9a-f]+$":
|
||||||
type: object
|
type: object
|
||||||
|
@ -63,9 +71,12 @@ patternProperties:
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- |
|
- |
|
||||||
|
#include <dt-bindings/gpio/gpio.h>
|
||||||
|
|
||||||
qfprom: eeprom@700000 {
|
qfprom: eeprom@700000 {
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-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-nforce2
|
||||||
i2c-nvidia-gpu
|
i2c-nvidia-gpu
|
||||||
i2c-ocores
|
i2c-ocores
|
||||||
i2c-parport-light
|
|
||||||
i2c-parport
|
i2c-parport
|
||||||
i2c-pca-isa
|
i2c-pca-isa
|
||||||
i2c-piix4
|
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
|
possible to access all devices on an adapter from userspace, through
|
||||||
the /dev interface. You need to load module i2c-dev for this.
|
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.
|
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
|
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.
|
the i2c-tools package.
|
||||||
|
|
||||||
I2C device files are character device files with major device number 89
|
I2C device files are character device files with major device number 89
|
||||||
and a minor device number corresponding to the number assigned as
|
and a minor device number corresponding to the number assigned as
|
||||||
explained above. They should be called "i2c-%d" (i2c-0, i2c-1, ...,
|
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
|
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::
|
First, you need to include these two headers::
|
||||||
|
|
||||||
#include <linux/i2c-dev.h>
|
#include <linux/i2c-dev.h>
|
||||||
|
@ -66,7 +66,7 @@ the device supports them. Both are illustrated below::
|
||||||
/* Using SMBus commands */
|
/* Using SMBus commands */
|
||||||
res = i2c_smbus_read_word_data(file, reg);
|
res = i2c_smbus_read_word_data(file, reg);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
/* ERROR HANDLING: i2c transaction failed */
|
/* ERROR HANDLING: I2C transaction failed */
|
||||||
} else {
|
} else {
|
||||||
/* res contains the read word */
|
/* res contains the read word */
|
||||||
}
|
}
|
||||||
|
@ -79,12 +79,12 @@ the device supports them. Both are illustrated below::
|
||||||
buf[1] = 0x43;
|
buf[1] = 0x43;
|
||||||
buf[2] = 0x65;
|
buf[2] = 0x65;
|
||||||
if (write(file, buf, 3) != 3) {
|
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) */
|
/* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */
|
||||||
if (read(file, buf, 1) != 1) {
|
if (read(file, buf, 1) != 1) {
|
||||||
/* ERROR HANDLING: i2c transaction failed */
|
/* ERROR HANDLING: I2C transaction failed */
|
||||||
} else {
|
} else {
|
||||||
/* buf[0] contains the read byte */
|
/* 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
|
If possible, use the provided ``i2c_smbus_*`` methods described below instead
|
||||||
of issuing direct ioctls.
|
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
|
You do not need to pass the address byte; instead, set it through
|
||||||
ioctl I2C_SLAVE before you try to access the device.
|
ioctl I2C_SLAVE before you try to access the device.
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Linux I2C and DMA
|
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
|
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
|
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
|
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
|
Key to symbols
|
||||||
==============
|
==============
|
||||||
|
|
||||||
=============== =============================================================
|
=============== =============================================================
|
||||||
S (1 bit) : Start bit
|
S Start condition
|
||||||
P (1 bit) : Stop bit
|
P Stop condition
|
||||||
Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
|
Rd/Wr (1 bit) Read/Write bit. Rd equals 1, Wr equals 0.
|
||||||
A, NA (1 bit) : Accept and reverse accept bit.
|
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
|
Addr (7 bits) I2C 7 bit address. Note that this can be expanded as usual to
|
||||||
get a 10 bit I2C address.
|
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.
|
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.
|
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.
|
host adapter.
|
||||||
=============== =============================================================
|
=============== =============================================================
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ Count (8 bits): A data byte containing the length of a block operation.
|
||||||
Simple send transaction
|
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
|
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
|
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
|
S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P
|
||||||
|
|
||||||
|
@ -44,11 +44,11 @@ This corresponds to i2c_master_recv::
|
||||||
Combined transactions
|
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
|
They are just like the above transactions, but instead of a stop
|
||||||
a start bit S is sent and the transaction continues. An example of
|
condition P a start condition S is sent and the transaction continues.
|
||||||
a byte read, followed by a byte write::
|
An example of a byte read, followed by a byte write::
|
||||||
|
|
||||||
S Addr Rd [A] [Data] NA S Addr Wr [A] Data [A] P
|
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
|
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:
|
are usually only needed to work around device issues:
|
||||||
|
|
||||||
I2C_M_IGNORE_NAK:
|
I2C_M_IGNORE_NAK:
|
||||||
|
@ -77,8 +77,9 @@ I2C_M_NOSTART:
|
||||||
S Addr Rd [A] [Data] NA Data [A] P
|
S Addr Rd [A] [Data] NA Data [A] P
|
||||||
|
|
||||||
If you set the I2C_M_NOSTART variable for the first partial message,
|
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
|
we do not generate Addr, but we do generate the start condition S.
|
||||||
probably confuse all other clients on your bus, so don't try this.
|
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
|
This is often used to gather transmits from multiple data buffers in
|
||||||
system memory into something that appears as a single transfer to the
|
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
|
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.
|
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.
|
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.
|
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
|
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.
|
that has to be operated before the device can be accessed.
|
||||||
|
|
||||||
Etc
|
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
|
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
|
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).
|
object (quoted, since it can also be an arbitrator or a gate).
|
||||||
|
|
||||||
Depending of the particular mux driver, something happens when there is
|
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
|
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,
|
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
|
select and deselect. select is called before the transfer and (the
|
||||||
|
@ -34,7 +34,7 @@ optional) deselect is called after the transfer.
|
||||||
Locking
|
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
|
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
|
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:
|
following list was correct at the time of writing:
|
||||||
|
@ -45,7 +45,7 @@ In drivers/i2c/muxes/:
|
||||||
i2c-arb-gpio-challenge Parent-locked
|
i2c-arb-gpio-challenge Parent-locked
|
||||||
i2c-mux-gpio Normally parent-locked, mux-locked iff
|
i2c-mux-gpio Normally parent-locked, mux-locked iff
|
||||||
all involved gpio pins are controlled by the
|
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
|
i2c-mux-gpmux Normally parent-locked, mux-locked iff
|
||||||
specified in device-tree.
|
specified in device-tree.
|
||||||
i2c-mux-ltc4306 Mux-locked
|
i2c-mux-ltc4306 Mux-locked
|
||||||
|
@ -54,7 +54,7 @@ i2c-mux-pca9541 Parent-locked
|
||||||
i2c-mux-pca954x Parent-locked
|
i2c-mux-pca954x Parent-locked
|
||||||
i2c-mux-pinctrl Normally parent-locked, mux-locked iff
|
i2c-mux-pinctrl Normally parent-locked, mux-locked iff
|
||||||
all involved pinctrl devices are controlled
|
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
|
i2c-mux-reg Parent-locked
|
||||||
====================== =============================================
|
====================== =============================================
|
||||||
|
|
||||||
|
@ -83,9 +83,9 @@ Mux-locked muxes
|
||||||
Mux-locked muxes does not lock the entire parent adapter during the
|
Mux-locked muxes does not lock the entire parent adapter during the
|
||||||
full select-transfer-deselect transaction, only the muxes on the parent
|
full select-transfer-deselect transaction, only the muxes on the parent
|
||||||
adapter are locked. Mux-locked muxes are mostly interesting if the
|
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
|
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
|
stages of the transaction. This has the benefit that the mux driver
|
||||||
may be easier and cleaner to implement, but it has some caveats.
|
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
|
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
|
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.
|
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.
|
the driver has to lock the root adapter during that operation.
|
||||||
Otherwise garbage may appear on the bus as seen from devices
|
Otherwise garbage may appear on the bus as seen from devices
|
||||||
behind the mux, when an unrelated i2c transfer is in flight during
|
behind the mux, when an unrelated I2C transfer is in flight during
|
||||||
the non-i2c mux-changing operation.
|
the non-I2C mux-changing operation.
|
||||||
==== =====================================================================
|
==== =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
@ -137,14 +137,14 @@ Mux-locked Example
|
||||||
|
|
||||||
When there is an access to D1, this happens:
|
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).
|
2. M1 locks muxes on its parent (the root adapter in this case).
|
||||||
3. M1 calls ->select to ready the mux.
|
3. M1 calls ->select to ready the mux.
|
||||||
4. M1 (presumably) does some i2c-transfers as part of its select.
|
4. M1 (presumably) does some I2C transfers as part of its select.
|
||||||
These transfers are normal i2c-transfers that locks the parent
|
These transfers are normal I2C transfers that locks the parent
|
||||||
adapter.
|
adapter.
|
||||||
5. M1 feeds the i2c-transfer from step 1 to its parent adapter as a
|
5. M1 feeds the I2C transfer from step 1 to its parent adapter as a
|
||||||
normal i2c-transfer that locks the parent adapter.
|
normal I2C transfer that locks the parent adapter.
|
||||||
6. M1 calls ->deselect, if it has one.
|
6. M1 calls ->deselect, if it has one.
|
||||||
7. Same rules as in step 4, but for ->deselect.
|
7. Same rules as in step 4, but for ->deselect.
|
||||||
8. M1 unlocks muxes on its parent.
|
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-
|
Parent-locked muxes lock the parent adapter during the full select-
|
||||||
transfer-deselect transaction. The implication is that the mux driver
|
transfer-deselect transaction. The implication is that the mux driver
|
||||||
has to ensure that any and all i2c transfers through that parent
|
has to ensure that any and all I2C transfers through that parent
|
||||||
adapter during the transaction are unlocked i2c transfers (using e.g.
|
adapter during the transaction are unlocked I2C transfers (using e.g.
|
||||||
__i2c_transfer), or a deadlock will follow. There are a couple of
|
__i2c_transfer), or a deadlock will follow. There are a couple of
|
||||||
caveats.
|
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
|
of another mux, this might break a possible assumption from the
|
||||||
child mux that the root adapter is unused between its select op
|
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 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
|
This is especially the case if the parent mux is mux-locked, but
|
||||||
it may also happen if the parent mux is parent-locked.
|
it may also happen if the parent mux is parent-locked.
|
||||||
|
|
||||||
PL2. If select/deselect calls out to other subsystems such as gpio,
|
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
|
caused by these subsystems are unlocked. This can be convoluted to
|
||||||
accomplish, maybe even impossible if an acceptably clean solution
|
accomplish, maybe even impossible if an acceptably clean solution
|
||||||
is sought.
|
is sought.
|
||||||
|
@ -197,15 +197,15 @@ Parent-locked Example
|
||||||
|
|
||||||
When there is an access to D1, this happens:
|
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).
|
2. M1 locks muxes on its parent (the root adapter in this case).
|
||||||
3. M1 locks its parent adapter.
|
3. M1 locks its parent adapter.
|
||||||
4. M1 calls ->select to ready the mux.
|
4. M1 calls ->select to ready the mux.
|
||||||
5. If M1 does any i2c-transfers (on this root adapter) as part of
|
5. If M1 does any I2C transfers (on this root adapter) as part of
|
||||||
its select, those transfers must be unlocked i2c-transfers so
|
its select, those transfers must be unlocked I2C transfers so
|
||||||
that they do not deadlock the root adapter.
|
that they do not deadlock the root adapter.
|
||||||
6. M1 feeds the i2c-transfer from step 1 to the root adapter as an
|
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
|
unlocked I2C transfer, so that it does not deadlock the parent
|
||||||
adapter.
|
adapter.
|
||||||
7. M1 calls ->deselect, if it has one.
|
7. M1 calls ->deselect, if it has one.
|
||||||
8. Same rules as in step 5, but for ->deselect.
|
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).
|
the buck to the root adapter).
|
||||||
|
|
||||||
This topology is bad if M2 is an auto-closing mux and M1->select
|
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.
|
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
|
This kind of topology is generally not suitable and should probably
|
||||||
be avoided. The reason is that M2 probably assumes that there will
|
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
|
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.
|
device lockups and/or other problems.
|
||||||
|
|
||||||
The topology is especially troublesome if M2 is an auto-closing
|
The topology is especially troublesome if M2 is an auto-closing
|
||||||
mux. In that case, any interleaved accesses to D4 might close M2
|
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
|
But if M2 is not making the above stated assumption, and if M2 is not
|
||||||
auto-closing, the topology is fine.
|
auto-closing, the topology is fine.
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 55 KiB |
|
@ -4,30 +4,66 @@
|
||||||
I2C/SMBus Subsystem
|
I2C/SMBus Subsystem
|
||||||
===================
|
===================
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
: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
|
dev-interface
|
||||||
dma-considerations
|
dma-considerations
|
||||||
fault-codes
|
fault-codes
|
||||||
functionality
|
functionality
|
||||||
|
|
||||||
|
Debugging
|
||||||
|
=========
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
gpio-fault-injection
|
gpio-fault-injection
|
||||||
i2c-protocol
|
|
||||||
i2c-stub
|
i2c-stub
|
||||||
i2c-topology
|
|
||||||
instantiating-devices
|
Slave I2C
|
||||||
old-module-parameters
|
=========
|
||||||
slave-eeprom-backend
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
slave-interface
|
slave-interface
|
||||||
smbus-protocol
|
slave-eeprom-backend
|
||||||
summary
|
|
||||||
|
Advanced topics
|
||||||
|
===============
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
ten-bit-addresses
|
ten-bit-addresses
|
||||||
|
|
||||||
|
Legacy documentation
|
||||||
|
====================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
upgrading-clients
|
upgrading-clients
|
||||||
writing-clients
|
old-module-parameters
|
||||||
|
|
||||||
muxes/i2c-mux-gpio
|
|
||||||
|
|
||||||
busses/index
|
|
||||||
|
|
||||||
.. only:: subproject and html
|
.. 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.
|
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
|
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
|
for many embedded systems. On such systems, each I2C bus has a number which
|
||||||
which is known in advance. It is thus possible to pre-declare the I2C
|
is known in advance. It is thus possible to pre-declare the I2C devices
|
||||||
devices which live on this bus. This is done with an array of struct
|
which live on this bus.
|
||||||
i2c_board_info which is registered by calling i2c_register_board_info().
|
|
||||||
|
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)::
|
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
|
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
|
addresses and custom data needed by their drivers.
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
Method 2: Instantiate the devices explicitly
|
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
|
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,
|
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
|
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)::
|
Example (from the sfe4001 network driver)::
|
||||||
|
|
||||||
|
@ -110,7 +121,7 @@ Example (from the sfe4001 network driver)::
|
||||||
{
|
{
|
||||||
(...)
|
(...)
|
||||||
efx->board_info.hwmon_client =
|
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
|
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
|
it may have different addresses from one board to the next (manufacturer
|
||||||
changing its design without notice). In this case, you can call
|
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)::
|
Example (from the nxp OHCI driver)::
|
||||||
|
|
||||||
|
@ -152,7 +163,7 @@ simply gives up.
|
||||||
|
|
||||||
The driver which instantiated the I2C device is responsible for destroying
|
The driver which instantiated the I2C device is responsible for destroying
|
||||||
it on cleanup. This is done by calling i2c_unregister_device() on the
|
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().
|
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
|
or when the underlying I2C bus is itself destroyed, whichever happens
|
||||||
first.
|
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
|
kernels will find out that this method 3 is essentially similar to what
|
||||||
was done there. Two significant differences are:
|
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
|
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
|
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
|
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
|
directory: ``new_device`` and ``delete_device``. Both files are write
|
||||||
must write the right parameters to them in order to properly instantiate,
|
only and you must write the right parameters to them in order to properly
|
||||||
respectively delete, an I2C device.
|
instantiate, respectively delete, an I2C device.
|
||||||
|
|
||||||
File new_device takes 2 parameters: the name of the I2C device (a string)
|
File ``new_device`` takes 2 parameters: the name of the I2C device (a
|
||||||
and the address of the I2C device (a number, typically expressed in
|
string) and the address of the I2C device (a number, typically expressed
|
||||||
hexadecimal starting with 0x, but can also be expressed in decimal.)
|
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
|
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
|
segment, the address is sufficient to uniquely identify the device to be
|
||||||
deleted.
|
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
|
<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
|
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
|
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
|
address), ``force`` (to forcibly attach the driver to a given device) and
|
||||||
"ignore" (to prevent a driver from probing a given address).
|
``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
|
binding model, it became clear that these per-module parameters were no
|
||||||
longer needed, and that a centralized implementation was possible. The new,
|
longer needed, and that a centralized implementation was possible. The new,
|
||||||
sysfs-based interface is described in the documentation file
|
sysfs-based interface is described in :doc:`instantiating-devices`, section
|
||||||
"instantiating-devices", section "Method 4: Instantiate from user-space".
|
"Method 4: Instantiate from user-space".
|
||||||
|
|
||||||
Below is a mapping from the old module parameters to the new interface.
|
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
|
# echo dummy 0x2f > /sys/bus/i2c/devices/i2c-1/new_device
|
||||||
# modprobe <driver>
|
# 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
|
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
|
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
|
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)
|
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
|
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
|
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'
|
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:
|
If you want to add slave support to the bus driver:
|
||||||
|
|
||||||
* implement calls to register/unregister the slave and add those to the
|
* 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
|
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
|
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,
|
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
|
The following is a summary of the SMBus protocol. It applies to
|
||||||
all revisions of the protocol (1.0, 1.1, and 2.0).
|
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
|
Each transaction type corresponds to a functionality flag. Before calling a
|
||||||
transaction function, a device driver should always check (just once) for
|
transaction function, a device driver should always check (just once) for
|
||||||
the corresponding functionality flag to ensure that the underlying I2C
|
the corresponding functionality flag to ensure that the underlying I2C
|
||||||
adapter supports the transaction in question. See
|
adapter supports the transaction in question. See :doc:`functionality` for
|
||||||
<file:Documentation/i2c/functionality.rst> for the details.
|
the details.
|
||||||
|
|
||||||
|
|
||||||
Key to symbols
|
Key to symbols
|
||||||
==============
|
==============
|
||||||
|
|
||||||
=============== =============================================================
|
=============== =============================================================
|
||||||
S (1 bit) : Start bit
|
S Start condition
|
||||||
P (1 bit) : Stop bit
|
P Stop condition
|
||||||
Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
|
Rd/Wr (1 bit) Read/Write bit. Rd equals 1, Wr equals 0.
|
||||||
A, NA (1 bit) : Accept and reverse accept bit.
|
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
|
Addr (7 bits) I2C 7 bit address. Note that this can be expanded as usual to
|
||||||
get a 10 bit I2C address.
|
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.
|
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.
|
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.
|
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
|
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
|
This reads a single byte from a device, without specifying a device
|
||||||
register. Some devices are so simple that this interface is enough; for
|
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
|
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
|
This operation is the reverse of Receive Byte: it sends a single byte
|
||||||
to a device. See Receive Byte for more information.
|
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
|
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.
|
This reads a single byte from a device, from a designated register.
|
||||||
The register is specified through the Comm byte::
|
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
|
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
|
This operation is very like Read Byte; again, data is read from a
|
||||||
device, from a designated register that is specified through the Comm
|
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
|
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
|
available for reads where the two data bytes are the other way
|
||||||
around (not SMBus compliant, but very popular.)
|
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
|
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
|
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
|
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
|
This is the opposite of the Read Word operation. 16 bits
|
||||||
of data is written to a device, to the designated register that is
|
of data are written to a device, to the designated register that is
|
||||||
specified through the Comm byte.::
|
specified through the Comm byte::
|
||||||
|
|
||||||
S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P
|
S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P
|
||||||
|
|
||||||
Functionality flag: I2C_FUNC_SMBUS_WRITE_WORD_DATA
|
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
|
available for writes where the two data bytes are the other way
|
||||||
around (not SMBus compliant, but very popular.)
|
around (not SMBus compliant, but very popular.)
|
||||||
|
|
||||||
|
|
||||||
SMBus Process Call:
|
SMBus Process Call
|
||||||
===================
|
==================
|
||||||
|
|
||||||
This command selects a device register (through the Comm byte), sends
|
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::
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
I2C Block Transactions
|
||||||
======================
|
======================
|
||||||
|
|
||||||
The following I2C block transactions are supported by the
|
The following I2C block transactions are similar to the SMBus Block Read
|
||||||
SMBus layer and are described here for completeness.
|
and Write operations, except these do not have a Count byte. They are
|
||||||
They are *NOT* defined by the SMBus specification.
|
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
|
I2C block transactions do not limit the number of bytes transferred
|
||||||
but the SMBus layer places a limit of 32 bytes.
|
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
|
This command reads a block of bytes from a device, from a
|
||||||
designated register that is specified through the Comm byte::
|
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
|
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
|
The opposite of the Block Read command, this writes bytes to
|
||||||
a device, to a designated register that is specified through the
|
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
|
I²C (pronounce: I squared C and written I2C in the kernel documentation) is
|
||||||
slow two-wire protocol (variable speed, up to 400 kHz), with a high speed
|
a protocol developed by Philips. It is a slow two-wire protocol (variable
|
||||||
extension (3.4 MHz). It provides an inexpensive bus for connecting many
|
speed, up to 400 kHz), with a high speed extension (3.4 MHz). It provides
|
||||||
types of devices with infrequent or low bandwidth communications needs.
|
an inexpensive bus for connecting many types of devices with infrequent or
|
||||||
I2C is widely used with embedded systems. Some systems use variants that
|
low bandwidth communications needs. I2C is widely used with embedded
|
||||||
don't meet branding requirements, and so are not advertised as being I2C.
|
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
|
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
|
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
|
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
|
.. kernel-figure:: i2c.svg
|
||||||
Adapter
|
:alt: Simple I2C bus with one master and 3 slaves
|
||||||
Device -> Driver
|
|
||||||
Client
|
|
||||||
|
|
||||||
An Algorithm driver contains general code that can be used for a whole class
|
Simple I2C bus
|
||||||
of I2C adapters. Each specific adapter driver either depends on one algorithm
|
|
||||||
driver, or includes its own implementation.
|
|
||||||
|
|
||||||
A Driver driver (yes, this sounds ridiculous, sorry) contains the general
|
A **master** chip is a node that starts communications with slaves. In the
|
||||||
code to access some type of device. Each detected device gets its own
|
Linux kernel implementation it is called an **adapter** or bus. Adapter
|
||||||
data in the Client structure. Usually, Driver and Client are more closely
|
drivers are in the ``drivers/i2c/busses/`` subdirectory.
|
||||||
integrated than Algorithm and Adapter.
|
|
||||||
|
|
||||||
For a given configuration, you will need a driver for your I2C bus, and
|
An **algorithm** contains general code that can be used to implement a
|
||||||
drivers for your I2C devices (usually one driver for each device).
|
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
|
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).
|
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.
|
client.
|
||||||
|
|
||||||
I have found it useful to define foo_read and foo_write functions for this.
|
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
|
but many chips have some kind of register-value idea that can easily
|
||||||
be encapsulated.
|
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,
|
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
|
you can instantiate that device by simply filling an i2c_board_info
|
||||||
structure with the device address and driver name, and calling
|
structure with the device address and driver name, and calling
|
||||||
i2c_new_device(). This will create the device, then the driver core will
|
i2c_new_client_device(). This will create the device, then the driver core
|
||||||
take care of finding the right driver and will call its probe() method.
|
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
|
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
|
want using the type field. You can also specify an IRQ and platform data
|
||||||
if needed.
|
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
|
example, where the same driver supports dozens of slightly different
|
||||||
models, and I2C device addresses change from one model to the next. In
|
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
|
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
|
similar to i2c_new_client_device(), except that it takes an additional list
|
||||||
possible I2C addresses to probe. A device is created for the first
|
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
|
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
|
present in the address range, simply call i2c_new_scanned_device() that
|
||||||
many times.
|
many times.
|
||||||
|
|
||||||
The call to i2c_new_device() or i2c_new_scanned_device() typically happens
|
The call to i2c_new_client_device() or i2c_new_scanned_device() typically
|
||||||
in the I2C bus driver. You may want to save the returned i2c_client
|
happens in the I2C bus driver. You may want to save the returned i2c_client
|
||||||
reference for later use.
|
reference for later use.
|
||||||
|
|
||||||
|
|
||||||
|
@ -236,11 +236,11 @@ possible.
|
||||||
Device Deletion
|
Device Deletion
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
Each I2C device which has been created using i2c_new_device() or
|
Each I2C device which has been created using i2c_new_client_device()
|
||||||
i2c_new_scanned_device() can be unregistered by calling
|
or i2c_new_scanned_device() can be unregistered by calling
|
||||||
i2c_unregister_device(). If you don't call it explicitly, it will be
|
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
|
called automatically before the underlying I2C bus itself is removed,
|
||||||
device can't survive its parent in the device driver model.
|
as a device can't survive its parent in the device driver model.
|
||||||
|
|
||||||
|
|
||||||
Initializing the driver
|
Initializing the driver
|
||||||
|
@ -344,7 +344,7 @@ Plain I2C communication
|
||||||
int i2c_master_recv(struct i2c_client *client, char *buf, int count);
|
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
|
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
|
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
|
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
|
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,
|
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
|
and they can be mixed in any way. The transactions are combined: no
|
||||||
stop bit is sent between transaction. The i2c_msg structure contains
|
stop condition is issued between transaction. The i2c_msg structure
|
||||||
for each message the client address, the number of bytes of the message
|
contains for each message the client address, the number of bytes of the
|
||||||
and the message data itself.
|
message and the message data itself.
|
||||||
|
|
||||||
You can read the file ``i2c-protocol`` for more information about the
|
You can read the file ``i2c-protocol`` for more information about the
|
||||||
actual I2C protocol.
|
actual I2C protocol.
|
||||||
|
|
|
@ -7814,9 +7814,7 @@ M: Jean Delvare <jdelvare@suse.com>
|
||||||
L: linux-i2c@vger.kernel.org
|
L: linux-i2c@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/i2c/busses/i2c-parport.rst
|
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.c
|
||||||
F: drivers/i2c/busses/i2c-parport-light.c
|
|
||||||
|
|
||||||
I2C SUBSYSTEM
|
I2C SUBSYSTEM
|
||||||
M: Wolfram Sang <wsa@the-dreams.de>
|
M: Wolfram Sang <wsa@the-dreams.de>
|
||||||
|
|
|
@ -367,7 +367,8 @@ comment "I2C system bus drivers (mostly embedded / system-on-chip)"
|
||||||
|
|
||||||
config I2C_ALTERA
|
config I2C_ALTERA
|
||||||
tristate "Altera Soft IP I2C"
|
tristate "Altera Soft IP I2C"
|
||||||
depends on (ARCH_SOCFPGA || NIOS2) && OF
|
depends on ARCH_SOCFPGA || NIOS2 || COMPILE_TEST
|
||||||
|
depends on OF
|
||||||
help
|
help
|
||||||
If you say yes to this option, support will be included for the
|
If you say yes to this option, support will be included for the
|
||||||
Altera Soft IP I2C interfaces on SoCFPGA and Nios2 architectures.
|
Altera Soft IP I2C interfaces on SoCFPGA and Nios2 architectures.
|
||||||
|
@ -387,7 +388,7 @@ config I2C_ASPEED
|
||||||
|
|
||||||
config I2C_AT91
|
config I2C_AT91
|
||||||
tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
|
tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
|
||||||
depends on ARCH_AT91
|
depends on ARCH_AT91 || COMPILE_TEST
|
||||||
help
|
help
|
||||||
This supports the use of the I2C interface on Atmel AT91
|
This supports the use of the I2C interface on Atmel AT91
|
||||||
processors.
|
processors.
|
||||||
|
@ -440,7 +441,8 @@ config I2C_AXXIA
|
||||||
|
|
||||||
config I2C_BCM2835
|
config I2C_BCM2835
|
||||||
tristate "Broadcom BCM2835 I2C controller"
|
tristate "Broadcom BCM2835 I2C controller"
|
||||||
depends on ARCH_BCM2835 || ARCH_BRCMSTB
|
depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST
|
||||||
|
depends on COMMON_CLK
|
||||||
help
|
help
|
||||||
If you say yes to this option, support will be included for the
|
If you say yes to this option, support will be included for the
|
||||||
BCM2835 I2C controller.
|
BCM2835 I2C controller.
|
||||||
|
@ -463,8 +465,8 @@ config I2C_BCM_IPROC
|
||||||
|
|
||||||
config I2C_BCM_KONA
|
config I2C_BCM_KONA
|
||||||
tristate "BCM Kona I2C adapter"
|
tristate "BCM Kona I2C adapter"
|
||||||
depends on ARCH_BCM_MOBILE
|
depends on ARCH_BCM_MOBILE || COMPILE_TEST
|
||||||
default y
|
default y if ARCH_BCM_MOBILE
|
||||||
help
|
help
|
||||||
If you say yes to this option, support will be included for the
|
If you say yes to this option, support will be included for the
|
||||||
I2C interface on the Broadcom Kona family of processors.
|
I2C interface on the Broadcom Kona family of processors.
|
||||||
|
@ -511,7 +513,7 @@ config I2C_CPM
|
||||||
|
|
||||||
config I2C_DAVINCI
|
config I2C_DAVINCI
|
||||||
tristate "DaVinci I2C driver"
|
tristate "DaVinci I2C driver"
|
||||||
depends on ARCH_DAVINCI || ARCH_KEYSTONE
|
depends on ARCH_DAVINCI || ARCH_KEYSTONE || COMPILE_TEST
|
||||||
help
|
help
|
||||||
Support for TI DaVinci I2C controller driver.
|
Support for TI DaVinci I2C controller driver.
|
||||||
|
|
||||||
|
@ -572,7 +574,7 @@ config I2C_DESIGNWARE_BAYTRAIL
|
||||||
|
|
||||||
config I2C_DIGICOLOR
|
config I2C_DIGICOLOR
|
||||||
tristate "Conexant Digicolor I2C driver"
|
tristate "Conexant Digicolor I2C driver"
|
||||||
depends on ARCH_DIGICOLOR
|
depends on ARCH_DIGICOLOR || COMPILE_TEST
|
||||||
help
|
help
|
||||||
Support for Conexant Digicolor SoCs (CX92755) I2C controller driver.
|
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.
|
I2C interface on the Renesas Electronics EM/EV family of processors.
|
||||||
|
|
||||||
config I2C_EXYNOS5
|
config I2C_EXYNOS5
|
||||||
tristate "Exynos5 high-speed I2C driver"
|
tristate "Exynos high-speed I2C driver"
|
||||||
depends on ARCH_EXYNOS && OF
|
depends on OF
|
||||||
default y
|
depends on ARCH_EXYNOS || COMPILE_TEST
|
||||||
|
default y if ARCH_EXYNOS
|
||||||
help
|
help
|
||||||
High-speed I2C controller on Exynos5 based Samsung SoCs.
|
High-speed I2C controller on Exynos5 and newer Samsung SoCs.
|
||||||
|
|
||||||
config I2C_GPIO
|
config I2C_GPIO
|
||||||
tristate "GPIO-based bitbanging I2C"
|
tristate "GPIO-based bitbanging I2C"
|
||||||
|
@ -634,7 +637,7 @@ config I2C_GPIO_FAULT_INJECTOR
|
||||||
|
|
||||||
config I2C_HIGHLANDER
|
config I2C_HIGHLANDER
|
||||||
tristate "Highlander FPGA SMBus interface"
|
tristate "Highlander FPGA SMBus interface"
|
||||||
depends on SH_HIGHLANDER
|
depends on SH_HIGHLANDER || COMPILE_TEST
|
||||||
help
|
help
|
||||||
If you say yes to this option, support will be included for
|
If you say yes to this option, support will be included for
|
||||||
the SMBus interface located in the FPGA on various Highlander
|
the SMBus interface located in the FPGA on various Highlander
|
||||||
|
@ -686,7 +689,7 @@ config I2C_IMX_LPI2C
|
||||||
|
|
||||||
config I2C_IOP3XX
|
config I2C_IOP3XX
|
||||||
tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
|
tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
|
||||||
depends on ARCH_IOP32X || ARCH_IXP4XX
|
depends on ARCH_IOP32X || ARCH_IXP4XX || COMPILE_TEST
|
||||||
help
|
help
|
||||||
Say Y here if you want to use the IIC bus controller on
|
Say Y here if you want to use the IIC bus controller on
|
||||||
the Intel IOPx3xx I/O Processors or IXP4xx Network Processors.
|
the Intel IOPx3xx I/O Processors or IXP4xx Network Processors.
|
||||||
|
@ -726,6 +729,7 @@ config I2C_LPC2K
|
||||||
config I2C_MESON
|
config I2C_MESON
|
||||||
tristate "Amlogic Meson I2C controller"
|
tristate "Amlogic Meson I2C controller"
|
||||||
depends on ARCH_MESON || COMPILE_TEST
|
depends on ARCH_MESON || COMPILE_TEST
|
||||||
|
depends on COMMON_CLK
|
||||||
help
|
help
|
||||||
If you say yes to this option, support will be included for the
|
If you say yes to this option, support will be included for the
|
||||||
I2C interface on the Amlogic Meson family of SoCs.
|
I2C interface on the Amlogic Meson family of SoCs.
|
||||||
|
@ -759,7 +763,7 @@ config I2C_MT7621
|
||||||
|
|
||||||
config I2C_MV64XXX
|
config I2C_MV64XXX
|
||||||
tristate "Marvell mv64xxx I2C Controller"
|
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
|
help
|
||||||
If you say yes to this option, support will be included for the
|
If you say yes to this option, support will be included for the
|
||||||
built-in I2C interface on the Marvell 64xxx line of host bridges.
|
built-in I2C interface on the Marvell 64xxx line of host bridges.
|
||||||
|
@ -770,7 +774,7 @@ config I2C_MV64XXX
|
||||||
|
|
||||||
config I2C_MXS
|
config I2C_MXS
|
||||||
tristate "Freescale i.MX28 I2C interface"
|
tristate "Freescale i.MX28 I2C interface"
|
||||||
depends on SOC_IMX28
|
depends on SOC_IMX28 || COMPILE_TEST
|
||||||
select STMP_DEVICE
|
select STMP_DEVICE
|
||||||
help
|
help
|
||||||
Say Y here if you want to use the I2C bus controller on
|
Say Y here if you want to use the I2C bus controller on
|
||||||
|
@ -799,7 +803,7 @@ config I2C_OCORES
|
||||||
|
|
||||||
config I2C_OMAP
|
config I2C_OMAP
|
||||||
tristate "OMAP I2C adapter"
|
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
|
default y if MACH_OMAP_H3 || MACH_OMAP_OSK
|
||||||
help
|
help
|
||||||
If you say yes to this option, support will be included for the
|
If you say yes to this option, support will be included for the
|
||||||
|
@ -833,7 +837,7 @@ config I2C_PCA_PLATFORM
|
||||||
|
|
||||||
config I2C_PMCMSP
|
config I2C_PMCMSP
|
||||||
tristate "PMC MSP I2C TWI Controller"
|
tristate "PMC MSP I2C TWI Controller"
|
||||||
depends on PMC_MSP
|
depends on PMC_MSP || COMPILE_TEST
|
||||||
help
|
help
|
||||||
This driver supports the PMC TWI controller on MSP devices.
|
This driver supports the PMC TWI controller on MSP devices.
|
||||||
|
|
||||||
|
@ -842,7 +846,7 @@ config I2C_PMCMSP
|
||||||
|
|
||||||
config I2C_PNX
|
config I2C_PNX
|
||||||
tristate "I2C bus support for Philips PNX and NXP LPC targets"
|
tristate "I2C bus support for Philips PNX and NXP LPC targets"
|
||||||
depends on ARCH_LPC32XX
|
depends on ARCH_LPC32XX || COMPILE_TEST
|
||||||
help
|
help
|
||||||
This driver supports the Philips IP3204 I2C IP block master and/or
|
This driver supports the Philips IP3204 I2C IP block master and/or
|
||||||
slave controller
|
slave controller
|
||||||
|
@ -863,7 +867,7 @@ config I2C_PUV3
|
||||||
|
|
||||||
config I2C_PXA
|
config I2C_PXA
|
||||||
tristate "Intel PXA2XX I2C adapter"
|
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
|
help
|
||||||
If you have devices in the PXA I2C bus, say yes to this option.
|
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
|
This driver can also be built as a module. If so, the module
|
||||||
|
@ -932,11 +936,11 @@ config HAVE_S3C2410_I2C
|
||||||
respective Kconfig file.
|
respective Kconfig file.
|
||||||
|
|
||||||
config I2C_S3C2410
|
config I2C_S3C2410
|
||||||
tristate "S3C2410 I2C Driver"
|
tristate "S3C/Exynos I2C Driver"
|
||||||
depends on HAVE_S3C2410_I2C
|
depends on HAVE_S3C2410_I2C || COMPILE_TEST
|
||||||
help
|
help
|
||||||
Say Y here to include support for I2C controller in the
|
Say Y here to include support for I2C controller in the
|
||||||
Samsung SoCs.
|
Samsung SoCs (S3C, S5Pv210, Exynos).
|
||||||
|
|
||||||
config I2C_SH7760
|
config I2C_SH7760
|
||||||
tristate "Renesas SH7760 I2C Controller"
|
tristate "Renesas SH7760 I2C Controller"
|
||||||
|
@ -971,7 +975,7 @@ config I2C_SIMTEC
|
||||||
|
|
||||||
config I2C_SIRF
|
config I2C_SIRF
|
||||||
tristate "CSR SiRFprimaII I2C interface"
|
tristate "CSR SiRFprimaII I2C interface"
|
||||||
depends on ARCH_SIRF
|
depends on ARCH_SIRF || COMPILE_TEST
|
||||||
help
|
help
|
||||||
If you say yes to this option, support will be included for the
|
If you say yes to this option, support will be included for the
|
||||||
CSR SiRFprimaII I2C interface.
|
CSR SiRFprimaII I2C interface.
|
||||||
|
@ -981,14 +985,14 @@ config I2C_SIRF
|
||||||
|
|
||||||
config I2C_SPRD
|
config I2C_SPRD
|
||||||
tristate "Spreadtrum I2C interface"
|
tristate "Spreadtrum I2C interface"
|
||||||
depends on I2C=y && ARCH_SPRD
|
depends on I2C=y && (ARCH_SPRD || COMPILE_TEST)
|
||||||
help
|
help
|
||||||
If you say yes to this option, support will be included for the
|
If you say yes to this option, support will be included for the
|
||||||
Spreadtrum I2C interface.
|
Spreadtrum I2C interface.
|
||||||
|
|
||||||
config I2C_ST
|
config I2C_ST
|
||||||
tristate "STMicroelectronics SSC I2C support"
|
tristate "STMicroelectronics SSC I2C support"
|
||||||
depends on ARCH_STI
|
depends on ARCH_STI || COMPILE_TEST
|
||||||
help
|
help
|
||||||
Enable this option to add support for STMicroelectronics SoCs
|
Enable this option to add support for STMicroelectronics SoCs
|
||||||
hardware SSC (Synchronous Serial Controller) as an I2C controller.
|
hardware SSC (Synchronous Serial Controller) as an I2C controller.
|
||||||
|
@ -1019,7 +1023,7 @@ config I2C_STM32F7
|
||||||
|
|
||||||
config I2C_STU300
|
config I2C_STU300
|
||||||
tristate "ST Microelectronics DDC I2C interface"
|
tristate "ST Microelectronics DDC I2C interface"
|
||||||
depends on MACH_U300
|
depends on MACH_U300 || COMPILE_TEST
|
||||||
default y if MACH_U300
|
default y if MACH_U300
|
||||||
help
|
help
|
||||||
If you say yes to this option, support will be included for the
|
If you say yes to this option, support will be included for the
|
||||||
|
@ -1055,15 +1059,16 @@ config I2C_SYNQUACER
|
||||||
|
|
||||||
config I2C_TEGRA
|
config I2C_TEGRA
|
||||||
tristate "NVIDIA Tegra internal I2C controller"
|
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
|
help
|
||||||
If you say yes to this option, support will be included for the
|
If you say yes to this option, support will be included for the
|
||||||
I2C controller embedded in NVIDIA Tegra SOCs
|
I2C controller embedded in NVIDIA Tegra SOCs
|
||||||
|
|
||||||
config I2C_TEGRA_BPMP
|
config I2C_TEGRA_BPMP
|
||||||
tristate "NVIDIA Tegra BPMP I2C controller"
|
tristate "NVIDIA Tegra BPMP I2C controller"
|
||||||
depends on TEGRA_BPMP
|
depends on TEGRA_BPMP || COMPILE_TEST
|
||||||
default y
|
default y if TEGRA_BPMP
|
||||||
help
|
help
|
||||||
If you say yes to this option, support will be included for the I2C
|
If you say yes to this option, support will be included for the I2C
|
||||||
controller embedded in NVIDIA Tegra SoCs accessed via the BPMP.
|
controller embedded in NVIDIA Tegra SoCs accessed via the BPMP.
|
||||||
|
@ -1101,7 +1106,7 @@ config I2C_VERSATILE
|
||||||
|
|
||||||
config I2C_WMT
|
config I2C_WMT
|
||||||
tristate "Wondermedia WM8xxx SoC I2C bus support"
|
tristate "Wondermedia WM8xxx SoC I2C bus support"
|
||||||
depends on ARCH_VT8500
|
depends on ARCH_VT8500 || COMPILE_TEST
|
||||||
help
|
help
|
||||||
Say yes if you want to support the I2C bus on Wondermedia 8xxx-series
|
Say yes if you want to support the I2C bus on Wondermedia 8xxx-series
|
||||||
SoCs.
|
SoCs.
|
||||||
|
@ -1142,7 +1147,7 @@ config I2C_XILINX
|
||||||
|
|
||||||
config I2C_XLR
|
config I2C_XLR
|
||||||
tristate "Netlogic XLR and Sigma Designs I2C support"
|
tristate "Netlogic XLR and Sigma Designs I2C support"
|
||||||
depends on CPU_XLR || ARCH_TANGO
|
depends on CPU_XLR || ARCH_TANGO || COMPILE_TEST
|
||||||
help
|
help
|
||||||
This driver enables support for the on-chip I2C interface of
|
This driver enables support for the on-chip I2C interface of
|
||||||
the Netlogic XLR/XLS MIPS processors and Sigma Designs SOCs.
|
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
|
This supports parallel port I2C adapters such as the ones made by
|
||||||
Philips or Velleman, Analog Devices evaluation boards, and more.
|
Philips or Velleman, Analog Devices evaluation boards, and more.
|
||||||
Basically any adapter using the parallel port as an I2C bus with
|
Basically any adapter using the parallel port as an I2C bus with
|
||||||
no extra chipset is supported by this driver, or could be.
|
no extra chipset is supported by this driver, or could be. Please
|
||||||
|
read the file Documentation/i2c/busses/i2c-parport.rst for details.
|
||||||
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.
|
|
||||||
|
|
||||||
This support is also available as a module. If so, the module
|
This support is also available as a module. If so, the module
|
||||||
will be called i2c-parport.
|
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
|
config I2C_ROBOTFUZZ_OSIF
|
||||||
tristate "RobotFuzz Open Source InterFace USB adapter"
|
tristate "RobotFuzz Open Source InterFace USB adapter"
|
||||||
depends on USB
|
depends on USB
|
||||||
|
@ -1328,7 +1299,7 @@ config I2C_ICY
|
||||||
|
|
||||||
config I2C_MLXCPLD
|
config I2C_MLXCPLD
|
||||||
tristate "Mellanox I2C driver"
|
tristate "Mellanox I2C driver"
|
||||||
depends on X86_64
|
depends on X86_64 || COMPILE_TEST
|
||||||
help
|
help
|
||||||
This exposes the Mellanox platform I2C busses to the linux I2C layer
|
This exposes the Mellanox platform I2C busses to the linux I2C layer
|
||||||
for X86 based systems.
|
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_DIOLAN_U2C) += i2c-diolan-u2c.o
|
||||||
obj-$(CONFIG_I2C_DLN2) += i2c-dln2.o
|
obj-$(CONFIG_I2C_DLN2) += i2c-dln2.o
|
||||||
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.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_ROBOTFUZZ_OSIF) += i2c-robotfuzz-osif.o
|
||||||
obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o
|
obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o
|
||||||
obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.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_max_div = 5,
|
||||||
.clk_offset = 3,
|
.clk_offset = 3,
|
||||||
.has_unre_flag = true,
|
.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 = {
|
static struct at91_twi_pdata at91sam9261_config = {
|
||||||
.clk_max_div = 5,
|
.clk_max_div = 5,
|
||||||
.clk_offset = 4,
|
.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 = {
|
static struct at91_twi_pdata at91sam9260_config = {
|
||||||
.clk_max_div = 7,
|
.clk_max_div = 7,
|
||||||
.clk_offset = 4,
|
.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 = {
|
static struct at91_twi_pdata at91sam9g20_config = {
|
||||||
.clk_max_div = 7,
|
.clk_max_div = 7,
|
||||||
.clk_offset = 4,
|
.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 = {
|
static struct at91_twi_pdata at91sam9g10_config = {
|
||||||
.clk_max_div = 7,
|
.clk_max_div = 7,
|
||||||
.clk_offset = 4,
|
.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[] = {
|
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 = {
|
static struct at91_twi_pdata at91sam9x5_config = {
|
||||||
.clk_max_div = 7,
|
.clk_max_div = 7,
|
||||||
.clk_offset = 4,
|
.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 = {
|
static struct at91_twi_pdata sama5d4_config = {
|
||||||
.clk_max_div = 7,
|
.clk_max_div = 7,
|
||||||
.clk_offset = 4,
|
.clk_offset = 4,
|
||||||
.has_unre_flag = false,
|
|
||||||
.has_alt_cmd = false,
|
|
||||||
.has_hold_field = true,
|
.has_hold_field = true,
|
||||||
.has_dig_filtr = true,
|
.has_dig_filtr = true,
|
||||||
.has_adv_dig_filtr = false,
|
|
||||||
.has_ana_filtr = false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct at91_twi_pdata sama5d2_config = {
|
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);
|
isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
|
||||||
cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
|
cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
|
||||||
|
id->err_status = 0;
|
||||||
|
|
||||||
/* Handling nack and arbitration lost interrupt */
|
/* Handling nack and arbitration lost interrupt */
|
||||||
if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) {
|
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)
|
!id->bus_hold_flag)
|
||||||
cdns_i2c_clear_bus_hold(id);
|
cdns_i2c_clear_bus_hold(id);
|
||||||
|
|
||||||
*(id->p_recv_buf)++ =
|
if (id->recv_count > 0) {
|
||||||
cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
|
*(id->p_recv_buf)++ =
|
||||||
id->recv_count--;
|
cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
|
||||||
id->curr_recv_count--;
|
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))
|
if (cdns_is_holdquirk(id, hold_quirk))
|
||||||
break;
|
break;
|
||||||
|
@ -342,7 +350,7 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update the status for errors */
|
/* 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)
|
if (id->err_status)
|
||||||
status = IRQ_HANDLED;
|
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);
|
cdns_i2c_writereg(regval, CDNS_I2C_CR_OFFSET);
|
||||||
/* Update the transfercount register to zero */
|
/* Update the transfercount register to zero */
|
||||||
cdns_i2c_writereg(0, CDNS_I2C_XFER_SIZE_OFFSET);
|
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);
|
regval = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
|
||||||
cdns_i2c_writereg(regval, CDNS_I2C_ISR_OFFSET);
|
cdns_i2c_writereg(regval, CDNS_I2C_ISR_OFFSET);
|
||||||
/* Clear the status register */
|
/* 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);
|
id->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
if (IS_ERR(id->clk)) {
|
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);
|
return PTR_ERR(id->clk);
|
||||||
}
|
}
|
||||||
ret = clk_prepare_enable(id->clk);
|
ret = clk_prepare_enable(id->clk);
|
||||||
if (ret)
|
if (ret)
|
||||||
dev_err(&pdev->dev, "Unable to enable clock.\n");
|
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_set_autosuspend_delay(id->dev, CNDS_I2C_PM_TIMEOUT);
|
||||||
pm_runtime_use_autosuspend(id->dev);
|
pm_runtime_use_autosuspend(id->dev);
|
||||||
pm_runtime_set_active(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;
|
id->clk_rate_change_nb.notifier_call = cdns_i2c_clk_notifier_cb;
|
||||||
if (clk_notifier_register(id->clk, &id->clk_rate_change_nb))
|
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:
|
err_clk_dis:
|
||||||
clk_disable_unprepare(id->clk);
|
clk_disable_unprepare(id->clk);
|
||||||
pm_runtime_set_suspended(&pdev->dev);
|
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
pm_runtime_set_suspended(&pdev->dev);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -997,10 +1006,13 @@ static int cdns_i2c_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct cdns_i2c *id = platform_get_drvdata(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);
|
i2c_del_adapter(&id->adap);
|
||||||
clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
|
clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
|
||||||
clk_disable_unprepare(id->clk);
|
clk_disable_unprepare(id->clk);
|
||||||
pm_runtime_disable(&pdev->dev);
|
|
||||||
|
|
||||||
return 0;
|
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)) {
|
if (acpi_dev_present("INT33FE", NULL, -1)) {
|
||||||
board_info.irq = adap->client_irq;
|
board_info.irq = adap->client_irq;
|
||||||
adap->client = i2c_new_device(&adap->adapter, &board_info);
|
adap->client = i2c_new_client_device(&adap->adapter, &board_info);
|
||||||
if (!adap->client) {
|
if (IS_ERR(adap->client)) {
|
||||||
ret = -ENOMEM;
|
ret = PTR_ERR(adap->client);
|
||||||
goto del_adapter;
|
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.parent = &pdev->dev;
|
||||||
bus->adap.dev.of_node = pdev->dev.of_node;
|
bus->adap.dev.of_node = pdev->dev.of_node;
|
||||||
bus->adap.retries = I2C_MAX_RETRIES;
|
bus->adap.retries = I2C_MAX_RETRIES;
|
||||||
|
ACPI_COMPANION_SET(&bus->adap.dev, ACPI_COMPANION(&pdev->dev));
|
||||||
|
|
||||||
err = i2c_add_adapter(&bus->adap);
|
err = i2c_add_adapter(&bus->adap);
|
||||||
if (err)
|
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);
|
MODULE_DEVICE_TABLE(of, cros_ec_i2c_of_match);
|
||||||
|
|
||||||
static const struct acpi_device_id cros_ec_i2c_tunnel_acpi_id[] = {
|
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);
|
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);
|
tmp |= (SMMR_MODE0 | SMMR_MODE1);
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@
|
||||||
* Elkhart Lake (PCH) 0x4b23 32 hard yes yes yes
|
* Elkhart Lake (PCH) 0x4b23 32 hard yes yes yes
|
||||||
* Tiger Lake-LP (PCH) 0xa0a3 32 hard yes yes yes
|
* Tiger Lake-LP (PCH) 0xa0a3 32 hard yes yes yes
|
||||||
* Jasper Lake (SOC) 0x4da3 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:
|
* Features supported by this driver:
|
||||||
* Software PEC no
|
* Software PEC no
|
||||||
|
@ -244,6 +245,7 @@
|
||||||
#define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS 0xa223
|
#define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS 0xa223
|
||||||
#define PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS 0xa2a3
|
#define PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS 0xa2a3
|
||||||
#define PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS 0xa323
|
#define PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS 0xa323
|
||||||
|
#define PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS 0xa3a3
|
||||||
|
|
||||||
struct i801_mux_config {
|
struct i801_mux_config {
|
||||||
char *gpio_chip;
|
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_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_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_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_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_TIGERLAKE_LP_SMBUS) },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_JASPER_LAKE_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));
|
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||||
info.addr = dmi_devices[i].i2c_addr;
|
info.addr = dmi_devices[i].i2c_addr;
|
||||||
strlcpy(info.type, dmi_devices[i].i2c_type, I2C_NAME_SIZE);
|
strlcpy(info.type, dmi_devices[i].i2c_type, I2C_NAME_SIZE);
|
||||||
i2c_new_device(adap, &info);
|
i2c_new_client_device(adap, &info);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1296,7 +1299,7 @@ static void register_dell_lis3lv02d_i2c_device(struct i801_priv *priv)
|
||||||
memset(&info, 0, sizeof(struct i2c_board_info));
|
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||||
info.addr = dell_lis3lv02d_devices[i].i2c_addr;
|
info.addr = dell_lis3lv02d_devices[i].i2c_addr;
|
||||||
strlcpy(info.type, "lis3lv02d", I2C_NAME_SIZE);
|
strlcpy(info.type, "lis3lv02d", I2C_NAME_SIZE);
|
||||||
i2c_new_device(&priv->adapter, &info);
|
i2c_new_client_device(&priv->adapter, &info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Register optional slaves */
|
/* 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));
|
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||||
info.addr = apanel_addr;
|
info.addr = apanel_addr;
|
||||||
strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
|
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"))
|
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_LEWISBURG_SSKU_SMBUS:
|
||||||
case PCI_DEVICE_ID_INTEL_DNV_SMBUS:
|
case PCI_DEVICE_ID_INTEL_DNV_SMBUS:
|
||||||
case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_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_BLOCK_PROC;
|
||||||
priv->features |= FEATURE_I2C_BLOCK_READ;
|
priv->features |= FEATURE_I2C_BLOCK_READ;
|
||||||
priv->features |= FEATURE_IRQ;
|
priv->features |= FEATURE_IRQ;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006 - 2009 Ingenic Semiconductor Inc.
|
* Copyright (C) 2006 - 2009 Ingenic Semiconductor Inc.
|
||||||
* Copyright (C) 2015 Imagination Technologies
|
* Copyright (C) 2015 Imagination Technologies
|
||||||
|
* Copyright (C) 2019 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
|
@ -17,6 +18,7 @@
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
@ -55,6 +57,7 @@
|
||||||
#define JZ4780_I2C_ACKGC 0x98
|
#define JZ4780_I2C_ACKGC 0x98
|
||||||
#define JZ4780_I2C_ENSTA 0x9C
|
#define JZ4780_I2C_ENSTA 0x9C
|
||||||
#define JZ4780_I2C_SDAHD 0xD0
|
#define JZ4780_I2C_SDAHD 0xD0
|
||||||
|
#define X1000_I2C_SDAHD 0x7C
|
||||||
|
|
||||||
#define JZ4780_I2C_CTRL_STPHLD BIT(7)
|
#define JZ4780_I2C_CTRL_STPHLD BIT(7)
|
||||||
#define JZ4780_I2C_CTRL_SLVDIS BIT(6)
|
#define JZ4780_I2C_CTRL_SLVDIS BIT(6)
|
||||||
|
@ -73,6 +76,8 @@
|
||||||
#define JZ4780_I2C_STA_TFNF BIT(1)
|
#define JZ4780_I2C_STA_TFNF BIT(1)
|
||||||
#define JZ4780_I2C_STA_ACT BIT(0)
|
#define JZ4780_I2C_STA_ACT BIT(0)
|
||||||
|
|
||||||
|
#define X1000_I2C_DC_STOP BIT(9)
|
||||||
|
|
||||||
static const char * const jz4780_i2c_abrt_src[] = {
|
static const char * const jz4780_i2c_abrt_src[] = {
|
||||||
"ABRT_7B_ADDR_NOACK",
|
"ABRT_7B_ADDR_NOACK",
|
||||||
"ABRT_10ADDR1_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_I2CFLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1))
|
||||||
|
|
||||||
#define JZ4780_I2C_FIFO_LEN 16
|
#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 JZ4780_I2C_TIMEOUT 300
|
||||||
|
|
||||||
#define BUFSIZE 200
|
#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 {
|
struct jz4780_i2c {
|
||||||
void __iomem *iomem;
|
void __iomem *iomem;
|
||||||
int irq;
|
int irq;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
struct i2c_adapter adap;
|
struct i2c_adapter adap;
|
||||||
|
const struct ingenic_i2c_config *cdata;
|
||||||
|
|
||||||
/* lock to protect rbuf and wbuf between xfer_rd/wr and irq handler */
|
/* lock to protect rbuf and wbuf between xfer_rd/wr and irq handler */
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
|
@ -340,11 +360,18 @@ static int jz4780_i2c_set_speed(struct jz4780_i2c *i2c)
|
||||||
|
|
||||||
if (hold_time >= 0) {
|
if (hold_time >= 0) {
|
||||||
/*i2c hold time enable */
|
/*i2c hold time enable */
|
||||||
hold_time |= JZ4780_I2C_SDAHD_HDENB;
|
if (i2c->cdata->version >= ID_X1000) {
|
||||||
jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, hold_time);
|
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 {
|
} else {
|
||||||
/* disable hold time */
|
/* 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;
|
return 0;
|
||||||
|
@ -359,9 +386,11 @@ static int jz4780_i2c_cleanup(struct jz4780_i2c *i2c)
|
||||||
spin_lock_irqsave(&i2c->lock, flags);
|
spin_lock_irqsave(&i2c->lock, flags);
|
||||||
|
|
||||||
/* can send stop now if need */
|
/* can send stop now if need */
|
||||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
if (i2c->cdata->version < ID_X1000) {
|
||||||
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
/* disable all interrupts first */
|
/* disable all interrupts first */
|
||||||
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0);
|
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);
|
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;
|
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);
|
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;
|
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);
|
jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, rd_left - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intst & JZ4780_I2C_INTST_TXEMP) {
|
if (intst & JZ4780_I2C_INTST_TXEMP) {
|
||||||
if (i2c->is_write == 0) {
|
if (i2c->is_write == 0) {
|
||||||
int cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered;
|
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_cmd_xfered
|
||||||
- i2c->rd_data_xfered);
|
- i2c->rd_data_xfered);
|
||||||
int cmd_to_send = min(cmd_left, max_send);
|
int cmd_to_send = min(cmd_left, max_send);
|
||||||
|
|
||||||
if (i2c->rd_cmd_xfered != 0)
|
if (i2c->rd_cmd_xfered != 0)
|
||||||
cmd_to_send = min(cmd_to_send,
|
cmd_to_send = min(cmd_to_send,
|
||||||
JZ4780_I2C_FIFO_LEN
|
i2c->cdata->fifosize
|
||||||
- TX_LEVEL - 1);
|
- i2c->cdata->tx_level - 1);
|
||||||
|
|
||||||
if (cmd_to_send) {
|
if (cmd_to_send) {
|
||||||
jz4780_i2c_send_rcmd(i2c, cmd_to_send);
|
|
||||||
i2c->rd_cmd_xfered += 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) {
|
if (cmd_left == 0) {
|
||||||
intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM);
|
intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM);
|
||||||
intmsk &= ~JZ4780_I2C_INTM_MTXEMP;
|
intmsk &= ~JZ4780_I2C_INTM_MTXEMP;
|
||||||
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, intmsk);
|
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, intmsk);
|
||||||
|
|
||||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
if (i2c->cdata->version < ID_X1000) {
|
||||||
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
tmp = jz4780_i2c_readw(i2c,
|
||||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
JZ4780_I2C_CTRL);
|
||||||
|
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||||
|
jz4780_i2c_writew(i2c,
|
||||||
|
JZ4780_I2C_CTRL, tmp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsigned short data;
|
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);
|
i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
|
||||||
|
|
||||||
while ((i2c_sta & JZ4780_I2C_STA_TFNF) &&
|
while ((i2c_sta & JZ4780_I2C_STA_TFNF) &&
|
||||||
(i2c->wt_len > 0)) {
|
(i2c->wt_len > 0)) {
|
||||||
i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
|
i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
|
||||||
data = *i2c->wbuf;
|
data = *i2c->wbuf;
|
||||||
data &= ~JZ4780_I2C_DC_READ;
|
data &= ~JZ4780_I2C_DC_READ;
|
||||||
jz4780_i2c_writew(i2c, JZ4780_I2C_DC,
|
if ((!i2c->stop_hold) && (i2c->cdata->version >=
|
||||||
data);
|
ID_X1000))
|
||||||
|
data |= X1000_I2C_DC_STOP;
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_DC, data);
|
||||||
i2c->wbuf++;
|
i2c->wbuf++;
|
||||||
i2c->wt_len--;
|
i2c->wt_len--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i2c->wt_len == 0) {
|
if (i2c->wt_len == 0) {
|
||||||
if (!i2c->stop_hold) {
|
if ((!i2c->stop_hold) && (i2c->cdata->version <
|
||||||
|
ID_X1000)) {
|
||||||
tmp = jz4780_i2c_readw(i2c,
|
tmp = jz4780_i2c_readw(i2c,
|
||||||
JZ4780_I2C_CTRL);
|
JZ4780_I2C_CTRL);
|
||||||
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL,
|
jz4780_i2c_writew(i2c,
|
||||||
tmp);
|
JZ4780_I2C_CTRL, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
jz4780_i2c_trans_done(i2c);
|
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_data_xfered = 0;
|
||||||
i2c->rd_cmd_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);
|
jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, len - 1);
|
||||||
else
|
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_writew(i2c, JZ4780_I2C_INTM,
|
||||||
JZ4780_I2C_INTM_MRXFL | JZ4780_I2C_INTM_MTXEMP
|
JZ4780_I2C_INTM_MRXFL | JZ4780_I2C_INTM_MTXEMP
|
||||||
| JZ4780_I2C_INTM_MTXABT | JZ4780_I2C_INTM_MRXOF);
|
| JZ4780_I2C_INTM_MTXABT | JZ4780_I2C_INTM_MRXOF);
|
||||||
|
|
||||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
if (i2c->cdata->version < ID_X1000) {
|
||||||
tmp |= JZ4780_I2C_CTRL_STPHLD;
|
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
tmp |= JZ4780_I2C_CTRL_STPHLD;
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&i2c->lock, flags);
|
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->wbuf = buf;
|
||||||
i2c->wt_len = len;
|
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_writew(i2c, JZ4780_I2C_INTM, JZ4780_I2C_INTM_MTXEMP
|
||||||
| JZ4780_I2C_INTM_MTXABT);
|
| JZ4780_I2C_INTM_MTXABT);
|
||||||
|
|
||||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
if (i2c->cdata->version < ID_X1000) {
|
||||||
tmp |= JZ4780_I2C_CTRL_STPHLD;
|
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
tmp |= JZ4780_I2C_CTRL_STPHLD;
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&i2c->lock, flags);
|
spin_unlock_irqrestore(&i2c->lock, flags);
|
||||||
|
|
||||||
|
@ -716,8 +767,25 @@ static const struct i2c_algorithm jz4780_i2c_algorithm = {
|
||||||
.functionality = jz4780_i2c_functionality,
|
.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[] = {
|
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 */ }
|
{ /* sentinel */ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, jz4780_i2c_of_matches);
|
MODULE_DEVICE_TABLE(of, jz4780_i2c_of_matches);
|
||||||
|
@ -734,6 +802,12 @@ static int jz4780_i2c_probe(struct platform_device *pdev)
|
||||||
if (!i2c)
|
if (!i2c)
|
||||||
return -ENOMEM;
|
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.owner = THIS_MODULE;
|
||||||
i2c->adap.algo = &jz4780_i2c_algorithm;
|
i2c->adap.algo = &jz4780_i2c_algorithm;
|
||||||
i2c->adap.algo_data = i2c;
|
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);
|
dev_info(&pdev->dev, "Bus frequency is %d KHz\n", i2c->speed);
|
||||||
|
|
||||||
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
if (i2c->cdata->version < ID_X1000) {
|
||||||
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
|
||||||
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
tmp &= ~JZ4780_I2C_CTRL_STPHLD;
|
||||||
|
jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0x0);
|
jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0x0);
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <linux/iopoll.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.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);
|
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)
|
static irqreturn_t meson_i2c_irq(int irqno, void *dev_id)
|
||||||
{
|
{
|
||||||
struct meson_i2c *i2c = 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;
|
return IRQ_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctrl & REG_CTRL_ERROR) {
|
meson_i2c_transfer_complete(i2c, ctrl);
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i2c->state == STATE_READ && i2c->count)
|
if (i2c->state == STATE_IDLE) {
|
||||||
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;
|
|
||||||
complete(&i2c->done);
|
complete(&i2c->done);
|
||||||
goto out;
|
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,
|
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;
|
unsigned long time_left, flags;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
u32 ctrl;
|
||||||
|
|
||||||
i2c->msg = msg;
|
i2c->msg = msg;
|
||||||
i2c->last = last;
|
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;
|
i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
|
||||||
meson_i2c_prepare_xfer(i2c);
|
meson_i2c_prepare_xfer(i2c);
|
||||||
reinit_completion(&i2c->done);
|
|
||||||
|
if (!atomic)
|
||||||
|
reinit_completion(&i2c->done);
|
||||||
|
|
||||||
/* Start the transfer */
|
/* Start the transfer */
|
||||||
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, REG_CTRL_START);
|
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, REG_CTRL_START);
|
||||||
|
|
||||||
time_left = msecs_to_jiffies(I2C_TIMEOUT_MS);
|
if (atomic) {
|
||||||
time_left = wait_for_completion_timeout(&i2c->done, time_left);
|
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
|
* 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);
|
spin_lock_irqsave(&i2c->lock, flags);
|
||||||
|
|
||||||
|
if (atomic && !ret)
|
||||||
|
meson_i2c_transfer_complete(i2c, ctrl);
|
||||||
|
|
||||||
/* Abort any active operation */
|
/* Abort any active operation */
|
||||||
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0);
|
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0);
|
||||||
|
|
||||||
if (!time_left) {
|
if (ret)
|
||||||
i2c->state = STATE_IDLE;
|
i2c->state = STATE_IDLE;
|
||||||
ret = -ETIMEDOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i2c->error)
|
if (i2c->error)
|
||||||
ret = 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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
static int meson_i2c_xfer_messages(struct i2c_adapter *adap,
|
||||||
int num)
|
struct i2c_msg *msgs, int num, bool atomic)
|
||||||
{
|
{
|
||||||
struct meson_i2c *i2c = adap->algo_data;
|
struct meson_i2c *i2c = adap->algo_data;
|
||||||
int i, ret = 0;
|
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);
|
clk_enable(i2c->clk);
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
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)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -350,14 +370,27 @@ static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||||
return ret ?: i;
|
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)
|
static u32 meson_i2c_func(struct i2c_adapter *adap)
|
||||||
{
|
{
|
||||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct i2c_algorithm meson_i2c_algorithm = {
|
static const struct i2c_algorithm meson_i2c_algorithm = {
|
||||||
.master_xfer = meson_i2c_xfer,
|
.master_xfer = meson_i2c_xfer,
|
||||||
.functionality = meson_i2c_func,
|
.master_xfer_atomic = meson_i2c_xfer_atomic,
|
||||||
|
.functionality = meson_i2c_func,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int meson_i2c_probe(struct platform_device *pdev)
|
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->addr = 0x8;
|
||||||
i2cd->gpu_ccgx_ucsi->irq = irq;
|
i2cd->gpu_ccgx_ucsi->irq = irq;
|
||||||
i2cd->gpu_ccgx_ucsi->properties = ccgx_props;
|
i2cd->gpu_ccgx_ucsi->properties = ccgx_props;
|
||||||
i2cd->ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
|
i2cd->ccgx_client = i2c_new_client_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
|
||||||
if (!i2cd->ccgx_client)
|
if (IS_ERR(i2cd->ccgx_client))
|
||||||
return -ENODEV;
|
return PTR_ERR(i2cd->ccgx_client);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -731,7 +731,7 @@ static int ocores_i2c_probe(struct platform_device *pdev)
|
||||||
/* add in known devices to the bus */
|
/* add in known devices to the bus */
|
||||||
if (pdata) {
|
if (pdata) {
|
||||||
for (i = 0; i < pdata->num_devices; i++)
|
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;
|
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/slab.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/mutex.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 ------------------------------------------------------ */
|
/* ----- Device list ------------------------------------------------------ */
|
||||||
|
|
||||||
|
@ -40,9 +123,30 @@ struct i2c_par {
|
||||||
|
|
||||||
static LIST_HEAD(adapter_list);
|
static LIST_HEAD(adapter_list);
|
||||||
static DEFINE_MUTEX(adapter_list_lock);
|
static DEFINE_MUTEX(adapter_list_lock);
|
||||||
|
|
||||||
#define MAX_DEVICE 4
|
#define MAX_DEVICE 4
|
||||||
static int parport[MAX_DEVICE] = {0, -1, -1, -1};
|
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 ----------------------------------- */
|
/* ----- Low-level parallel port access ----------------------------------- */
|
||||||
|
|
||||||
|
@ -311,12 +415,5 @@ MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
|
||||||
MODULE_DESCRIPTION("I2C bus over parallel port");
|
MODULE_DESCRIPTION("I2C bus over parallel port");
|
||||||
MODULE_LICENSE("GPL");
|
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_init(i2c_parport_init);
|
||||||
module_exit(i2c_parport_exit);
|
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),
|
if (!request_mem_region(res->start, resource_size(res),
|
||||||
pldev->name)) {
|
pldev->name)) {
|
||||||
dev_err(&pldev->dev,
|
dev_err(&pldev->dev,
|
||||||
"Unable to get memory/io address region 0x%08x\n",
|
"Unable to get memory/io address region %pap\n",
|
||||||
res->start);
|
&res->start);
|
||||||
rc = -EBUSY;
|
rc = -EBUSY;
|
||||||
goto ret_err;
|
goto ret_err;
|
||||||
}
|
}
|
||||||
|
@ -285,7 +285,7 @@ static int pmcmsptwi_probe(struct platform_device *pldev)
|
||||||
resource_size(res));
|
resource_size(res));
|
||||||
if (!pmcmsptwi_data.iobase) {
|
if (!pmcmsptwi_data.iobase) {
|
||||||
dev_err(&pldev->dev,
|
dev_err(&pldev->dev,
|
||||||
"Unable to ioremap address 0x%08x\n", res->start);
|
"Unable to ioremap address %pap\n", &res->start);
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
goto ret_unreserve;
|
goto ret_unreserve;
|
||||||
}
|
}
|
||||||
|
|
|
@ -734,8 +734,8 @@ static int i2c_pnx_probe(struct platform_device *pdev)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_clock;
|
goto out_clock;
|
||||||
|
|
||||||
dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n",
|
dev_dbg(&pdev->dev, "%s: Master at %pap, irq %d.\n",
|
||||||
alg_data->adapter.name, res->start, alg_data->irq);
|
alg_data->adapter.name, &res->start, alg_data->irq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -240,8 +240,8 @@ static void i2c_powermac_create_one(struct i2c_adapter *adap,
|
||||||
|
|
||||||
strncpy(info.type, type, sizeof(info.type));
|
strncpy(info.type, type, sizeof(info.type));
|
||||||
info.addr = addr;
|
info.addr = addr;
|
||||||
newdev = i2c_new_device(adap, &info);
|
newdev = i2c_new_client_device(adap, &info);
|
||||||
if (!newdev)
|
if (IS_ERR(newdev))
|
||||||
dev_err(&adap->dev,
|
dev_err(&adap->dev,
|
||||||
"i2c-powermac: Failure to register missing %s\n",
|
"i2c-powermac: Failure to register missing %s\n",
|
||||||
type);
|
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.irq = irq_of_parse_and_map(node, 0);
|
||||||
info.of_node = of_node_get(node);
|
info.of_node = of_node_get(node);
|
||||||
|
|
||||||
newdev = i2c_new_device(adap, &info);
|
newdev = i2c_new_client_device(adap, &info);
|
||||||
if (!newdev) {
|
if (IS_ERR(newdev)) {
|
||||||
dev_err(&adap->dev, "i2c-powermac: Failure to register"
|
dev_err(&adap->dev, "i2c-powermac: Failure to register"
|
||||||
" %pOF\n", node);
|
" %pOF\n", node);
|
||||||
of_node_put(node);
|
of_node_put(node);
|
||||||
|
|
|
@ -168,6 +168,24 @@
|
||||||
|
|
||||||
#define STM32F7_AUTOSUSPEND_DELAY (HZ / 100)
|
#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
|
* struct stm32f7_i2c_spec - private i2c specification timing
|
||||||
* @rate: I2C bus speed (Hz)
|
* @rate: I2C bus speed (Hz)
|
||||||
|
@ -276,6 +294,7 @@ struct stm32f7_i2c_msg {
|
||||||
* @timing: I2C computed timings
|
* @timing: I2C computed timings
|
||||||
* @slave: list of slave devices registered on the I2C bus
|
* @slave: list of slave devices registered on the I2C bus
|
||||||
* @slave_running: slave device currently used
|
* @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
|
* @slave_dir: transfer direction for the current slave device
|
||||||
* @master_mode: boolean to know in which mode the I2C is running (master or
|
* @master_mode: boolean to know in which mode the I2C is running (master or
|
||||||
* slave)
|
* slave)
|
||||||
|
@ -298,6 +317,7 @@ struct stm32f7_i2c_dev {
|
||||||
struct stm32f7_i2c_timings timing;
|
struct stm32f7_i2c_timings timing;
|
||||||
struct i2c_client *slave[STM32F7_I2C_MAX_SLAVE];
|
struct i2c_client *slave[STM32F7_I2C_MAX_SLAVE];
|
||||||
struct i2c_client *slave_running;
|
struct i2c_client *slave_running;
|
||||||
|
struct stm32f7_i2c_regs backup_regs;
|
||||||
u32 slave_dir;
|
u32 slave_dir;
|
||||||
bool master_mode;
|
bool master_mode;
|
||||||
struct stm32_i2c_dma *dma;
|
struct stm32_i2c_dma *dma;
|
||||||
|
@ -2027,8 +2047,7 @@ static int stm32f7_i2c_remove(struct platform_device *pdev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
static int __maybe_unused stm32f7_i2c_runtime_suspend(struct device *dev)
|
||||||
static int stm32f7_i2c_runtime_suspend(struct device *dev)
|
|
||||||
{
|
{
|
||||||
struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(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;
|
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);
|
struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -2053,11 +2072,101 @@ static int stm32f7_i2c_runtime_resume(struct device *dev)
|
||||||
|
|
||||||
return 0;
|
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 = {
|
static const struct dev_pm_ops stm32f7_i2c_pm_ops = {
|
||||||
SET_RUNTIME_PM_OPS(stm32f7_i2c_runtime_suspend,
|
SET_RUNTIME_PM_OPS(stm32f7_i2c_runtime_suspend,
|
||||||
stm32f7_i2c_runtime_resume, NULL)
|
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[] = {
|
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);
|
"Attempt: %d\n", i+1);
|
||||||
|
|
||||||
dev_err(&dev->pdev->dev, "base address = "
|
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);
|
(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)) {
|
if (!strncmp(adapter->name, "TAOS TSL2550 EVM", 16)) {
|
||||||
dev_info(&adapter->dev, "Instantiating device %s at 0x%02x\n",
|
dev_info(&adapter->dev, "Instantiating device %s at 0x%02x\n",
|
||||||
tsl2550_info.type, tsl2550_info.addr);
|
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,
|
static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
|
||||||
|
|
|
@ -16,7 +16,9 @@
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/iopoll.h>
|
#include <linux/iopoll.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/ktime.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/pinctrl/consumer.h>
|
#include <linux/pinctrl/consumer.h>
|
||||||
|
@ -129,11 +131,12 @@
|
||||||
#define I2C_PACKET_HEADER_SIZE 12
|
#define I2C_PACKET_HEADER_SIZE 12
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Upto I2C_PIO_MODE_MAX_LEN bytes, controller will use PIO mode,
|
* I2C Controller will use PIO mode for transfers up to 32 bytes in order to
|
||||||
* above this, controller will use DMA to fill FIFO.
|
* avoid DMA overhead, otherwise external APB DMA controller will be used.
|
||||||
* MAX PIO len is 20 bytes excluding packet header.
|
* 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.
|
* 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
|
* @base_phys: physical base address of the I2C controller
|
||||||
* @cont_id: I2C controller ID, used for packet header
|
* @cont_id: I2C controller ID, used for packet header
|
||||||
* @irq: IRQ number of transfer complete interrupt
|
* @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
|
* @is_dvc: identifies the DVC I2C controller, has a different register layout
|
||||||
* @msg_complete: transfer completion notifier
|
* @msg_complete: transfer completion notifier
|
||||||
* @msg_err: error code for completed message
|
* @msg_err: error code for completed message
|
||||||
|
@ -240,7 +242,6 @@ struct tegra_i2c_hw_feature {
|
||||||
* @bus_clk_rate: current I2C bus clock rate
|
* @bus_clk_rate: current I2C bus clock rate
|
||||||
* @clk_divisor_non_hs_mode: clock divider for non-high-speed modes
|
* @clk_divisor_non_hs_mode: clock divider for non-high-speed modes
|
||||||
* @is_multimaster_mode: track if I2C controller is in multi-master mode
|
* @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
|
* @tx_dma_chan: DMA transmit channel
|
||||||
* @rx_dma_chan: DMA receive channel
|
* @rx_dma_chan: DMA receive channel
|
||||||
* @dma_phys: handle to DMA resources
|
* @dma_phys: handle to DMA resources
|
||||||
|
@ -248,6 +249,7 @@ struct tegra_i2c_hw_feature {
|
||||||
* @dma_buf_size: DMA buffer size
|
* @dma_buf_size: DMA buffer size
|
||||||
* @is_curr_dma_xfer: indicates active DMA transfer
|
* @is_curr_dma_xfer: indicates active DMA transfer
|
||||||
* @dma_complete: DMA completion notifier
|
* @dma_complete: DMA completion notifier
|
||||||
|
* @is_curr_atomic_xfer: indicates active atomic transfer
|
||||||
*/
|
*/
|
||||||
struct tegra_i2c_dev {
|
struct tegra_i2c_dev {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
@ -260,7 +262,6 @@ struct tegra_i2c_dev {
|
||||||
phys_addr_t base_phys;
|
phys_addr_t base_phys;
|
||||||
int cont_id;
|
int cont_id;
|
||||||
int irq;
|
int irq;
|
||||||
bool irq_disabled;
|
|
||||||
int is_dvc;
|
int is_dvc;
|
||||||
struct completion msg_complete;
|
struct completion msg_complete;
|
||||||
int msg_err;
|
int msg_err;
|
||||||
|
@ -270,8 +271,6 @@ struct tegra_i2c_dev {
|
||||||
u32 bus_clk_rate;
|
u32 bus_clk_rate;
|
||||||
u16 clk_divisor_non_hs_mode;
|
u16 clk_divisor_non_hs_mode;
|
||||||
bool is_multimaster_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 *tx_dma_chan;
|
||||||
struct dma_chan *rx_dma_chan;
|
struct dma_chan *rx_dma_chan;
|
||||||
dma_addr_t dma_phys;
|
dma_addr_t dma_phys;
|
||||||
|
@ -279,17 +278,18 @@ struct tegra_i2c_dev {
|
||||||
unsigned int dma_buf_size;
|
unsigned int dma_buf_size;
|
||||||
bool is_curr_dma_xfer;
|
bool is_curr_dma_xfer;
|
||||||
struct completion dma_complete;
|
struct completion dma_complete;
|
||||||
|
bool is_curr_atomic_xfer;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
|
static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
|
||||||
unsigned long reg)
|
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)
|
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,
|
static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
|
||||||
unsigned long reg)
|
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 */
|
/* Read back register to make sure that register writes completed */
|
||||||
if (reg != I2C_TX_FIFO)
|
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)
|
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,
|
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);
|
reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_CONFIG_LOAD);
|
||||||
addr = i2c_dev->base + reg_offset;
|
addr = i2c_dev->base + reg_offset;
|
||||||
i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD);
|
i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD);
|
||||||
if (in_interrupt())
|
|
||||||
err = readl_poll_timeout_atomic(addr, val, val == 0,
|
if (i2c_dev->is_curr_atomic_xfer)
|
||||||
1000,
|
err = readl_relaxed_poll_timeout_atomic(
|
||||||
I2C_CONFIG_LOAD_TIMEOUT);
|
addr, val, val == 0, 1000,
|
||||||
|
I2C_CONFIG_LOAD_TIMEOUT);
|
||||||
else
|
else
|
||||||
err = readl_poll_timeout(addr, val, val == 0, 1000,
|
err = readl_relaxed_poll_timeout(
|
||||||
I2C_CONFIG_LOAD_TIMEOUT);
|
addr, val, val == 0, 1000,
|
||||||
|
I2C_CONFIG_LOAD_TIMEOUT);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_warn(i2c_dev->dev,
|
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)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (i2c_dev->irq_disabled) {
|
|
||||||
i2c_dev->irq_disabled = false;
|
|
||||||
enable_irq(i2c_dev->irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
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);
|
status = i2c_readl(i2c_dev, I2C_INT_STATUS);
|
||||||
|
|
||||||
spin_lock(&i2c_dev->xfer_lock);
|
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
|
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_PACKET_TRANSFER_STATUS),
|
||||||
i2c_readl(i2c_dev, I2C_STATUS),
|
i2c_readl(i2c_dev, I2C_STATUS),
|
||||||
i2c_readl(i2c_dev, I2C_CNFG));
|
i2c_readl(i2c_dev, I2C_CNFG));
|
||||||
i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT;
|
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;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -925,7 +916,6 @@ err:
|
||||||
|
|
||||||
complete(&i2c_dev->msg_complete);
|
complete(&i2c_dev->msg_complete);
|
||||||
done:
|
done:
|
||||||
spin_unlock(&i2c_dev->xfer_lock);
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -999,6 +989,64 @@ out:
|
||||||
i2c_writel(i2c_dev, val, reg);
|
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)
|
static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
|
||||||
{
|
{
|
||||||
struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(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);
|
i2c_writel(i2c_dev, reg, I2C_BUS_CLEAR_CNFG);
|
||||||
tegra_i2c_unmask_irq(i2c_dev, I2C_INT_BUS_CLR_DONE);
|
tegra_i2c_unmask_irq(i2c_dev, I2C_INT_BUS_CLR_DONE);
|
||||||
|
|
||||||
time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
|
time_left = tegra_i2c_wait_completion_timeout(
|
||||||
msecs_to_jiffies(50));
|
i2c_dev, &i2c_dev->msg_complete, 50);
|
||||||
if (time_left == 0) {
|
if (time_left == 0) {
|
||||||
dev_err(i2c_dev->dev, "timed out for bus clear\n");
|
dev_err(i2c_dev->dev, "timed out for bus clear\n");
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
|
@ -1044,7 +1092,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
||||||
u32 packet_header;
|
u32 packet_header;
|
||||||
u32 int_mask;
|
u32 int_mask;
|
||||||
unsigned long time_left;
|
unsigned long time_left;
|
||||||
unsigned long flags;
|
|
||||||
size_t xfer_size;
|
size_t xfer_size;
|
||||||
u32 *buffer = NULL;
|
u32 *buffer = NULL;
|
||||||
int err = 0;
|
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 = msg->len + I2C_PACKET_HEADER_SIZE;
|
||||||
|
|
||||||
xfer_size = ALIGN(xfer_size, BYTES_PER_FIFO_WORD);
|
xfer_size = ALIGN(xfer_size, BYTES_PER_FIFO_WORD);
|
||||||
i2c_dev->is_curr_dma_xfer = (xfer_size > I2C_PIO_MODE_MAX_LEN) &&
|
i2c_dev->is_curr_dma_xfer = (xfer_size > I2C_PIO_MODE_PREFERRED_LEN) &&
|
||||||
i2c_dev->dma_buf;
|
i2c_dev->dma_buf &&
|
||||||
|
!i2c_dev->is_curr_atomic_xfer;
|
||||||
tegra_i2c_config_fifo_trig(i2c_dev, xfer_size);
|
tegra_i2c_config_fifo_trig(i2c_dev, xfer_size);
|
||||||
dma = i2c_dev->is_curr_dma_xfer;
|
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,
|
xfer_time += DIV_ROUND_CLOSEST(((xfer_size * 9) + 2) * MSEC_PER_SEC,
|
||||||
i2c_dev->bus_clk_rate);
|
i2c_dev->bus_clk_rate);
|
||||||
spin_lock_irqsave(&i2c_dev->xfer_lock, flags);
|
|
||||||
|
|
||||||
int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
|
int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
|
||||||
tegra_i2c_unmask_irq(i2c_dev, int_mask);
|
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,
|
dev_err(i2c_dev->dev,
|
||||||
"starting RX DMA failed, err %d\n",
|
"starting RX DMA failed, err %d\n",
|
||||||
err);
|
err);
|
||||||
goto unlock;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -1149,7 +1196,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
||||||
dev_err(i2c_dev->dev,
|
dev_err(i2c_dev->dev,
|
||||||
"starting TX DMA failed, err %d\n",
|
"starting TX DMA failed, err %d\n",
|
||||||
err);
|
err);
|
||||||
goto unlock;
|
return err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tegra_i2c_fill_tx_fifo(i2c_dev);
|
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",
|
dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n",
|
||||||
i2c_readl(i2c_dev, I2C_INT_MASK));
|
i2c_readl(i2c_dev, I2C_INT_MASK));
|
||||||
|
|
||||||
unlock:
|
|
||||||
spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags);
|
|
||||||
|
|
||||||
if (dma) {
|
if (dma) {
|
||||||
if (err)
|
time_left = tegra_i2c_wait_completion_timeout(
|
||||||
return err;
|
i2c_dev, &i2c_dev->dma_complete, xfer_time);
|
||||||
|
|
||||||
time_left = wait_for_completion_timeout(&i2c_dev->dma_complete,
|
dmaengine_terminate_sync(i2c_dev->msg_read ?
|
||||||
msecs_to_jiffies(xfer_time));
|
i2c_dev->rx_dma_chan :
|
||||||
if (time_left == 0) {
|
i2c_dev->tx_dma_chan);
|
||||||
|
|
||||||
|
if (!time_left && !completion_done(&i2c_dev->dma_complete)) {
|
||||||
dev_err(i2c_dev->dev, "DMA transfer timeout\n");
|
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);
|
tegra_i2c_init(i2c_dev, true);
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
@ -1195,20 +1238,15 @@ unlock:
|
||||||
memcpy(i2c_dev->msg_buf, i2c_dev->dma_buf,
|
memcpy(i2c_dev->msg_buf, i2c_dev->dma_buf,
|
||||||
msg->len);
|
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,
|
time_left = tegra_i2c_wait_completion_timeout(
|
||||||
msecs_to_jiffies(xfer_time));
|
i2c_dev, &i2c_dev->msg_complete, xfer_time);
|
||||||
|
|
||||||
tegra_i2c_mask_irq(i2c_dev, int_mask);
|
tegra_i2c_mask_irq(i2c_dev, int_mask);
|
||||||
|
|
||||||
if (time_left == 0) {
|
if (time_left == 0) {
|
||||||
dev_err(i2c_dev->dev, "i2c transfer timed out\n");
|
dev_err(i2c_dev->dev, "i2c transfer timed out\n");
|
||||||
|
|
||||||
tegra_i2c_init(i2c_dev, true);
|
tegra_i2c_init(i2c_dev, true);
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
@ -1270,6 +1308,19 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
||||||
return ret ?: i;
|
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)
|
static u32 tegra_i2c_func(struct i2c_adapter *adap)
|
||||||
{
|
{
|
||||||
struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(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 = {
|
static const struct i2c_algorithm tegra_i2c_algo = {
|
||||||
.master_xfer = tegra_i2c_xfer,
|
.master_xfer = tegra_i2c_xfer,
|
||||||
.functionality = tegra_i2c_func,
|
.master_xfer_atomic = tegra_i2c_xfer_atomic,
|
||||||
|
.functionality = tegra_i2c_func,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* payload size is only 12 bit */
|
/* payload size is only 12 bit */
|
||||||
|
@ -1568,7 +1620,6 @@ static int tegra_i2c_probe(struct platform_device *pdev)
|
||||||
I2C_PACKET_HEADER_SIZE;
|
I2C_PACKET_HEADER_SIZE;
|
||||||
init_completion(&i2c_dev->msg_complete);
|
init_completion(&i2c_dev->msg_complete);
|
||||||
init_completion(&i2c_dev->dma_complete);
|
init_completion(&i2c_dev->dma_complete);
|
||||||
spin_lock_init(&i2c_dev->xfer_lock);
|
|
||||||
|
|
||||||
if (!i2c_dev->hw->has_single_clk_source) {
|
if (!i2c_dev->hw->has_single_clk_source) {
|
||||||
fast_clk = devm_clk_get(&pdev->dev, "fast-clk");
|
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;
|
goto unprepare_fast_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pm_runtime_irq_safe(&pdev->dev);
|
||||||
pm_runtime_enable(&pdev->dev);
|
pm_runtime_enable(&pdev->dev);
|
||||||
if (!pm_runtime_enabled(&pdev->dev)) {
|
if (!pm_runtime_enabled(&pdev->dev)) {
|
||||||
ret = tegra_i2c_runtime_resume(&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;
|
goto release_dma;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
irq_set_status_flags(i2c_dev->irq, IRQ_NOAUTOEN);
|
||||||
|
|
||||||
ret = devm_request_irq(&pdev->dev, i2c_dev->irq,
|
ret = devm_request_irq(&pdev->dev, i2c_dev->irq,
|
||||||
tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev);
|
tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev);
|
||||||
if (ret) {
|
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) {
|
pmsg->buf, pmsg->len) != pmsg->len) {
|
||||||
dev_err(&adapter->dev,
|
dev_err(&adapter->dev,
|
||||||
"failure reading data\n");
|
"failure reading data\n");
|
||||||
ret = -EREMOTEIO;
|
ret = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
} else {
|
} 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) {
|
pmsg->buf, pmsg->len) != pmsg->len) {
|
||||||
dev_err(&adapter->dev,
|
dev_err(&adapter->dev,
|
||||||
"failure writing data\n");
|
"failure writing data\n");
|
||||||
ret = -EREMOTEIO;
|
ret = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,13 +102,13 @@ static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
|
||||||
/* read status */
|
/* read status */
|
||||||
if (usb_read(adapter, CMD_GET_STATUS, 0, 0, pstatus, 1) != 1) {
|
if (usb_read(adapter, CMD_GET_STATUS, 0, 0, pstatus, 1) != 1) {
|
||||||
dev_err(&adapter->dev, "failure reading status\n");
|
dev_err(&adapter->dev, "failure reading status\n");
|
||||||
ret = -EREMOTEIO;
|
ret = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(&adapter->dev, " status = %d\n", *pstatus);
|
dev_dbg(&adapter->dev, " status = %d\n", *pstatus);
|
||||||
if (*pstatus == STATUS_ADDRESS_NAK) {
|
if (*pstatus == STATUS_ADDRESS_NAK) {
|
||||||
ret = -EREMOTEIO;
|
ret = -ENXIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,6 +156,8 @@ struct xiic_i2c {
|
||||||
#define XIIC_RESET_MASK 0xAUL
|
#define XIIC_RESET_MASK 0xAUL
|
||||||
|
|
||||||
#define XIIC_PM_TIMEOUT 1000 /* ms */
|
#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
|
* The following constant is used for the device global interrupt enable
|
||||||
* register, to enable all interrupts for the device, this is the only bit
|
* 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_tx_space(i2c) ((i2c)->tx_msg->len - (i2c)->tx_pos)
|
||||||
#define xiic_rx_space(i2c) ((i2c)->rx_msg->len - (i2c)->rx_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);
|
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);
|
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;
|
u8 sr;
|
||||||
|
unsigned long timeout;
|
||||||
|
|
||||||
|
timeout = jiffies + XIIC_I2C_TIMEOUT;
|
||||||
for (sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET);
|
for (sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET);
|
||||||
!(sr & XIIC_SR_RX_FIFO_EMPTY_MASK);
|
!(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);
|
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);
|
xiic_setreg32(i2c, XIIC_RESETR_OFFSET, XIIC_RESET_MASK);
|
||||||
|
|
||||||
/* Set receive Fifo depth to maximum (zero based). */
|
/* 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);
|
xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, XIIC_CR_ENABLE_DEVICE_MASK);
|
||||||
|
|
||||||
/* make sure RX fifo is empty */
|
/* make sure RX fifo is empty */
|
||||||
xiic_clear_rx_fifo(i2c);
|
ret = xiic_clear_rx_fifo(i2c);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* Enable interrupts */
|
/* Enable interrupts */
|
||||||
xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
|
xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
|
||||||
|
|
||||||
xiic_irq_clr_en(i2c, XIIC_INTR_ARB_LOST_MASK);
|
xiic_irq_clr_en(i2c, XIIC_INTR_ARB_LOST_MASK);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xiic_deinit(struct xiic_i2c *i2c)
|
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);
|
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);
|
mutex_unlock(&i2c->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
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->tx_msg = msgs;
|
||||||
i2c->nmsgs = num;
|
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) ||
|
if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
|
||||||
(i2c->state == STATE_DONE), HZ)) {
|
(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);
|
i2c->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
if (IS_ERR(i2c->clk)) {
|
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);
|
return PTR_ERR(i2c->clk);
|
||||||
}
|
}
|
||||||
ret = clk_prepare_enable(i2c->clk);
|
ret = clk_prepare_enable(i2c->clk);
|
||||||
|
@ -769,10 +798,10 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
i2c->dev = &pdev->dev;
|
i2c->dev = &pdev->dev;
|
||||||
pm_runtime_enable(i2c->dev);
|
|
||||||
pm_runtime_set_autosuspend_delay(i2c->dev, XIIC_PM_TIMEOUT);
|
pm_runtime_set_autosuspend_delay(i2c->dev, XIIC_PM_TIMEOUT);
|
||||||
pm_runtime_use_autosuspend(i2c->dev);
|
pm_runtime_use_autosuspend(i2c->dev);
|
||||||
pm_runtime_set_active(i2c->dev);
|
pm_runtime_set_active(i2c->dev);
|
||||||
|
pm_runtime_enable(i2c->dev);
|
||||||
ret = devm_request_threaded_irq(&pdev->dev, irq, xiic_isr,
|
ret = devm_request_threaded_irq(&pdev->dev, irq, xiic_isr,
|
||||||
xiic_process, IRQF_ONESHOT,
|
xiic_process, IRQF_ONESHOT,
|
||||||
pdev->name, i2c);
|
pdev->name, i2c);
|
||||||
|
@ -794,7 +823,11 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
||||||
if (!(sr & XIIC_SR_TX_FIFO_EMPTY_MASK))
|
if (!(sr & XIIC_SR_TX_FIFO_EMPTY_MASK))
|
||||||
i2c->endianness = BIG;
|
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 */
|
/* add i2c adapter to i2c tree */
|
||||||
ret = i2c_add_adapter(&i2c->adap);
|
ret = i2c_add_adapter(&i2c->adap);
|
||||||
|
@ -806,7 +839,7 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
||||||
if (pdata) {
|
if (pdata) {
|
||||||
/* add in known devices to the bus */
|
/* add in known devices to the bus */
|
||||||
for (i = 0; i < pdata->num_devices; i++)
|
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;
|
return 0;
|
||||||
|
@ -826,14 +859,16 @@ static int xiic_i2c_remove(struct platform_device *pdev)
|
||||||
/* remove adapter & data */
|
/* remove adapter & data */
|
||||||
i2c_del_adapter(&i2c->adap);
|
i2c_del_adapter(&i2c->adap);
|
||||||
|
|
||||||
ret = clk_prepare_enable(i2c->clk);
|
ret = pm_runtime_get_sync(i2c->dev);
|
||||||
if (ret) {
|
if (ret < 0)
|
||||||
dev_err(&pdev->dev, "Unable to enable clock.\n");
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
xiic_deinit(i2c);
|
xiic_deinit(i2c);
|
||||||
|
pm_runtime_put_sync(i2c->dev);
|
||||||
clk_disable_unprepare(i2c->clk);
|
clk_disable_unprepare(i2c->clk);
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
pm_runtime_set_suspended(&pdev->dev);
|
||||||
|
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -225,7 +225,7 @@ static void i2c_acpi_register_device(struct i2c_adapter *adapter,
|
||||||
adev->power.flags.ignore_parent = true;
|
adev->power.flags.ignore_parent = true;
|
||||||
acpi_device_set_enumerated(adev);
|
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;
|
adev->power.flags.ignore_parent = false;
|
||||||
dev_err(&adapter->dev,
|
dev_err(&adapter->dev,
|
||||||
"failed to add I2C device %s from ACPI\n",
|
"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
|
* resources, in that case this function can be used to create an i2c-client
|
||||||
* for other I2cSerialBus resources in the Current Resource Settings table.
|
* 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.
|
* 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.
|
* 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_acpi_lookup lookup;
|
||||||
struct i2c_adapter *adapter;
|
struct i2c_adapter *adapter;
|
||||||
struct i2c_client *client;
|
|
||||||
struct acpi_device *adev;
|
struct acpi_device *adev;
|
||||||
LIST_HEAD(resource_list);
|
LIST_HEAD(resource_list);
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -489,11 +489,7 @@ struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
|
||||||
if (!adapter)
|
if (!adapter)
|
||||||
return ERR_PTR(-EPROBE_DEFER);
|
return ERR_PTR(-EPROBE_DEFER);
|
||||||
|
|
||||||
client = i2c_new_device(adapter, info);
|
return i2c_new_client_device(adapter, info);
|
||||||
if (!client)
|
|
||||||
return ERR_PTR(-ENODEV);
|
|
||||||
|
|
||||||
return client;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(i2c_acpi_new_device);
|
EXPORT_SYMBOL_GPL(i2c_acpi_new_device);
|
||||||
|
|
||||||
|
|
|
@ -456,15 +456,15 @@ static void i2c_client_dev_release(struct device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
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 ?
|
return sprintf(buf, "%s\n", dev->type == &i2c_client_type ?
|
||||||
to_i2c_client(dev)->name : to_i2c_adapter(dev)->name);
|
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
|
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);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
int len;
|
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);
|
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[] = {
|
static struct attribute *i2c_dev_attrs[] = {
|
||||||
&dev_attr_name.attr,
|
&dev_attr_name.attr,
|
||||||
|
@ -831,8 +831,8 @@ EXPORT_SYMBOL_GPL(i2c_new_device);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* i2c_unregister_device - reverse effect of i2c_new_device()
|
* i2c_unregister_device - reverse effect of i2c_new_*_device()
|
||||||
* @client: value returned from i2c_new_device()
|
* @client: value returned from i2c_new_*_device()
|
||||||
* Context: can sleep
|
* Context: can sleep
|
||||||
*/
|
*/
|
||||||
void i2c_unregister_device(struct i2c_client *client)
|
void i2c_unregister_device(struct i2c_client *client)
|
||||||
|
@ -1023,8 +1023,8 @@ EXPORT_SYMBOL_GPL(i2c_adapter_depth);
|
||||||
* the user to provide incorrect parameters.
|
* the user to provide incorrect parameters.
|
||||||
*/
|
*/
|
||||||
static ssize_t
|
static ssize_t
|
||||||
i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr,
|
new_device_store(struct device *dev, struct device_attribute *attr,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct i2c_adapter *adap = to_i2c_adapter(dev);
|
struct i2c_adapter *adap = to_i2c_adapter(dev);
|
||||||
struct i2c_board_info info;
|
struct i2c_board_info info;
|
||||||
|
@ -1079,7 +1079,7 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr,
|
||||||
|
|
||||||
return count;
|
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
|
* 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.
|
* the user to delete the wrong device.
|
||||||
*/
|
*/
|
||||||
static ssize_t
|
static ssize_t
|
||||||
i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr,
|
delete_device_store(struct device *dev, struct device_attribute *attr,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct i2c_adapter *adap = to_i2c_adapter(dev);
|
struct i2c_adapter *adap = to_i2c_adapter(dev);
|
||||||
struct i2c_client *client, *next;
|
struct i2c_client *client, *next;
|
||||||
|
@ -1135,7 +1135,7 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr,
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, S_IWUSR, NULL,
|
static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, S_IWUSR, NULL,
|
||||||
i2c_sysfs_delete_device);
|
delete_device_store);
|
||||||
|
|
||||||
static struct attribute *i2c_adapter_attrs[] = {
|
static struct attribute *i2c_adapter_attrs[] = {
|
||||||
&dev_attr_name.attr,
|
&dev_attr_name.attr,
|
||||||
|
@ -1178,9 +1178,8 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
|
||||||
|
|
||||||
down_read(&__i2c_board_lock);
|
down_read(&__i2c_board_lock);
|
||||||
list_for_each_entry(devinfo, &__i2c_board_list, list) {
|
list_for_each_entry(devinfo, &__i2c_board_list, list) {
|
||||||
if (devinfo->busnum == adapter->nr
|
if (devinfo->busnum == adapter->nr &&
|
||||||
&& !i2c_new_device(adapter,
|
IS_ERR(i2c_new_client_device(adapter, &devinfo->board_info)))
|
||||||
&devinfo->board_info))
|
|
||||||
dev_err(&adapter->dev,
|
dev_err(&adapter->dev,
|
||||||
"Can't create device at 0x%02x\n",
|
"Can't create device at 0x%02x\n",
|
||||||
devinfo->board_info.addr);
|
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",
|
dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n",
|
||||||
info.type, info.addr);
|
info.type, info.addr);
|
||||||
client = i2c_new_device(adapter, &info);
|
client = i2c_new_client_device(adapter, &info);
|
||||||
if (client)
|
if (!IS_ERR(client))
|
||||||
list_add_tail(&client->detected, &driver->clients);
|
list_add_tail(&client->detected, &driver->clients);
|
||||||
else
|
else
|
||||||
dev_err(&adapter->dev, "Failed creating %s at 0x%02x\n",
|
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)
|
if (ret)
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
client = i2c_new_device(adap, &info);
|
client = i2c_new_client_device(adap, &info);
|
||||||
if (!client) {
|
if (IS_ERR(client))
|
||||||
dev_err(&adap->dev, "of_i2c: Failure registering %pOF\n", node);
|
dev_err(&adap->dev, "of_i2c: Failure registering %pOF\n", node);
|
||||||
return ERR_PTR(-EINVAL);
|
|
||||||
}
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
* warranty of any kind, whether express or implied.
|
* warranty of any kind, whether express or implied.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/bitops.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
|
@ -42,20 +43,20 @@
|
||||||
#define PCA9541_CONTROL 0x01
|
#define PCA9541_CONTROL 0x01
|
||||||
#define PCA9541_ISTAT 0x02
|
#define PCA9541_ISTAT 0x02
|
||||||
|
|
||||||
#define PCA9541_CTL_MYBUS (1 << 0)
|
#define PCA9541_CTL_MYBUS BIT(0)
|
||||||
#define PCA9541_CTL_NMYBUS (1 << 1)
|
#define PCA9541_CTL_NMYBUS BIT(1)
|
||||||
#define PCA9541_CTL_BUSON (1 << 2)
|
#define PCA9541_CTL_BUSON BIT(2)
|
||||||
#define PCA9541_CTL_NBUSON (1 << 3)
|
#define PCA9541_CTL_NBUSON BIT(3)
|
||||||
#define PCA9541_CTL_BUSINIT (1 << 4)
|
#define PCA9541_CTL_BUSINIT BIT(4)
|
||||||
#define PCA9541_CTL_TESTON (1 << 6)
|
#define PCA9541_CTL_TESTON BIT(6)
|
||||||
#define PCA9541_CTL_NTESTON (1 << 7)
|
#define PCA9541_CTL_NTESTON BIT(7)
|
||||||
|
|
||||||
#define PCA9541_ISTAT_INTIN (1 << 0)
|
#define PCA9541_ISTAT_INTIN BIT(0)
|
||||||
#define PCA9541_ISTAT_BUSINIT (1 << 1)
|
#define PCA9541_ISTAT_BUSINIT BIT(1)
|
||||||
#define PCA9541_ISTAT_BUSOK (1 << 2)
|
#define PCA9541_ISTAT_BUSOK BIT(2)
|
||||||
#define PCA9541_ISTAT_BUSLOST (1 << 3)
|
#define PCA9541_ISTAT_BUSLOST BIT(3)
|
||||||
#define PCA9541_ISTAT_MYTEST (1 << 6)
|
#define PCA9541_ISTAT_MYTEST BIT(6)
|
||||||
#define PCA9541_ISTAT_NMYTEST (1 << 7)
|
#define PCA9541_ISTAT_NMYTEST BIT(7)
|
||||||
|
|
||||||
#define BUSON (PCA9541_CTL_BUSON | PCA9541_CTL_NBUSON)
|
#define BUSON (PCA9541_CTL_BUSON | PCA9541_CTL_NBUSON)
|
||||||
#define MYBUS (PCA9541_CTL_MYBUS | PCA9541_CTL_NMYBUS)
|
#define MYBUS (PCA9541_CTL_MYBUS | PCA9541_CTL_NMYBUS)
|
||||||
|
|
|
@ -86,7 +86,7 @@ struct pca954x {
|
||||||
|
|
||||||
u8 last_chan; /* last register value */
|
u8 last_chan; /* last register value */
|
||||||
/* MUX_IDLE_AS_IS, MUX_IDLE_DISCONNECT or >= 0 for channel */
|
/* MUX_IDLE_AS_IS, MUX_IDLE_DISCONNECT or >= 0 for channel */
|
||||||
s8 idle_state;
|
s32 idle_state;
|
||||||
|
|
||||||
struct i2c_client *client;
|
struct i2c_client *client;
|
||||||
|
|
||||||
|
@ -229,20 +229,23 @@ static int pca954x_reg_write(struct i2c_adapter *adap,
|
||||||
I2C_SMBUS_BYTE, &dummy);
|
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)
|
static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
|
||||||
{
|
{
|
||||||
struct pca954x *data = i2c_mux_priv(muxc);
|
struct pca954x *data = i2c_mux_priv(muxc);
|
||||||
struct i2c_client *client = data->client;
|
struct i2c_client *client = data->client;
|
||||||
const struct chip_desc *chip = data->chip;
|
|
||||||
u8 regval;
|
u8 regval;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
/* we make switches look like muxes, not sure how to be smarter */
|
regval = pca954x_regval(data, chan);
|
||||||
if (chip->muxtype == pca954x_ismux)
|
|
||||||
regval = chan | chip->enable;
|
|
||||||
else
|
|
||||||
regval = 1 << chan;
|
|
||||||
|
|
||||||
/* Only select the channel if its different from the last channel */
|
/* Only select the channel if its different from the last channel */
|
||||||
if (data->last_chan != regval) {
|
if (data->last_chan != regval) {
|
||||||
ret = pca954x_reg_write(muxc->parent, client, 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 pca954x *data = i2c_mux_priv(muxc);
|
||||||
struct i2c_client *client = data->client;
|
struct i2c_client *client = data->client;
|
||||||
s8 idle_state;
|
s32 idle_state;
|
||||||
|
|
||||||
idle_state = READ_ONCE(data->idle_state);
|
idle_state = READ_ONCE(data->idle_state);
|
||||||
if (idle_state >= 0)
|
if (idle_state >= 0)
|
||||||
|
@ -402,6 +405,22 @@ static void pca954x_cleanup(struct i2c_mux_core *muxc)
|
||||||
i2c_mux_del_adapters(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
|
* I2C init/probing/exit functions
|
||||||
*/
|
*/
|
||||||
|
@ -411,7 +430,6 @@ static int pca954x_probe(struct i2c_client *client,
|
||||||
struct i2c_adapter *adap = client->adapter;
|
struct i2c_adapter *adap = client->adapter;
|
||||||
struct device *dev = &client->dev;
|
struct device *dev = &client->dev;
|
||||||
struct device_node *np = dev->of_node;
|
struct device_node *np = dev->of_node;
|
||||||
bool idle_disconnect_dt;
|
|
||||||
struct gpio_desc *gpio;
|
struct gpio_desc *gpio;
|
||||||
struct i2c_mux_core *muxc;
|
struct i2c_mux_core *muxc;
|
||||||
struct pca954x *data;
|
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
|
* 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");
|
dev_warn(dev, "probe failed\n");
|
||||||
return -ENODEV;
|
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);
|
ret = pca954x_irq_setup(muxc);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto fail_cleanup;
|
goto fail_cleanup;
|
||||||
|
@ -530,9 +549,13 @@ static int pca954x_resume(struct device *dev)
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||||
struct pca954x *data = i2c_mux_priv(muxc);
|
struct pca954x *data = i2c_mux_priv(muxc);
|
||||||
|
int ret;
|
||||||
|
|
||||||
data->last_chan = 0;
|
ret = pca954x_init(client, data);
|
||||||
return i2c_smbus_write_byte(client, 0);
|
if (ret < 0)
|
||||||
|
dev_err(&client->dev, "failed to verify mux presence\n");
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
* at24.c - handle most I2C EEPROMs
|
||||||
*
|
*
|
||||||
|
@ -6,23 +6,23 @@
|
||||||
* Copyright (C) 2008 Wolfram Sang, Pengutronix
|
* 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/acpi.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/i2c.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/nvmem-provider.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/pm_runtime.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. */
|
/* Address pointer is 16 bit. */
|
||||||
#define AT24_FLAG_ADDR16 BIT(7)
|
#define AT24_FLAG_ADDR16 BIT(7)
|
||||||
|
@ -88,8 +88,7 @@ struct at24_data {
|
||||||
u8 flags;
|
u8 flags;
|
||||||
|
|
||||||
struct nvmem_device *nvmem;
|
struct nvmem_device *nvmem;
|
||||||
|
struct regulator *vcc_reg;
|
||||||
struct gpio_desc *wp_gpio;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some chips tie up multiple I2C addresses; dummy devices reserve
|
* 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.
|
* from this host, but not from other I2C masters.
|
||||||
*/
|
*/
|
||||||
mutex_lock(&at24->lock);
|
mutex_lock(&at24->lock);
|
||||||
gpiod_set_value_cansleep(at24->wp_gpio, 0);
|
|
||||||
|
|
||||||
while (count) {
|
while (count) {
|
||||||
ret = at24_regmap_write(at24, buf, off, count);
|
ret = at24_regmap_write(at24, buf, off, count);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
gpiod_set_value_cansleep(at24->wp_gpio, 1);
|
|
||||||
mutex_unlock(&at24->lock);
|
mutex_unlock(&at24->lock);
|
||||||
pm_runtime_put(dev);
|
pm_runtime_put(dev);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -472,7 +469,6 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
|
||||||
count -= ret;
|
count -= ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpiod_set_value_cansleep(at24->wp_gpio, 1);
|
|
||||||
mutex_unlock(&at24->lock);
|
mutex_unlock(&at24->lock);
|
||||||
|
|
||||||
pm_runtime_put(dev);
|
pm_runtime_put(dev);
|
||||||
|
@ -662,9 +658,9 @@ static int at24_probe(struct i2c_client *client)
|
||||||
at24->client[0].client = client;
|
at24->client[0].client = client;
|
||||||
at24->client[0].regmap = regmap;
|
at24->client[0].regmap = regmap;
|
||||||
|
|
||||||
at24->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_HIGH);
|
at24->vcc_reg = devm_regulator_get(dev, "vcc");
|
||||||
if (IS_ERR(at24->wp_gpio))
|
if (IS_ERR(at24->vcc_reg))
|
||||||
return PTR_ERR(at24->wp_gpio);
|
return PTR_ERR(at24->vcc_reg);
|
||||||
|
|
||||||
writable = !(flags & AT24_FLAG_READONLY);
|
writable = !(flags & AT24_FLAG_READONLY);
|
||||||
if (writable) {
|
if (writable) {
|
||||||
|
@ -701,6 +697,12 @@ static int at24_probe(struct i2c_client *client)
|
||||||
|
|
||||||
i2c_set_clientdata(client, at24);
|
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 */
|
/* enable runtime pm */
|
||||||
pm_runtime_set_active(dev);
|
pm_runtime_set_active(dev);
|
||||||
pm_runtime_enable(dev);
|
pm_runtime_enable(dev);
|
||||||
|
@ -713,6 +715,7 @@ static int at24_probe(struct i2c_client *client)
|
||||||
pm_runtime_idle(dev);
|
pm_runtime_idle(dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
pm_runtime_disable(dev);
|
pm_runtime_disable(dev);
|
||||||
|
regulator_disable(at24->vcc_reg);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -728,15 +731,42 @@ static int at24_probe(struct i2c_client *client)
|
||||||
|
|
||||||
static int at24_remove(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);
|
pm_runtime_disable(&client->dev);
|
||||||
|
if (!pm_runtime_status_suspended(&client->dev))
|
||||||
|
regulator_disable(at24->vcc_reg);
|
||||||
pm_runtime_set_suspended(&client->dev);
|
pm_runtime_set_suspended(&client->dev);
|
||||||
|
|
||||||
return 0;
|
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 = {
|
static struct i2c_driver at24_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "at24",
|
.name = "at24",
|
||||||
|
.pm = &at24_pm_ops,
|
||||||
.of_match_table = at24_of_match,
|
.of_match_table = at24_of_match,
|
||||||
.acpi_match_table = ACPI_PTR(at24_acpi_ids),
|
.acpi_match_table = ACPI_PTR(at24_acpi_ids),
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/nvmem-consumer.h>
|
#include <linux/nvmem-consumer.h>
|
||||||
#include <linux/nvmem-provider.h>
|
#include <linux/nvmem-provider.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include "nvmem.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,
|
static int nvmem_reg_write(struct nvmem_device *nvmem, unsigned int offset,
|
||||||
void *val, size_t bytes)
|
void *val, size_t bytes)
|
||||||
{
|
{
|
||||||
if (nvmem->reg_write)
|
int ret;
|
||||||
return nvmem->reg_write(nvmem->priv, offset, val, bytes);
|
|
||||||
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -340,6 +347,14 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
|
||||||
kfree(nvmem);
|
kfree(nvmem);
|
||||||
return ERR_PTR(rval);
|
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);
|
kref_init(&nvmem->refcnt);
|
||||||
INIT_LIST_HEAD(&nvmem->cells);
|
INIT_LIST_HEAD(&nvmem->cells);
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/nvmem-consumer.h>
|
#include <linux/nvmem-consumer.h>
|
||||||
#include <linux/nvmem-provider.h>
|
#include <linux/nvmem-provider.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
|
|
||||||
struct nvmem_device {
|
struct nvmem_device {
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
|
@ -26,6 +27,7 @@ struct nvmem_device {
|
||||||
struct list_head cells;
|
struct list_head cells;
|
||||||
nvmem_reg_read_t reg_read;
|
nvmem_reg_read_t reg_read;
|
||||||
nvmem_reg_write_t reg_write;
|
nvmem_reg_write_t reg_write;
|
||||||
|
struct gpio_desc *wp_gpio;
|
||||||
void *priv;
|
void *priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -50,8 +50,8 @@ struct property_entry;
|
||||||
* transmit an arbitrary number of messages without interruption.
|
* transmit an arbitrary number of messages without interruption.
|
||||||
* @count must be be less than 64k since msg.len is u16.
|
* @count must be be less than 64k since msg.len is u16.
|
||||||
*/
|
*/
|
||||||
extern int i2c_transfer_buffer_flags(const struct i2c_client *client,
|
int i2c_transfer_buffer_flags(const struct i2c_client *client,
|
||||||
char *buf, int count, u16 flags);
|
char *buf, int count, u16 flags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* i2c_master_recv - issue a single I2C message in master receive mode
|
* 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.
|
/* Transfer num messages.
|
||||||
*/
|
*/
|
||||||
extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
|
||||||
int num);
|
|
||||||
/* Unlocked flavor */
|
/* Unlocked flavor */
|
||||||
extern int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
|
||||||
int num);
|
|
||||||
|
|
||||||
/* This is the very generalized SMBus access routine. You probably do not
|
/* 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,
|
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
|
/* Now follow the 'nice' access routines. These also document the calling
|
||||||
conventions of i2c_smbus_xfer. */
|
conventions of i2c_smbus_xfer. */
|
||||||
|
|
||||||
extern s32 i2c_smbus_read_byte(const struct i2c_client *client);
|
s32 i2c_smbus_read_byte(const struct i2c_client *client);
|
||||||
extern s32 i2c_smbus_write_byte(const struct i2c_client *client, u8 value);
|
s32 i2c_smbus_write_byte(const struct i2c_client *client, u8 value);
|
||||||
extern s32 i2c_smbus_read_byte_data(const struct i2c_client *client,
|
s32 i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command);
|
||||||
u8 command);
|
s32 i2c_smbus_write_byte_data(const struct i2c_client *client,
|
||||||
extern s32 i2c_smbus_write_byte_data(const struct i2c_client *client,
|
u8 command, u8 value);
|
||||||
u8 command, u8 value);
|
s32 i2c_smbus_read_word_data(const struct i2c_client *client, u8 command);
|
||||||
extern s32 i2c_smbus_read_word_data(const struct i2c_client *client,
|
s32 i2c_smbus_write_word_data(const struct i2c_client *client,
|
||||||
u8 command);
|
u8 command, u16 value);
|
||||||
extern s32 i2c_smbus_write_word_data(const struct i2c_client *client,
|
|
||||||
u8 command, u16 value);
|
|
||||||
|
|
||||||
static inline s32
|
static inline s32
|
||||||
i2c_smbus_read_word_swapped(const struct i2c_client *client, u8 command)
|
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 */
|
/* Returns the number of read bytes */
|
||||||
extern s32 i2c_smbus_read_block_data(const struct i2c_client *client,
|
s32 i2c_smbus_read_block_data(const struct i2c_client *client,
|
||||||
u8 command, u8 *values);
|
u8 command, u8 *values);
|
||||||
extern s32 i2c_smbus_write_block_data(const struct i2c_client *client,
|
s32 i2c_smbus_write_block_data(const struct i2c_client *client,
|
||||||
u8 command, u8 length, const u8 *values);
|
u8 command, u8 length, const u8 *values);
|
||||||
/* Returns the number of read bytes */
|
/* Returns the number of read bytes */
|
||||||
extern s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client,
|
s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client,
|
||||||
u8 command, u8 length, u8 *values);
|
u8 command, u8 length, u8 *values);
|
||||||
extern s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client,
|
s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client,
|
||||||
u8 command, u8 length,
|
u8 command, u8 length, const u8 *values);
|
||||||
const u8 *values);
|
s32 i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client,
|
||||||
extern s32
|
u8 command, u8 length,
|
||||||
i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client,
|
u8 *values);
|
||||||
u8 command, u8 length, u8 *values);
|
|
||||||
int i2c_get_device_id(const struct i2c_client *client,
|
int i2c_get_device_id(const struct i2c_client *client,
|
||||||
struct i2c_device_identity *id);
|
struct i2c_device_identity *id);
|
||||||
#endif /* I2C */
|
#endif /* I2C */
|
||||||
|
@ -337,10 +332,10 @@ struct i2c_client {
|
||||||
};
|
};
|
||||||
#define to_i2c_client(d) container_of(d, struct i2c_client, dev)
|
#define to_i2c_client(d) container_of(d, struct i2c_client, dev)
|
||||||
|
|
||||||
extern struct i2c_client *i2c_verify_client(struct device *dev);
|
struct i2c_client *i2c_verify_client(struct device *dev);
|
||||||
extern struct i2c_adapter *i2c_verify_adapter(struct device *dev);
|
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_device_id *i2c_match_id(const struct i2c_device_id *id,
|
||||||
const struct i2c_client *client);
|
const struct i2c_client *client);
|
||||||
|
|
||||||
static inline struct i2c_client *kobj_to_i2c_client(struct kobject *kobj)
|
static inline struct i2c_client *kobj_to_i2c_client(struct kobject *kobj)
|
||||||
{
|
{
|
||||||
|
@ -369,9 +364,9 @@ enum i2c_slave_event {
|
||||||
I2C_SLAVE_STOP,
|
I2C_SLAVE_STOP,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb);
|
int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb);
|
||||||
extern int i2c_slave_unregister(struct i2c_client *client);
|
int i2c_slave_unregister(struct i2c_client *client);
|
||||||
extern bool i2c_detect_slave_mode(struct device *dev);
|
bool i2c_detect_slave_mode(struct device *dev);
|
||||||
|
|
||||||
static inline int i2c_slave_event(struct i2c_client *client,
|
static inline int i2c_slave_event(struct i2c_client *client,
|
||||||
enum i2c_slave_event event, u8 *val)
|
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
|
* with integrated I2C, a config eeprom, sensors, and a codec that's
|
||||||
* used in conjunction with the primary hardware.
|
* 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);
|
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);
|
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
|
/* 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,
|
* it must return 1 on successful probe, 0 otherwise. If it is not provided,
|
||||||
* a default probing method is used.
|
* a default probing method is used.
|
||||||
*/
|
*/
|
||||||
extern struct i2c_client *
|
struct i2c_client *
|
||||||
i2c_new_scanned_device(struct i2c_adapter *adap,
|
i2c_new_scanned_device(struct i2c_adapter *adap,
|
||||||
struct i2c_board_info *info,
|
struct i2c_board_info *info,
|
||||||
unsigned short const *addr_list,
|
unsigned short const *addr_list,
|
||||||
int (*probe)(struct i2c_adapter *adap, unsigned short addr));
|
int (*probe)(struct i2c_adapter *adap, unsigned short addr));
|
||||||
|
|
||||||
extern struct i2c_client *
|
struct i2c_client *
|
||||||
i2c_new_probed_device(struct i2c_adapter *adap,
|
i2c_new_probed_device(struct i2c_adapter *adap,
|
||||||
struct i2c_board_info *info,
|
struct i2c_board_info *info,
|
||||||
unsigned short const *addr_list,
|
unsigned short const *addr_list,
|
||||||
int (*probe)(struct i2c_adapter *adap, unsigned short addr));
|
int (*probe)(struct i2c_adapter *adap, unsigned short addr));
|
||||||
|
|
||||||
/* Common custom probe functions */
|
/* 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);
|
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);
|
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,
|
i2c_new_ancillary_device(struct i2c_client *client,
|
||||||
const char *name,
|
const char *name,
|
||||||
u16 default_addr);
|
u16 default_addr);
|
||||||
|
|
||||||
extern void i2c_unregister_device(struct i2c_client *client);
|
void i2c_unregister_device(struct i2c_client *client);
|
||||||
#endif /* I2C */
|
#endif /* I2C */
|
||||||
|
|
||||||
/* Mainboard arch_initcall() code should register all its I2C devices.
|
/* 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.
|
* Modules for add-on boards must use other calls.
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_I2C_BOARDINFO
|
#ifdef CONFIG_I2C_BOARDINFO
|
||||||
extern int
|
int
|
||||||
i2c_register_board_info(int busnum, struct i2c_board_info const *info,
|
i2c_register_board_info(int busnum, struct i2c_board_info const *info,
|
||||||
unsigned n);
|
unsigned n);
|
||||||
#else
|
#else
|
||||||
|
@ -840,12 +835,12 @@ static inline void i2c_mark_adapter_resumed(struct i2c_adapter *adap)
|
||||||
/* administration...
|
/* administration...
|
||||||
*/
|
*/
|
||||||
#if IS_ENABLED(CONFIG_I2C)
|
#if IS_ENABLED(CONFIG_I2C)
|
||||||
extern int i2c_add_adapter(struct i2c_adapter *adap);
|
int i2c_add_adapter(struct i2c_adapter *adap);
|
||||||
extern void i2c_del_adapter(struct i2c_adapter *adap);
|
void i2c_del_adapter(struct i2c_adapter *adap);
|
||||||
extern int i2c_add_numbered_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);
|
int i2c_register_driver(struct module *owner, struct i2c_driver *driver);
|
||||||
extern void i2c_del_driver(struct i2c_driver *driver);
|
void i2c_del_driver(struct i2c_driver *driver);
|
||||||
|
|
||||||
/* use a define to avoid include chaining to get THIS_MODULE */
|
/* use a define to avoid include chaining to get THIS_MODULE */
|
||||||
#define i2c_add_driver(driver) \
|
#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
|
/* call the i2c_client->command() of all attached clients with
|
||||||
* the given arguments */
|
* the given arguments */
|
||||||
extern void i2c_clients_command(struct i2c_adapter *adap,
|
void i2c_clients_command(struct i2c_adapter *adap,
|
||||||
unsigned int cmd, void *arg);
|
unsigned int cmd, void *arg);
|
||||||
|
|
||||||
extern struct i2c_adapter *i2c_get_adapter(int nr);
|
struct i2c_adapter *i2c_get_adapter(int nr);
|
||||||
extern void i2c_put_adapter(struct i2c_adapter *adap);
|
void i2c_put_adapter(struct i2c_adapter *adap);
|
||||||
extern unsigned int i2c_adapter_depth(struct i2c_adapter *adapter);
|
unsigned int i2c_adapter_depth(struct i2c_adapter *adapter);
|
||||||
|
|
||||||
void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t, bool use_defaults);
|
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)
|
#if IS_ENABLED(CONFIG_OF)
|
||||||
/* must call put_device() when done with returned i2c_client device */
|
/* 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 */
|
/* 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 */
|
/* 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);
|
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,
|
*i2c_of_match_device(const struct of_device_id *matches,
|
||||||
struct i2c_client *client);
|
struct i2c_client *client);
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
|
|
||||||
struct nvmem_device;
|
struct nvmem_device;
|
||||||
struct nvmem_cell_info;
|
struct nvmem_cell_info;
|
||||||
|
@ -45,6 +46,7 @@ enum nvmem_type {
|
||||||
* @word_size: Minimum read/write access granularity.
|
* @word_size: Minimum read/write access granularity.
|
||||||
* @stride: Minimum read/write access stride.
|
* @stride: Minimum read/write access stride.
|
||||||
* @priv: User context passed to read/write callbacks.
|
* @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
|
* 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
|
* no name is specified in its configuration. In such case "<id>" is
|
||||||
|
@ -58,6 +60,7 @@ struct nvmem_config {
|
||||||
const char *name;
|
const char *name;
|
||||||
int id;
|
int id;
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
|
struct gpio_desc *wp_gpio;
|
||||||
const struct nvmem_cell_info *cells;
|
const struct nvmem_cell_info *cells;
|
||||||
int ncells;
|
int ncells;
|
||||||
enum nvmem_type type;
|
enum nvmem_type type;
|
||||||
|
|
Loading…
Reference in New Issue