mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
i2c-for-7.1-rc1-part1
- generic cleanups in npcm7xx, qcom-cci, xiic and designware DT
bindings
- atr: use kzalloc_flex for alias pool allocation
- ixp4xx: convert bindings to DT schema
- ocores: use read_poll_timeout_atomic() for polling waits
- qcom-geni: skip extra TX DMA TRE for single read messages
- s3c24xx: validate SMBus block length before using it
- spacemit: refactor xfer path and add K1 PIO support
- tegra: identify DVC and VI with SoC data variants
- tegra: support SoC-specific register offsets
- xiic: switch to devres and generic fw properties
- xiic: skip input clock setup on non-OF systems
- various minor improvements in other drivers
rtl9300:
- add per-SoC callbacks and clock support for RTL9607C
- add support for new 50 kHz and 2.5 MHz bus speeds
- general refactoring in preparation for RTL9607C support
New support:
- DesignWare GOOG5000 (ACPI HID)
- Intel Nova Lake (ACPI ID)
- Realtek RTL9607C
- SpacemiT K3 binding
- Tegra410 register layout support
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEOZGx6rniZ1Gk92RdFA3kzBSgKbYFAmnjHO8ACgkQFA3kzBSg
KbaWaw//eCB8xtFFo2S4i/ZJrnLnEo317VJBtHiAQjQdV+9LgVIk8S66JG5mzzJO
yFVBXZ6Qx6RuPUxYo8V+PvW/4/GemcWANcnztT3G6+SQXF6ATcnnDzzCf9KjV5PI
m7RNH44hZInP39TBpAj/hG2eas4F4S0zkcpuV+s5IB7tUkxdQhkSjrseMoTVZGh8
FDEsiQIlJR3qxjIa/FPw1/iuC7FJHJfuWjT3czNil0uLb/i+xOpHWjDvgaAXi+wU
U58zz2AyJTbUPclO0H4udbQbQ+qACjOSaelEf+v5wlWmy6BT0ZI+CO/pRteD+Iix
UHb/zPilrBG42JN+L7ndJat4jW1POEi6fol9y1gg9yWtH09QGEfR16+YlqDag4/M
Cgu1I3QUatGlT7jXkg8pr2Q/u7IFi4XGyvsNIs4k7oqYkbZKMCyWFDPVC5EByNus
JcnpRACuJldDv3Rj1jZXUjVE1vDBb438lR8XRrrGpYd+j7xS7vFRjDxE/47y+weR
sP83ODZH2GesQx3VkZPOnINd9/qfKEPYqilxkkoAO+0mh+iCdstyrjg3VlFbZNpf
eeSZqlGNLVcDEpY8HENSLxdp3PANRxTqDVlGrYPEt3WH0EmWOhhXLOysKtDEgehL
qKYiouyXgcCwVgBkp3sR7REQ0+LfRi+U8Y2Rw02WKjMk1jclRUA=
=G0Mn
-----END PGP SIGNATURE-----
Merge tag 'i2c-for-7.1-rc1-part1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang:
"The biggest news in this pull request is that it will start the last
cycle of me handling the I2C subsystem. From 7.2. on, I will pass
maintainership to Andi Shyti who has been maintaining the I2C drivers
for a while now and who has done a great job in doing so.
We will use this cycle for a hopefully smooth transition. Thanks must
go to Andi for stepping up! I will still be around for guidance.
Updates:
- generic cleanups in npcm7xx, qcom-cci, xiic and designware DT
bindings
- atr: use kzalloc_flex for alias pool allocation
- ixp4xx: convert bindings to DT schema
- ocores: use read_poll_timeout_atomic() for polling waits
- qcom-geni: skip extra TX DMA TRE for single read messages
- s3c24xx: validate SMBus block length before using it
- spacemit: refactor xfer path and add K1 PIO support
- tegra: identify DVC and VI with SoC data variants
- tegra: support SoC-specific register offsets
- xiic: switch to devres and generic fw properties
- xiic: skip input clock setup on non-OF systems
- various minor improvements in other drivers
rtl9300:
- add per-SoC callbacks and clock support for RTL9607C
- add support for new 50 kHz and 2.5 MHz bus speeds
- general refactoring in preparation for RTL9607C support
New support:
- DesignWare GOOG5000 (ACPI HID)
- Intel Nova Lake (ACPI ID)
- Realtek RTL9607C
- SpacemiT K3 binding
- Tegra410 register layout support"
* tag 'i2c-for-7.1-rc1-part1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (40 commits)
i2c: usbio: Add ACPI device-id for NVL platforms
i2c: qcom-geni: Avoid extra TX DMA TRE for single read message in GPI mode
i2c: atr: use kzalloc_flex
i2c: spacemit: introduce pio for k1
i2c: spacemit: move i2c_xfer_msg()
i2c: xiic: skip input clock setup on non-OF systems
i2c: xiic: use numbered adapter registration
i2c: xiic: cosmetic: use resource format specifier in debug log
i2c: xiic: cosmetic cleanup
i2c: xiic: switch to generic device property accessors
i2c: xiic: remove duplicate error message
i2c: xiic: switch to devres managed APIs
i2c: rtl9300: add RTL9607C i2c controller support
i2c: rtl9300: introduce new function properties to driver data
i2c: rtl9300: introduce clk struct for upcoming rtl9607 support
dt-bindings: i2c: realtek,rtl9301-i2c: extend for clocks and RTL9607C support
i2c: rtl9300: introduce a property for 8 bit width reg address
i2c: rtl9300: introduce F_BUSY to the reg_fields struct
i2c: rtl9300: introduce max length property to driver data
i2c: rtl9300: split data_reg into read and write reg
...
This commit is contained in:
commit
fba676bd29
|
|
@ -1,20 +0,0 @@
|
|||
i2c Controller on XScale platforms such as IOP3xx and IXP4xx
|
||||
|
||||
Required properties:
|
||||
- compatible : Must be one of
|
||||
"intel,iop3xx-i2c"
|
||||
"intel,ixp4xx-i2c";
|
||||
- reg
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
|
||||
Optional properties:
|
||||
- Child nodes conforming to i2c bus binding
|
||||
|
||||
Example:
|
||||
|
||||
i2c@c8011000 {
|
||||
compatible = "intel,ixp4xx-i2c";
|
||||
reg = <0xc8011000 0x18>;
|
||||
interrupts = <33 IRQ_TYPE_LEVEL_LOW>;
|
||||
};
|
||||
41
Documentation/devicetree/bindings/i2c/intel,ixp4xx-i2c.yaml
Normal file
41
Documentation/devicetree/bindings/i2c/intel,ixp4xx-i2c.yaml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/intel,ixp4xx-i2c.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: I2c Controller on XScale platforms such as IOP3xx and IXP4xx
|
||||
|
||||
maintainers:
|
||||
- Andi Shyti <andi.shyti@kernel.org>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- intel,iop3xx-i2c
|
||||
- intel,ixp4xx-i2c
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
i2c@c8011000 {
|
||||
compatible = "intel,ixp4xx-i2c";
|
||||
reg = <0xc8011000 0x18>;
|
||||
interrupts = <33 IRQ_TYPE_LEVEL_LOW>;
|
||||
};
|
||||
|
|
@ -27,6 +27,7 @@ properties:
|
|||
- items:
|
||||
- enum:
|
||||
- qcom,kaanapali-cci
|
||||
- qcom,milos-cci
|
||||
- qcom,qcm2290-cci
|
||||
- qcom,qcs8300-cci
|
||||
- qcom,sa8775p-cci
|
||||
|
|
@ -34,6 +35,7 @@ properties:
|
|||
- qcom,sc8280xp-cci
|
||||
- qcom,sdm670-cci
|
||||
- qcom,sdm845-cci
|
||||
- qcom,sm6150-cci
|
||||
- qcom,sm6350-cci
|
||||
- qcom,sm8250-cci
|
||||
- qcom,sm8450-cci
|
||||
|
|
@ -251,6 +253,7 @@ allOf:
|
|||
contains:
|
||||
enum:
|
||||
- qcom,sa8775p-cci
|
||||
- qcom,sm6150-cci
|
||||
- qcom,sm8550-cci
|
||||
- qcom,sm8650-cci
|
||||
- qcom,x1e80100-cci
|
||||
|
|
@ -265,6 +268,23 @@ allOf:
|
|||
- const: cpas_ahb
|
||||
- const: cci
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,milos-cci
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
clock-names:
|
||||
items:
|
||||
- const: soc_ahb
|
||||
- const: cpas_ahb
|
||||
- const: cci
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ description:
|
|||
assigned to either I2C controller.
|
||||
RTL9310 SoCs have equal capabilities but support 12 common SDA lines which
|
||||
can be assigned to either I2C controller.
|
||||
RTL9607C SoCs have equal capabilities but each controller only supports 1
|
||||
SCL/SDA line.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
|
@ -34,6 +36,7 @@ properties:
|
|||
- enum:
|
||||
- realtek,rtl9301-i2c
|
||||
- realtek,rtl9310-i2c
|
||||
- realtek,rtl9607-i2c
|
||||
|
||||
reg:
|
||||
items:
|
||||
|
|
@ -51,6 +54,9 @@ properties:
|
|||
The SCL line number of this I2C controller.
|
||||
enum: [ 0, 1 ]
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
patternProperties:
|
||||
'^i2c@[0-9ab]$':
|
||||
$ref: /schemas/i2c/i2c-controller.yaml
|
||||
|
|
@ -81,6 +87,15 @@ allOf:
|
|||
then:
|
||||
patternProperties:
|
||||
'^i2c@[89ab]$': false
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: realtek,rtl9607-i2c
|
||||
then:
|
||||
required:
|
||||
- realtek,scl
|
||||
- clocks
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ properties:
|
|||
- items:
|
||||
- enum:
|
||||
- renesas,riic-r9a08g045 # RZ/G3S
|
||||
- renesas,riic-r9a08g046 # RZ/G3L
|
||||
- renesas,riic-r9a09g047 # RZ/G3E
|
||||
- renesas,riic-r9a09g056 # RZ/V2N
|
||||
- const: renesas,riic-r9a09g057 # RZ/V2H(P)
|
||||
|
|
|
|||
|
|
@ -32,8 +32,6 @@ properties:
|
|||
- const: renesas,r9a06g032-i2c # RZ/N1D
|
||||
- const: renesas,rzn1-i2c # RZ/N1
|
||||
- const: snps,designware-i2c
|
||||
- description: Baikal-T1 SoC System I2C controller
|
||||
const: baikal,bt1-sys-i2c
|
||||
- description: Mobileye EyeQ DesignWare I2C controller
|
||||
items:
|
||||
- enum:
|
||||
|
|
|
|||
|
|
@ -14,7 +14,11 @@ allOf:
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
const: spacemit,k1-i2c
|
||||
oneOf:
|
||||
- items:
|
||||
- const: spacemit,k3-i2c
|
||||
- const: spacemit,k1-i2c
|
||||
- const: spacemit,k1-i2c
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -1211,8 +1211,7 @@ config I2C_SYNQUACER
|
|||
|
||||
config I2C_TEGRA
|
||||
tristate "NVIDIA Tegra internal I2C controller"
|
||||
depends on ARCH_TEGRA || (COMPILE_TEST && (ARC || ARM || ARM64 || M68K || RISCV || SUPERH || SPARC))
|
||||
# COMPILE_TEST needs architectures with readsX()/writesX() primitives
|
||||
depends on ARCH_TEGRA || COMPILE_TEST
|
||||
depends on PINCTRL
|
||||
# ARCH_TEGRA implies PINCTRL, but the COMPILE_TEST side doesn't.
|
||||
help
|
||||
|
|
|
|||
|
|
@ -270,8 +270,7 @@ static struct i2c_adapter_quirks cp2615_i2c_quirks = {
|
|||
.max_comb_2nd_msg_len = MAX_I2C_SIZE
|
||||
};
|
||||
|
||||
static void
|
||||
cp2615_i2c_remove(struct usb_interface *usbif)
|
||||
static void cp2615_i2c_disconnect(struct usb_interface *usbif)
|
||||
{
|
||||
struct i2c_adapter *adap = usb_get_intfdata(usbif);
|
||||
|
||||
|
|
@ -328,7 +327,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
|
|||
static struct usb_driver cp2615_i2c_driver = {
|
||||
.name = "i2c-cp2615",
|
||||
.probe = cp2615_i2c_probe,
|
||||
.disconnect = cp2615_i2c_remove,
|
||||
.disconnect = cp2615_i2c_disconnect,
|
||||
.id_table = id_table,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -268,6 +268,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
|
|||
{ "AMDI0510", 0 },
|
||||
{ "APMC0D0F", 0 },
|
||||
{ "FUJI200B", 0 },
|
||||
{ "GOOG5000", 0 },
|
||||
{ "HISI02A1", 0 },
|
||||
{ "HISI02A2", 0 },
|
||||
{ "HISI02A3", 0 },
|
||||
|
|
|
|||
|
|
@ -427,12 +427,6 @@ static const struct usb_device_id diolan_u2c_table[] = {
|
|||
|
||||
MODULE_DEVICE_TABLE(usb, diolan_u2c_table);
|
||||
|
||||
static void diolan_u2c_free(struct i2c_diolan_u2c *dev)
|
||||
{
|
||||
usb_put_dev(dev->usb_dev);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
static int diolan_u2c_probe(struct usb_interface *interface,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
|
|
@ -453,7 +447,7 @@ static int diolan_u2c_probe(struct usb_interface *interface,
|
|||
dev->ep_out = hostif->endpoint[0].desc.bEndpointAddress;
|
||||
dev->ep_in = hostif->endpoint[1].desc.bEndpointAddress;
|
||||
|
||||
dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
|
||||
dev->usb_dev = interface_to_usbdev(interface);
|
||||
dev->interface = interface;
|
||||
|
||||
/* save our data pointer in this interface device */
|
||||
|
|
@ -488,7 +482,7 @@ static int diolan_u2c_probe(struct usb_interface *interface,
|
|||
|
||||
error_free:
|
||||
usb_set_intfdata(interface, NULL);
|
||||
diolan_u2c_free(dev);
|
||||
kfree(dev);
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -499,7 +493,7 @@ static void diolan_u2c_disconnect(struct usb_interface *interface)
|
|||
|
||||
i2c_del_adapter(&dev->adapter);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
diolan_u2c_free(dev);
|
||||
kfree(dev);
|
||||
|
||||
dev_dbg(&interface->dev, "disconnected\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,6 +98,10 @@
|
|||
|
||||
#define SPACEMIT_BUS_RESET_CLK_CNT_MAX 9
|
||||
|
||||
#define SPACEMIT_WAIT_TIMEOUT 1000 /* ms */
|
||||
#define SPACEMIT_POLL_TIMEOUT 1000 /* us */
|
||||
#define SPACEMIT_POLL_INTERVAL 30 /* us */
|
||||
|
||||
enum spacemit_i2c_state {
|
||||
SPACEMIT_STATE_IDLE,
|
||||
SPACEMIT_STATE_START,
|
||||
|
|
@ -126,6 +130,7 @@ struct spacemit_i2c_dev {
|
|||
|
||||
enum spacemit_i2c_state state;
|
||||
bool read;
|
||||
bool use_pio;
|
||||
struct completion complete;
|
||||
u32 status;
|
||||
};
|
||||
|
|
@ -172,6 +177,14 @@ static int spacemit_i2c_handle_err(struct spacemit_i2c_dev *i2c)
|
|||
return i2c->status & SPACEMIT_SR_ACKNAK ? -ENXIO : -EIO;
|
||||
}
|
||||
|
||||
static inline void spacemit_i2c_delay(struct spacemit_i2c_dev *i2c, unsigned int us)
|
||||
{
|
||||
if (i2c->use_pio)
|
||||
udelay(us);
|
||||
else
|
||||
fsleep(us);
|
||||
}
|
||||
|
||||
static void spacemit_i2c_conditionally_reset_bus(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
u32 status;
|
||||
|
|
@ -183,7 +196,8 @@ static void spacemit_i2c_conditionally_reset_bus(struct spacemit_i2c_dev *i2c)
|
|||
return;
|
||||
|
||||
spacemit_i2c_reset(i2c);
|
||||
usleep_range(10, 20);
|
||||
|
||||
spacemit_i2c_delay(i2c, 10);
|
||||
|
||||
for (clk_cnt = 0; clk_cnt < SPACEMIT_BUS_RESET_CLK_CNT_MAX; clk_cnt++) {
|
||||
status = readl(i2c->base + SPACEMIT_IBMR);
|
||||
|
|
@ -212,9 +226,15 @@ static int spacemit_i2c_wait_bus_idle(struct spacemit_i2c_dev *i2c)
|
|||
if (!(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB)))
|
||||
return 0;
|
||||
|
||||
if (i2c->use_pio)
|
||||
ret = readl_poll_timeout_atomic(i2c->base + SPACEMIT_ISR,
|
||||
val, !(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB)),
|
||||
1500, SPACEMIT_I2C_BUS_BUSY_TIMEOUT);
|
||||
else
|
||||
ret = readl_poll_timeout(i2c->base + SPACEMIT_ISR,
|
||||
val, !(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB)),
|
||||
1500, SPACEMIT_I2C_BUS_BUSY_TIMEOUT);
|
||||
|
||||
if (ret)
|
||||
spacemit_i2c_reset(i2c);
|
||||
|
||||
|
|
@ -226,7 +246,7 @@ static void spacemit_i2c_check_bus_release(struct spacemit_i2c_dev *i2c)
|
|||
/* in case bus is not released after transfer completes */
|
||||
if (readl(i2c->base + SPACEMIT_ISR) & SPACEMIT_SR_EBB) {
|
||||
spacemit_i2c_conditionally_reset_bus(i2c);
|
||||
usleep_range(90, 150);
|
||||
spacemit_i2c_delay(i2c, 90);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -238,26 +258,34 @@ spacemit_i2c_clear_int_status(struct spacemit_i2c_dev *i2c, u32 mask)
|
|||
|
||||
static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
u32 val;
|
||||
u32 val = 0;
|
||||
|
||||
if (!i2c->use_pio) {
|
||||
/*
|
||||
* Unmask interrupt bits for all xfer mode:
|
||||
* Enable interrupt bits for all xfer mode:
|
||||
* bus error, arbitration loss detected.
|
||||
* For transaction complete signal, we use master stop
|
||||
* interrupt, so we don't need to unmask SPACEMIT_CR_TXDONEIE.
|
||||
*/
|
||||
val = SPACEMIT_CR_BEIE | SPACEMIT_CR_ALDIE;
|
||||
val |= SPACEMIT_CR_BEIE | SPACEMIT_CR_ALDIE;
|
||||
|
||||
/*
|
||||
* Unmask interrupt bits for interrupt xfer mode:
|
||||
* When IDBR receives a byte, an interrupt is triggered.
|
||||
*
|
||||
* For the tx empty interrupt, it will be enabled in the
|
||||
* i2c_start function.
|
||||
* Otherwise, it will cause an erroneous empty interrupt before i2c_start.
|
||||
* i2c_start().
|
||||
* We don't want a TX empty interrupt until we start
|
||||
* a transfer in i2c_start().
|
||||
*/
|
||||
val |= SPACEMIT_CR_DRFIE;
|
||||
|
||||
/*
|
||||
* Enable master stop interrupt bit.
|
||||
* For transaction complete signal, we use master stop
|
||||
* interrupt, so we don't need to unmask SPACEMIT_CR_TXDONEIE.
|
||||
*/
|
||||
val |= SPACEMIT_CR_MSDIE;
|
||||
}
|
||||
|
||||
if (i2c->clock_freq == SPACEMIT_I2C_MAX_FAST_MODE_FREQ)
|
||||
val |= SPACEMIT_CR_MODE_FAST;
|
||||
|
||||
|
|
@ -268,7 +296,7 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
|
|||
val |= SPACEMIT_CR_SCLE;
|
||||
|
||||
/* enable master stop detected */
|
||||
val |= SPACEMIT_CR_MSDE | SPACEMIT_CR_MSDIE;
|
||||
val |= SPACEMIT_CR_MSDE;
|
||||
|
||||
writel(val, i2c->base + SPACEMIT_ICR);
|
||||
|
||||
|
|
@ -301,41 +329,15 @@ static void spacemit_i2c_start(struct spacemit_i2c_dev *i2c)
|
|||
/* send start pulse */
|
||||
val = readl(i2c->base + SPACEMIT_ICR);
|
||||
val &= ~SPACEMIT_CR_STOP;
|
||||
val |= SPACEMIT_CR_START | SPACEMIT_CR_TB | SPACEMIT_CR_DTEIE;
|
||||
val |= SPACEMIT_CR_START | SPACEMIT_CR_TB;
|
||||
|
||||
/* Enable the TX empty interrupt */
|
||||
if (!i2c->use_pio)
|
||||
val |= SPACEMIT_CR_DTEIE;
|
||||
|
||||
writel(val, i2c->base + SPACEMIT_ICR);
|
||||
}
|
||||
|
||||
static int spacemit_i2c_xfer_msg(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
unsigned long time_left;
|
||||
struct i2c_msg *msg;
|
||||
|
||||
for (i2c->msg_idx = 0; i2c->msg_idx < i2c->msg_num; i2c->msg_idx++) {
|
||||
msg = &i2c->msgs[i2c->msg_idx];
|
||||
i2c->msg_buf = msg->buf;
|
||||
i2c->unprocessed = msg->len;
|
||||
i2c->status = 0;
|
||||
|
||||
reinit_completion(&i2c->complete);
|
||||
|
||||
spacemit_i2c_start(i2c);
|
||||
|
||||
time_left = wait_for_completion_timeout(&i2c->complete,
|
||||
i2c->adapt.timeout);
|
||||
if (!time_left) {
|
||||
dev_err(i2c->dev, "msg completion timeout\n");
|
||||
spacemit_i2c_conditionally_reset_bus(i2c);
|
||||
spacemit_i2c_reset(i2c);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (i2c->status & SPACEMIT_SR_ERR)
|
||||
return spacemit_i2c_handle_err(i2c);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool spacemit_i2c_is_last_msg(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
if (i2c->msg_idx != i2c->msg_num - 1)
|
||||
|
|
@ -347,8 +349,23 @@ static bool spacemit_i2c_is_last_msg(struct spacemit_i2c_dev *i2c)
|
|||
return !i2c->unprocessed;
|
||||
}
|
||||
|
||||
static inline void spacemit_i2c_complete(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
/* SPACEMIT_STATE_IDLE avoids triggering the next byte */
|
||||
i2c->state = SPACEMIT_STATE_IDLE;
|
||||
|
||||
if (i2c->use_pio)
|
||||
return;
|
||||
|
||||
complete(&i2c->complete);
|
||||
}
|
||||
|
||||
static void spacemit_i2c_handle_write(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
/* If there's no space in the IDBR, we're done */
|
||||
if (!(i2c->status & SPACEMIT_SR_ITE))
|
||||
return;
|
||||
|
||||
/* if transfer completes, SPACEMIT_ISR will handle it */
|
||||
if (i2c->status & SPACEMIT_SR_MSD)
|
||||
return;
|
||||
|
|
@ -359,16 +376,19 @@ static void spacemit_i2c_handle_write(struct spacemit_i2c_dev *i2c)
|
|||
return;
|
||||
}
|
||||
|
||||
/* SPACEMIT_STATE_IDLE avoids trigger next byte */
|
||||
i2c->state = SPACEMIT_STATE_IDLE;
|
||||
complete(&i2c->complete);
|
||||
spacemit_i2c_complete(i2c);
|
||||
}
|
||||
|
||||
static void spacemit_i2c_handle_read(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
/* If there's nothing in the IDBR, we're done */
|
||||
if (!(i2c->status & SPACEMIT_SR_IRF))
|
||||
return;
|
||||
|
||||
if (i2c->unprocessed) {
|
||||
*i2c->msg_buf++ = readl(i2c->base + SPACEMIT_IDBR);
|
||||
i2c->unprocessed--;
|
||||
return;
|
||||
}
|
||||
|
||||
/* if transfer completes, SPACEMIT_ISR will handle it */
|
||||
|
|
@ -379,9 +399,7 @@ static void spacemit_i2c_handle_read(struct spacemit_i2c_dev *i2c)
|
|||
if (i2c->unprocessed)
|
||||
return;
|
||||
|
||||
/* SPACEMIT_STATE_IDLE avoids trigger next byte */
|
||||
i2c->state = SPACEMIT_STATE_IDLE;
|
||||
complete(&i2c->complete);
|
||||
spacemit_i2c_complete(i2c);
|
||||
}
|
||||
|
||||
static void spacemit_i2c_handle_start(struct spacemit_i2c_dev *i2c)
|
||||
|
|
@ -415,29 +433,16 @@ static void spacemit_i2c_err_check(struct spacemit_i2c_dev *i2c)
|
|||
|
||||
spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK);
|
||||
|
||||
i2c->state = SPACEMIT_STATE_IDLE;
|
||||
complete(&i2c->complete);
|
||||
spacemit_i2c_complete(i2c);
|
||||
}
|
||||
|
||||
static irqreturn_t spacemit_i2c_irq_handler(int irq, void *devid)
|
||||
static void spacemit_i2c_handle_state(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
struct spacemit_i2c_dev *i2c = devid;
|
||||
u32 status, val;
|
||||
|
||||
status = readl(i2c->base + SPACEMIT_ISR);
|
||||
if (!status)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
i2c->status = status;
|
||||
|
||||
spacemit_i2c_clear_int_status(i2c, status);
|
||||
u32 val;
|
||||
|
||||
if (i2c->status & SPACEMIT_SR_ERR)
|
||||
goto err_out;
|
||||
|
||||
val = readl(i2c->base + SPACEMIT_ICR);
|
||||
val &= ~(SPACEMIT_CR_TB | SPACEMIT_CR_ACKNAK | SPACEMIT_CR_STOP | SPACEMIT_CR_START);
|
||||
|
||||
switch (i2c->state) {
|
||||
case SPACEMIT_STATE_START:
|
||||
spacemit_i2c_handle_start(i2c);
|
||||
|
|
@ -453,7 +458,12 @@ static irqreturn_t spacemit_i2c_irq_handler(int irq, void *devid)
|
|||
}
|
||||
|
||||
if (i2c->state != SPACEMIT_STATE_IDLE) {
|
||||
val |= SPACEMIT_CR_TB | SPACEMIT_CR_ALDIE;
|
||||
val = readl(i2c->base + SPACEMIT_ICR);
|
||||
val &= ~(SPACEMIT_CR_TB | SPACEMIT_CR_ACKNAK |
|
||||
SPACEMIT_CR_STOP | SPACEMIT_CR_START);
|
||||
val |= SPACEMIT_CR_TB;
|
||||
if (!i2c->use_pio)
|
||||
val |= SPACEMIT_CR_ALDIE;
|
||||
|
||||
if (spacemit_i2c_is_last_msg(i2c)) {
|
||||
/* trigger next byte with stop */
|
||||
|
|
@ -467,6 +477,133 @@ static irqreturn_t spacemit_i2c_irq_handler(int irq, void *devid)
|
|||
|
||||
err_out:
|
||||
spacemit_i2c_err_check(i2c);
|
||||
}
|
||||
|
||||
/*
|
||||
* In PIO mode, this function is used as a replacement for
|
||||
* wait_for_completion_timeout(), whose return value indicates
|
||||
* the remaining time.
|
||||
*
|
||||
* We do not have a meaningful remaining-time value here, so
|
||||
* return a non-zero value on success to indicate "not timed out".
|
||||
* Returning 1 ensures callers treating the return value as
|
||||
* time_left will not incorrectly report a timeout.
|
||||
*/
|
||||
static int spacemit_i2c_wait_pio_xfer(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
u32 mask, msec = jiffies_to_msecs(i2c->adapt.timeout);
|
||||
ktime_t timeout = ktime_add_ms(ktime_get(), msec);
|
||||
int ret;
|
||||
|
||||
mask = SPACEMIT_SR_IRF | SPACEMIT_SR_ITE;
|
||||
|
||||
do {
|
||||
i2c->status = readl(i2c->base + SPACEMIT_ISR);
|
||||
|
||||
spacemit_i2c_clear_int_status(i2c, i2c->status);
|
||||
|
||||
if (i2c->status & mask)
|
||||
spacemit_i2c_handle_state(i2c);
|
||||
else
|
||||
udelay(SPACEMIT_POLL_INTERVAL);
|
||||
} while (i2c->unprocessed && ktime_compare(ktime_get(), timeout) < 0);
|
||||
|
||||
if (i2c->unprocessed)
|
||||
return 0;
|
||||
|
||||
if (i2c->read)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* If this is the last byte to write of the current message,
|
||||
* we have to wait here. Otherwise, control will proceed directly
|
||||
* to start(), which would overwrite the current data.
|
||||
*/
|
||||
ret = readl_poll_timeout_atomic(i2c->base + SPACEMIT_ISR,
|
||||
i2c->status, i2c->status & SPACEMIT_SR_ITE,
|
||||
SPACEMIT_POLL_INTERVAL, SPACEMIT_POLL_TIMEOUT);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* For writes: in interrupt mode, an ITE (write-empty) interrupt is triggered
|
||||
* after the last byte, and the MSD-related handling takes place there.
|
||||
* In PIO mode, however, we need to explicitly call err_check() to emulate this
|
||||
* step, otherwise the next transfer will fail.
|
||||
*/
|
||||
if (i2c->msg_idx == i2c->msg_num - 1) {
|
||||
mask = SPACEMIT_SR_MSD | SPACEMIT_SR_ERR;
|
||||
/*
|
||||
* In some cases, MSD may not arrive immediately;
|
||||
* wait here to handle that.
|
||||
*/
|
||||
ret = readl_poll_timeout_atomic(i2c->base + SPACEMIT_ISR,
|
||||
i2c->status, i2c->status & mask,
|
||||
SPACEMIT_POLL_INTERVAL, SPACEMIT_POLL_TIMEOUT);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
spacemit_i2c_err_check(i2c);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int spacemit_i2c_wait_xfer_complete(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
if (i2c->use_pio)
|
||||
return spacemit_i2c_wait_pio_xfer(i2c);
|
||||
|
||||
return wait_for_completion_timeout(&i2c->complete,
|
||||
i2c->adapt.timeout);
|
||||
}
|
||||
|
||||
static int spacemit_i2c_xfer_msg(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
unsigned long time_left;
|
||||
struct i2c_msg *msg;
|
||||
|
||||
for (i2c->msg_idx = 0; i2c->msg_idx < i2c->msg_num; i2c->msg_idx++) {
|
||||
msg = &i2c->msgs[i2c->msg_idx];
|
||||
i2c->msg_buf = msg->buf;
|
||||
i2c->unprocessed = msg->len;
|
||||
i2c->status = 0;
|
||||
|
||||
reinit_completion(&i2c->complete);
|
||||
|
||||
spacemit_i2c_start(i2c);
|
||||
|
||||
time_left = spacemit_i2c_wait_xfer_complete(i2c);
|
||||
|
||||
if (!time_left) {
|
||||
dev_err(i2c->dev, "msg completion timeout\n");
|
||||
spacemit_i2c_conditionally_reset_bus(i2c);
|
||||
spacemit_i2c_reset(i2c);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (i2c->status & SPACEMIT_SR_ERR)
|
||||
return spacemit_i2c_handle_err(i2c);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t spacemit_i2c_irq_handler(int irq, void *devid)
|
||||
{
|
||||
struct spacemit_i2c_dev *i2c = devid;
|
||||
u32 status;
|
||||
|
||||
status = readl(i2c->base + SPACEMIT_ISR);
|
||||
if (!status)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
i2c->status = status;
|
||||
|
||||
spacemit_i2c_clear_int_status(i2c, status);
|
||||
|
||||
spacemit_i2c_handle_state(i2c);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
|
@ -475,6 +612,11 @@ static void spacemit_i2c_calc_timeout(struct spacemit_i2c_dev *i2c)
|
|||
unsigned long timeout;
|
||||
int idx = 0, cnt = 0;
|
||||
|
||||
if (i2c->use_pio) {
|
||||
i2c->adapt.timeout = msecs_to_jiffies(SPACEMIT_WAIT_TIMEOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
for (; idx < i2c->msg_num; idx++)
|
||||
cnt += (i2c->msgs + idx)->len + 1;
|
||||
|
||||
|
|
@ -487,11 +629,14 @@ static void spacemit_i2c_calc_timeout(struct spacemit_i2c_dev *i2c)
|
|||
i2c->adapt.timeout = usecs_to_jiffies(timeout + USEC_PER_SEC / 10) / i2c->msg_num;
|
||||
}
|
||||
|
||||
static int spacemit_i2c_xfer(struct i2c_adapter *adapt, struct i2c_msg *msgs, int num)
|
||||
static inline int
|
||||
spacemit_i2c_xfer_common(struct i2c_adapter *adapt, struct i2c_msg *msgs, int num, bool use_pio)
|
||||
{
|
||||
struct spacemit_i2c_dev *i2c = i2c_get_adapdata(adapt);
|
||||
int ret;
|
||||
|
||||
i2c->use_pio = use_pio;
|
||||
|
||||
i2c->msgs = msgs;
|
||||
i2c->msg_num = num;
|
||||
|
||||
|
|
@ -519,6 +664,16 @@ static int spacemit_i2c_xfer(struct i2c_adapter *adapt, struct i2c_msg *msgs, in
|
|||
return ret < 0 ? ret : num;
|
||||
}
|
||||
|
||||
static int spacemit_i2c_xfer(struct i2c_adapter *adapt, struct i2c_msg *msgs, int num)
|
||||
{
|
||||
return spacemit_i2c_xfer_common(adapt, msgs, num, false);
|
||||
}
|
||||
|
||||
static int spacemit_i2c_pio_xfer_atomic(struct i2c_adapter *adapt, struct i2c_msg *msgs, int num)
|
||||
{
|
||||
return spacemit_i2c_xfer_common(adapt, msgs, num, true);
|
||||
}
|
||||
|
||||
static u32 spacemit_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
|
||||
|
|
@ -526,6 +681,7 @@ static u32 spacemit_i2c_func(struct i2c_adapter *adap)
|
|||
|
||||
static const struct i2c_algorithm spacemit_i2c_algo = {
|
||||
.xfer = spacemit_i2c_xfer,
|
||||
.xfer_atomic = spacemit_i2c_pio_xfer_atomic,
|
||||
.functionality = spacemit_i2c_func,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1384,7 +1384,7 @@ static irqreturn_t npcm_i2c_int_slave_handler(struct npcm_i2c *bus)
|
|||
*/
|
||||
bus->operation = I2C_NO_OPER;
|
||||
bus->own_slave_addr = 0xFF;
|
||||
i2c_slave_event(bus->slave, I2C_SLAVE_STOP, 0);
|
||||
i2c_slave_event(bus->slave, I2C_SLAVE_STOP, NULL);
|
||||
iowrite8(NPCM_I2CST_SLVSTP, bus->reg + NPCM_I2CST);
|
||||
if (bus->fifo_use) {
|
||||
npcm_i2c_clear_fifo_int(bus);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
/*
|
||||
|
|
@ -258,7 +259,7 @@ static void ocores_process_timeout(struct ocores_i2c *i2c)
|
|||
* @reg: register to query
|
||||
* @mask: bitmask to apply on register value
|
||||
* @val: expected result
|
||||
* @timeout: timeout in jiffies
|
||||
* @timeout_us: timeout in microseconds
|
||||
*
|
||||
* Timeout is necessary to avoid to stay here forever when the chip
|
||||
* does not answer correctly.
|
||||
|
|
@ -267,21 +268,14 @@ static void ocores_process_timeout(struct ocores_i2c *i2c)
|
|||
*/
|
||||
static int ocores_wait(struct ocores_i2c *i2c,
|
||||
int reg, u8 mask, u8 val,
|
||||
const unsigned long timeout)
|
||||
unsigned long timeout_us)
|
||||
{
|
||||
unsigned long j;
|
||||
u8 status;
|
||||
|
||||
j = jiffies + timeout;
|
||||
while (1) {
|
||||
u8 status = oc_getreg(i2c, reg);
|
||||
|
||||
if ((status & mask) == val)
|
||||
break;
|
||||
|
||||
if (time_after(jiffies, j))
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
return 0;
|
||||
return read_poll_timeout_atomic(oc_getreg, status,
|
||||
(status & mask) == val,
|
||||
0, timeout_us, false,
|
||||
i2c, reg);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -314,7 +308,7 @@ static int ocores_poll_wait(struct ocores_i2c *i2c)
|
|||
* once we are here we expect to get the expected result immediately
|
||||
* so if after 1ms we timeout then something is broken.
|
||||
*/
|
||||
err = ocores_wait(i2c, OCI2C_STATUS, mask, 0, msecs_to_jiffies(1));
|
||||
err = ocores_wait(i2c, OCI2C_STATUS, mask, 0, 1000);
|
||||
if (err)
|
||||
dev_warn(i2c->adap.dev.parent,
|
||||
"%s: STATUS timeout, bit 0x%x did not clear in 1ms\n",
|
||||
|
|
|
|||
|
|
@ -71,9 +71,6 @@
|
|||
#define NUM_MASTERS 2
|
||||
#define NUM_QUEUES 2
|
||||
|
||||
/* Max number of resources + 1 for a NULL terminator */
|
||||
#define CCI_RES_MAX 6
|
||||
|
||||
#define CCI_I2C_SET_PARAM 1
|
||||
#define CCI_I2C_REPORT 8
|
||||
#define CCI_I2C_WRITE 9
|
||||
|
|
|
|||
|
|
@ -625,8 +625,8 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
|
|||
{
|
||||
struct gpi_i2c_config *peripheral;
|
||||
unsigned int flags;
|
||||
void *dma_buf;
|
||||
dma_addr_t addr;
|
||||
void *dma_buf = NULL;
|
||||
dma_addr_t addr = 0;
|
||||
enum dma_data_direction map_dirn;
|
||||
enum dma_transfer_direction dma_dirn;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
|
|
@ -639,6 +639,16 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
|
|||
gi2c_gpi_xfer = &gi2c->i2c_multi_desc_config;
|
||||
msg_idx = gi2c_gpi_xfer->msg_idx_cnt;
|
||||
|
||||
/*
|
||||
* Skip TX DMA mapping for a read message (I2C_M_RD) to avoid
|
||||
* programming an extra TX DMA TRE that would cause an unintended
|
||||
* write cycle on the I2C bus before the actual read operation.
|
||||
*/
|
||||
if (op == I2C_WRITE && msgs[msg_idx].flags & I2C_M_RD) {
|
||||
peripheral->multi_msg = true;
|
||||
goto skip_tx_dma_map;
|
||||
}
|
||||
|
||||
dma_buf = i2c_get_dma_safe_msg_buf(&msgs[msg_idx], 1);
|
||||
if (!dma_buf) {
|
||||
ret = -ENOMEM;
|
||||
|
|
@ -658,6 +668,7 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
|
|||
goto out;
|
||||
}
|
||||
|
||||
skip_tx_dma_map:
|
||||
if (gi2c->is_tx_multi_desc_xfer) {
|
||||
flags = DMA_CTRL_ACK;
|
||||
|
||||
|
|
@ -740,9 +751,12 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
|
|||
return 0;
|
||||
|
||||
err_config:
|
||||
/* Avoid DMA unmap as the write operation skipped DMA mapping */
|
||||
if (dma_buf) {
|
||||
dma_unmap_single(gi2c->se.dev->parent, addr,
|
||||
msgs[msg_idx].len, map_dirn);
|
||||
i2c_put_dma_safe_msg_buf(dma_buf, &msgs[msg_idx], false);
|
||||
}
|
||||
|
||||
out:
|
||||
gi2c->err = ret;
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ static int osif_probe(struct usb_interface *interface,
|
|||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->usb_dev = usb_get_dev(interface_to_usbdev(interface));
|
||||
priv->usb_dev = interface_to_usbdev(interface);
|
||||
priv->interface = interface;
|
||||
|
||||
usb_set_intfdata(interface, priv);
|
||||
|
|
@ -163,7 +163,6 @@ static int osif_probe(struct usb_interface *interface,
|
|||
NULL, 0);
|
||||
if (ret) {
|
||||
dev_err(&interface->dev, "failure sending bit rate");
|
||||
usb_put_dev(priv->usb_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -184,7 +183,6 @@ static void osif_disconnect(struct usb_interface *interface)
|
|||
|
||||
i2c_del_adapter(&(priv->adapter));
|
||||
usb_set_intfdata(interface, NULL);
|
||||
usb_put_dev(priv->usb_dev);
|
||||
}
|
||||
|
||||
static struct usb_driver osif_driver = {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-mux.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
|
|
@ -11,10 +12,16 @@
|
|||
#include <linux/unaligned.h>
|
||||
|
||||
enum rtl9300_bus_freq {
|
||||
RTL9300_I2C_STD_FREQ,
|
||||
RTL9300_I2C_FAST_FREQ,
|
||||
RTL9300_I2C_STD_FREQ, // 100kHz
|
||||
RTL9300_I2C_FAST_FREQ, // 400kHz
|
||||
RTL9300_I2C_SUPER_FAST_FREQ, // 2.5MHz
|
||||
RTL9300_I2C_SLOW_FREQ, // 50kHz
|
||||
};
|
||||
|
||||
#define RTL9300_I2C_MAX_SUPER_FAST_FREQ 2500000
|
||||
#define RTL9300_I2C_MAX_SLOW_FREQ 50000
|
||||
|
||||
|
||||
struct rtl9300_i2c;
|
||||
|
||||
struct rtl9300_i2c_chan {
|
||||
|
|
@ -22,6 +29,7 @@ struct rtl9300_i2c_chan {
|
|||
struct rtl9300_i2c *i2c;
|
||||
enum rtl9300_bus_freq bus_freq;
|
||||
u8 sda_num;
|
||||
u32 clk_div;
|
||||
};
|
||||
|
||||
enum rtl9300_i2c_reg_scope {
|
||||
|
|
@ -47,6 +55,9 @@ enum rtl9300_i2c_reg_fields {
|
|||
F_SCL_SEL,
|
||||
F_SDA_OUT_SEL,
|
||||
F_SDA_SEL,
|
||||
F_BUSY,
|
||||
F_CLK_DIV,
|
||||
F_EXT_SCK_5MS,
|
||||
|
||||
/* keep last */
|
||||
F_NUM_FIELDS
|
||||
|
|
@ -55,12 +66,22 @@ enum rtl9300_i2c_reg_fields {
|
|||
struct rtl9300_i2c_drv_data {
|
||||
struct rtl9300_i2c_reg_field field_desc[F_NUM_FIELDS];
|
||||
int (*select_scl)(struct rtl9300_i2c *i2c, u8 scl);
|
||||
u32 data_reg;
|
||||
int (*config_chan)(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan);
|
||||
void (*config_clock)(u32 clock_freq, struct rtl9300_i2c_chan *chan);
|
||||
int (*misc_init)(struct rtl9300_i2c *i2c);
|
||||
u32 rd_reg;
|
||||
u32 wd_reg;
|
||||
u8 max_nchan;
|
||||
u8 max_data_len;
|
||||
u8 reg_addr_8bit_len;
|
||||
};
|
||||
|
||||
#define RTL9300_I2C_MUX_NCHAN 8
|
||||
#define RTL9310_I2C_MUX_NCHAN 12
|
||||
#define RTL9607_I2C_MUX_NCHAN 1
|
||||
|
||||
#define RTL9300_I2C_MAX_DATA_LEN 16
|
||||
#define RTL9607_I2C_MAX_DATA_LEN 4
|
||||
|
||||
struct rtl9300_i2c {
|
||||
struct regmap *regmap;
|
||||
|
|
@ -68,10 +89,12 @@ struct rtl9300_i2c {
|
|||
struct rtl9300_i2c_chan chans[RTL9310_I2C_MUX_NCHAN];
|
||||
struct regmap_field *fields[F_NUM_FIELDS];
|
||||
u32 reg_base;
|
||||
u32 data_reg;
|
||||
u32 rd_reg;
|
||||
u32 wd_reg;
|
||||
u8 scl_num;
|
||||
u8 sda_num;
|
||||
struct mutex lock;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
DEFINE_GUARD(rtl9300_i2c, struct rtl9300_i2c *, mutex_lock(&_T->lock), mutex_unlock(&_T->lock))
|
||||
|
|
@ -99,6 +122,7 @@ struct rtl9300_i2c_xfer {
|
|||
#define RTL9300_I2C_MST_DATA_WORD2 0x10
|
||||
#define RTL9300_I2C_MST_DATA_WORD3 0x14
|
||||
#define RTL9300_I2C_MST_GLB_CTRL 0x384
|
||||
#define RTL9300_REG_ADDR_8BIT_LEN 1
|
||||
|
||||
#define RTL9310_I2C_MST_IF_CTRL 0x1004
|
||||
#define RTL9310_I2C_MST_IF_SEL 0x1008
|
||||
|
|
@ -106,6 +130,14 @@ struct rtl9300_i2c_xfer {
|
|||
#define RTL9310_I2C_MST_MEMADDR_CTRL 0x4
|
||||
#define RTL9310_I2C_MST_DATA_CTRL 0x8
|
||||
|
||||
#define RTL9607_I2C_CONFIG 0x22f50
|
||||
#define RTL9607_IO_MODE_EN 0x23014
|
||||
#define RTL9607_I2C_IND_WD 0x0
|
||||
#define RTL9607_I2C_IND_ADR 0x8
|
||||
#define RTL9607_I2C_IND_CMD 0x10
|
||||
#define RTL9607_I2C_IND_RD 0x18
|
||||
#define RTL9607_REG_ADDR_8BIT_LEN 0
|
||||
|
||||
static int rtl9300_i2c_reg_addr_set(struct rtl9300_i2c *i2c, u32 reg, u16 len)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -157,6 +189,58 @@ static int rtl9300_i2c_config_chan(struct rtl9300_i2c *i2c, struct rtl9300_i2c_c
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rtl9607_i2c_config_chan(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan)
|
||||
{
|
||||
const struct rtl9300_i2c_drv_data *drv_data;
|
||||
int ret;
|
||||
|
||||
if (i2c->sda_num == chan->sda_num)
|
||||
return 0;
|
||||
|
||||
ret = regmap_field_write(i2c->fields[F_CLK_DIV], chan->clk_div);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drv_data = device_get_match_data(i2c->dev);
|
||||
ret = drv_data->select_scl(i2c, i2c->scl_num);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
i2c->sda_num = chan->sda_num;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rtl9300_i2c_config_clock(u32 clock_freq, struct rtl9300_i2c_chan *chan)
|
||||
{
|
||||
struct rtl9300_i2c *i2c = chan->i2c;
|
||||
|
||||
switch (clock_freq) {
|
||||
case I2C_MAX_STANDARD_MODE_FREQ:
|
||||
chan->bus_freq = RTL9300_I2C_STD_FREQ;
|
||||
break;
|
||||
case I2C_MAX_FAST_MODE_FREQ:
|
||||
chan->bus_freq = RTL9300_I2C_FAST_FREQ;
|
||||
break;
|
||||
case RTL9300_I2C_MAX_SUPER_FAST_FREQ:
|
||||
chan->bus_freq = RTL9300_I2C_SUPER_FAST_FREQ;
|
||||
break;
|
||||
case RTL9300_I2C_MAX_SLOW_FREQ:
|
||||
chan->bus_freq = RTL9300_I2C_SLOW_FREQ;
|
||||
break;
|
||||
default:
|
||||
dev_warn(i2c->dev, "SDA%d clock-frequency %d not supported using default\n",
|
||||
chan->sda_num, clock_freq);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void rtl9607_i2c_config_clock(u32 clock_freq, struct rtl9300_i2c_chan *chan)
|
||||
{
|
||||
struct rtl9300_i2c *i2c = chan->i2c;
|
||||
|
||||
chan->clk_div = clk_get_rate(i2c->clk) / clock_freq - 1;
|
||||
}
|
||||
|
||||
static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, u8 len)
|
||||
{
|
||||
u32 vals[4] = {};
|
||||
|
|
@ -165,7 +249,7 @@ static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, u8 len)
|
|||
if (len > 16)
|
||||
return -EIO;
|
||||
|
||||
ret = regmap_bulk_read(i2c->regmap, i2c->data_reg, vals, ARRAY_SIZE(vals));
|
||||
ret = regmap_bulk_read(i2c->regmap, i2c->rd_reg, vals, ARRAY_SIZE(vals));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -192,19 +276,21 @@ static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, u8 len)
|
|||
vals[reg] |= buf[i] << shift;
|
||||
}
|
||||
|
||||
return regmap_bulk_write(i2c->regmap, i2c->data_reg, vals, ARRAY_SIZE(vals));
|
||||
return regmap_bulk_write(i2c->regmap, i2c->wd_reg, vals, ARRAY_SIZE(vals));
|
||||
}
|
||||
|
||||
static int rtl9300_i2c_writel(struct rtl9300_i2c *i2c, u32 data)
|
||||
{
|
||||
return regmap_write(i2c->regmap, i2c->data_reg, data);
|
||||
return regmap_write(i2c->regmap, i2c->wd_reg, data);
|
||||
}
|
||||
|
||||
static int rtl9300_i2c_prepare_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_xfer *xfer)
|
||||
{
|
||||
const struct rtl9300_i2c_drv_data *drv_data;
|
||||
int ret;
|
||||
|
||||
if (xfer->data_len < 1 || xfer->data_len > 16)
|
||||
drv_data = device_get_match_data(i2c->dev);
|
||||
if (xfer->data_len < 1 || xfer->data_len > drv_data->max_data_len)
|
||||
return -EINVAL;
|
||||
|
||||
ret = regmap_field_write(i2c->fields[F_DEV_ADDR], xfer->dev_addr);
|
||||
|
|
@ -249,7 +335,7 @@ static int rtl9300_i2c_do_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_xfer
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_field_read_poll_timeout(i2c->fields[F_I2C_TRIG], val, !val, 100, 100000);
|
||||
ret = regmap_field_read_poll_timeout(i2c->fields[F_BUSY], val, !val, 100, 100000);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -262,14 +348,14 @@ static int rtl9300_i2c_do_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_xfer
|
|||
if (!xfer->write) {
|
||||
switch (xfer->type) {
|
||||
case RTL9300_I2C_XFER_BYTE:
|
||||
ret = regmap_read(i2c->regmap, i2c->data_reg, &val);
|
||||
ret = regmap_read(i2c->regmap, i2c->rd_reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*xfer->data = val & 0xff;
|
||||
break;
|
||||
case RTL9300_I2C_XFER_WORD:
|
||||
ret = regmap_read(i2c->regmap, i2c->data_reg, &val);
|
||||
ret = regmap_read(i2c->regmap, i2c->rd_reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -291,6 +377,7 @@ static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned s
|
|||
union i2c_smbus_data *data)
|
||||
{
|
||||
struct rtl9300_i2c_chan *chan = i2c_get_adapdata(adap);
|
||||
const struct rtl9300_i2c_drv_data *drv_data;
|
||||
struct rtl9300_i2c *i2c = chan->i2c;
|
||||
struct rtl9300_i2c_xfer xfer = {0};
|
||||
int ret;
|
||||
|
|
@ -300,14 +387,15 @@ static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned s
|
|||
|
||||
guard(rtl9300_i2c)(i2c);
|
||||
|
||||
ret = rtl9300_i2c_config_chan(i2c, chan);
|
||||
drv_data = device_get_match_data(i2c->dev);
|
||||
ret = drv_data->config_chan(i2c, chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
xfer.dev_addr = addr & 0x7f;
|
||||
xfer.write = (read_write == I2C_SMBUS_WRITE);
|
||||
xfer.reg_addr = command;
|
||||
xfer.reg_addr_len = 1;
|
||||
xfer.reg_addr_len = drv_data->reg_addr_8bit_len;
|
||||
|
||||
switch (size) {
|
||||
case I2C_SMBUS_BYTE:
|
||||
|
|
@ -367,6 +455,17 @@ static struct i2c_adapter_quirks rtl9300_i2c_quirks = {
|
|||
.max_write_len = 16,
|
||||
};
|
||||
|
||||
static int rtl9300_i2c_init(struct rtl9300_i2c *i2c)
|
||||
{
|
||||
/* only use standard read format */
|
||||
return regmap_field_write(i2c->fields[F_RD_MODE], 0);
|
||||
}
|
||||
|
||||
static int rtl9607_i2c_init(struct rtl9300_i2c *i2c)
|
||||
{
|
||||
return regmap_field_write(i2c->fields[F_EXT_SCK_5MS], 1);
|
||||
}
|
||||
|
||||
static int rtl9300_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
|
@ -402,7 +501,8 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
|
|||
if (device_get_child_node_count(dev) > drv_data->max_nchan)
|
||||
return dev_err_probe(dev, -EINVAL, "Too many channels\n");
|
||||
|
||||
i2c->data_reg = i2c->reg_base + drv_data->data_reg;
|
||||
i2c->rd_reg = i2c->reg_base + drv_data->rd_reg;
|
||||
i2c->wd_reg = i2c->reg_base + drv_data->wd_reg;
|
||||
for (i = 0; i < F_NUM_FIELDS; i++) {
|
||||
fields[i] = drv_data->field_desc[i].field;
|
||||
if (drv_data->field_desc[i].scope == REG_SCOPE_MASTER)
|
||||
|
|
@ -413,6 +513,10 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
i2c->clk = devm_clk_get_optional_enabled(dev, NULL);
|
||||
if (IS_ERR(i2c->clk))
|
||||
return dev_err_probe(dev, PTR_ERR(i2c->clk), "Failed to enable i2c clock\n");
|
||||
|
||||
i = 0;
|
||||
for_each_child_of_node_scoped(dev->of_node, child) {
|
||||
struct rtl9300_i2c_chan *chan = &i2c->chans[i];
|
||||
|
|
@ -426,21 +530,11 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
clock_freq = I2C_MAX_STANDARD_MODE_FREQ;
|
||||
|
||||
switch (clock_freq) {
|
||||
case I2C_MAX_STANDARD_MODE_FREQ:
|
||||
chan->bus_freq = RTL9300_I2C_STD_FREQ;
|
||||
break;
|
||||
case I2C_MAX_FAST_MODE_FREQ:
|
||||
chan->bus_freq = RTL9300_I2C_FAST_FREQ;
|
||||
break;
|
||||
default:
|
||||
dev_warn(i2c->dev, "SDA%d clock-frequency %d not supported using default\n",
|
||||
sda_num, clock_freq);
|
||||
break;
|
||||
}
|
||||
|
||||
chan->sda_num = sda_num;
|
||||
chan->i2c = i2c;
|
||||
|
||||
drv_data->config_clock(clock_freq, chan);
|
||||
|
||||
adap = &i2c->chans[i].adap;
|
||||
adap->owner = THIS_MODULE;
|
||||
adap->algo = &rtl9300_i2c_algo;
|
||||
|
|
@ -458,8 +552,7 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
|
|||
}
|
||||
i2c->sda_num = 0xff;
|
||||
|
||||
/* only use standard read format */
|
||||
ret = regmap_field_write(i2c->fields[F_RD_MODE], 0);
|
||||
ret = drv_data->misc_init(i2c);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -485,10 +578,17 @@ static const struct rtl9300_i2c_drv_data rtl9300_i2c_drv_data = {
|
|||
[F_MEM_ADDR_WIDTH] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 2, 3),
|
||||
[F_SCL_FREQ] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 0, 1),
|
||||
[F_SDA_SEL] = GLB_REG_FIELD(RTL9300_I2C_MST_GLB_CTRL, 0, 7),
|
||||
[F_BUSY] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 0, 0),
|
||||
},
|
||||
.select_scl = rtl9300_i2c_select_scl,
|
||||
.data_reg = RTL9300_I2C_MST_DATA_WORD0,
|
||||
.config_chan = rtl9300_i2c_config_chan,
|
||||
.config_clock = rtl9300_i2c_config_clock,
|
||||
.misc_init = rtl9300_i2c_init,
|
||||
.rd_reg = RTL9300_I2C_MST_DATA_WORD0,
|
||||
.wd_reg = RTL9300_I2C_MST_DATA_WORD0,
|
||||
.max_nchan = RTL9300_I2C_MUX_NCHAN,
|
||||
.max_data_len = RTL9300_I2C_MAX_DATA_LEN,
|
||||
.reg_addr_8bit_len = RTL9300_REG_ADDR_8BIT_LEN,
|
||||
};
|
||||
|
||||
static const struct rtl9300_i2c_drv_data rtl9310_i2c_drv_data = {
|
||||
|
|
@ -505,10 +605,42 @@ static const struct rtl9300_i2c_drv_data rtl9310_i2c_drv_data = {
|
|||
[F_I2C_FAIL] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 1, 1),
|
||||
[F_I2C_TRIG] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 0, 0),
|
||||
[F_MEM_ADDR] = MST_REG_FIELD(RTL9310_I2C_MST_MEMADDR_CTRL, 0, 23),
|
||||
[F_BUSY] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 0, 0),
|
||||
},
|
||||
.select_scl = rtl9310_i2c_select_scl,
|
||||
.data_reg = RTL9310_I2C_MST_DATA_CTRL,
|
||||
.config_chan = rtl9300_i2c_config_chan,
|
||||
.config_clock = rtl9300_i2c_config_clock,
|
||||
.misc_init = rtl9300_i2c_init,
|
||||
.rd_reg = RTL9310_I2C_MST_DATA_CTRL,
|
||||
.wd_reg = RTL9310_I2C_MST_DATA_CTRL,
|
||||
.max_nchan = RTL9310_I2C_MUX_NCHAN,
|
||||
.max_data_len = RTL9300_I2C_MAX_DATA_LEN,
|
||||
.reg_addr_8bit_len = RTL9300_REG_ADDR_8BIT_LEN,
|
||||
};
|
||||
|
||||
static const struct rtl9300_i2c_drv_data rtl9607_i2c_drv_data = {
|
||||
.field_desc = {
|
||||
[F_SCL_SEL] = GLB_REG_FIELD(RTL9607_IO_MODE_EN, 13, 14),
|
||||
[F_EXT_SCK_5MS] = MST_REG_FIELD(RTL9607_I2C_CONFIG, 26, 26),
|
||||
[F_DEV_ADDR] = MST_REG_FIELD(RTL9607_I2C_CONFIG, 14, 20),
|
||||
[F_MEM_ADDR_WIDTH] = MST_REG_FIELD(RTL9607_I2C_CONFIG, 12, 13),
|
||||
[F_DATA_WIDTH] = MST_REG_FIELD(RTL9607_I2C_CONFIG, 10, 11),
|
||||
[F_CLK_DIV] = MST_REG_FIELD(RTL9607_I2C_CONFIG, 0, 9),
|
||||
[F_I2C_FAIL] = MST_REG_FIELD(RTL9607_I2C_IND_CMD, 3, 3),
|
||||
[F_BUSY] = MST_REG_FIELD(RTL9607_I2C_IND_CMD, 2, 2),
|
||||
[F_RWOP] = MST_REG_FIELD(RTL9607_I2C_IND_CMD, 1, 1),
|
||||
[F_I2C_TRIG] = MST_REG_FIELD(RTL9607_I2C_IND_CMD, 0, 0),
|
||||
[F_MEM_ADDR] = MST_REG_FIELD(RTL9607_I2C_IND_ADR, 0, 31),
|
||||
},
|
||||
.select_scl = rtl9310_i2c_select_scl,
|
||||
.config_chan = rtl9607_i2c_config_chan,
|
||||
.config_clock = rtl9607_i2c_config_clock,
|
||||
.misc_init = rtl9607_i2c_init,
|
||||
.rd_reg = RTL9607_I2C_IND_RD,
|
||||
.wd_reg = RTL9607_I2C_IND_WD,
|
||||
.max_nchan = RTL9607_I2C_MUX_NCHAN,
|
||||
.max_data_len = RTL9607_I2C_MAX_DATA_LEN,
|
||||
.reg_addr_8bit_len = RTL9607_REG_ADDR_8BIT_LEN,
|
||||
};
|
||||
|
||||
static const struct of_device_id i2c_rtl9300_dt_ids[] = {
|
||||
|
|
@ -520,6 +652,7 @@ static const struct of_device_id i2c_rtl9300_dt_ids[] = {
|
|||
{ .compatible = "realtek,rtl9311-i2c", .data = (void *) &rtl9310_i2c_drv_data },
|
||||
{ .compatible = "realtek,rtl9312-i2c", .data = (void *) &rtl9310_i2c_drv_data },
|
||||
{ .compatible = "realtek,rtl9313-i2c", .data = (void *) &rtl9310_i2c_drv_data },
|
||||
{ .compatible = "realtek,rtl9607-i2c", .data = (void *) &rtl9607_i2c_drv_data },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, i2c_rtl9300_dt_ids);
|
||||
|
|
|
|||
|
|
@ -503,8 +503,13 @@ static void i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
|
|||
i2c->msg->buf[i2c->msg_ptr++] = byte;
|
||||
|
||||
/* Add actual length to read for smbus block read */
|
||||
if (i2c->msg->flags & I2C_M_RECV_LEN && i2c->msg->len == 1)
|
||||
if (i2c->msg->flags & I2C_M_RECV_LEN && i2c->msg->len == 1) {
|
||||
if (byte == 0 || byte > I2C_SMBUS_BLOCK_MAX) {
|
||||
s3c24xx_i2c_stop(i2c, -EPROTO);
|
||||
break;
|
||||
}
|
||||
i2c->msg->len += byte;
|
||||
}
|
||||
prepare_read:
|
||||
if (is_msglast(i2c)) {
|
||||
/* last byte of buffer */
|
||||
|
|
|
|||
|
|
@ -30,38 +30,29 @@
|
|||
|
||||
#define BYTES_PER_FIFO_WORD 4
|
||||
|
||||
#define I2C_CNFG 0x000
|
||||
#define I2C_CNFG_DEBOUNCE_CNT GENMASK(14, 12)
|
||||
#define I2C_CNFG_PACKET_MODE_EN BIT(10)
|
||||
#define I2C_CNFG_NEW_MASTER_FSM BIT(11)
|
||||
#define I2C_CNFG_MULTI_MASTER_MODE BIT(17)
|
||||
#define I2C_STATUS 0x01c
|
||||
#define I2C_SL_CNFG 0x020
|
||||
|
||||
#define I2C_SL_CNFG_NACK BIT(1)
|
||||
#define I2C_SL_CNFG_NEWSL BIT(2)
|
||||
#define I2C_SL_ADDR1 0x02c
|
||||
#define I2C_SL_ADDR2 0x030
|
||||
#define I2C_TLOW_SEXT 0x034
|
||||
#define I2C_TX_FIFO 0x050
|
||||
#define I2C_RX_FIFO 0x054
|
||||
#define I2C_PACKET_TRANSFER_STATUS 0x058
|
||||
#define I2C_FIFO_CONTROL 0x05c
|
||||
|
||||
#define I2C_FIFO_CONTROL_TX_FLUSH BIT(1)
|
||||
#define I2C_FIFO_CONTROL_RX_FLUSH BIT(0)
|
||||
#define I2C_FIFO_CONTROL_TX_TRIG(x) (((x) - 1) << 5)
|
||||
#define I2C_FIFO_CONTROL_RX_TRIG(x) (((x) - 1) << 2)
|
||||
#define I2C_FIFO_STATUS 0x060
|
||||
|
||||
#define I2C_FIFO_STATUS_TX GENMASK(7, 4)
|
||||
#define I2C_FIFO_STATUS_RX GENMASK(3, 0)
|
||||
#define I2C_INT_MASK 0x064
|
||||
#define I2C_INT_STATUS 0x068
|
||||
|
||||
#define I2C_INT_BUS_CLR_DONE BIT(11)
|
||||
#define I2C_INT_PACKET_XFER_COMPLETE BIT(7)
|
||||
#define I2C_INT_NO_ACK BIT(3)
|
||||
#define I2C_INT_ARBITRATION_LOST BIT(2)
|
||||
#define I2C_INT_TX_FIFO_DATA_REQ BIT(1)
|
||||
#define I2C_INT_RX_FIFO_DATA_REQ BIT(0)
|
||||
#define I2C_CLK_DIVISOR 0x06c
|
||||
|
||||
#define I2C_CLK_DIVISOR_STD_FAST_MODE GENMASK(31, 16)
|
||||
#define I2C_CLK_DIVISOR_HSMODE GENMASK(15, 0)
|
||||
|
||||
|
|
@ -94,50 +85,38 @@
|
|||
#define I2C_HEADER_CONTINUE_XFER BIT(15)
|
||||
#define I2C_HEADER_SLAVE_ADDR_SHIFT 1
|
||||
|
||||
#define I2C_BUS_CLEAR_CNFG 0x084
|
||||
#define I2C_BC_SCLK_THRESHOLD GENMASK(23, 16)
|
||||
#define I2C_BC_STOP_COND BIT(2)
|
||||
#define I2C_BC_TERMINATE BIT(1)
|
||||
#define I2C_BC_ENABLE BIT(0)
|
||||
#define I2C_BUS_CLEAR_STATUS 0x088
|
||||
|
||||
#define I2C_BC_STATUS BIT(0)
|
||||
|
||||
#define I2C_CONFIG_LOAD 0x08c
|
||||
#define I2C_MSTR_CONFIG_LOAD BIT(0)
|
||||
|
||||
#define I2C_CLKEN_OVERRIDE 0x090
|
||||
#define I2C_MST_CORE_CLKEN_OVR BIT(0)
|
||||
|
||||
#define I2C_INTERFACE_TIMING_0 0x094
|
||||
#define I2C_INTERFACE_TIMING_THIGH GENMASK(13, 8)
|
||||
#define I2C_INTERFACE_TIMING_TLOW GENMASK(5, 0)
|
||||
#define I2C_INTERFACE_TIMING_1 0x098
|
||||
#define I2C_INTERFACE_TIMING_TBUF GENMASK(29, 24)
|
||||
#define I2C_INTERFACE_TIMING_TSU_STO GENMASK(21, 16)
|
||||
#define I2C_INTERFACE_TIMING_THD_STA GENMASK(13, 8)
|
||||
#define I2C_INTERFACE_TIMING_TSU_STA GENMASK(5, 0)
|
||||
|
||||
#define I2C_HS_INTERFACE_TIMING_0 0x09c
|
||||
#define I2C_HS_INTERFACE_TIMING_THIGH GENMASK(13, 8)
|
||||
#define I2C_HS_INTERFACE_TIMING_TLOW GENMASK(5, 0)
|
||||
#define I2C_HS_INTERFACE_TIMING_1 0x0a0
|
||||
#define I2C_HS_INTERFACE_TIMING_TSU_STO GENMASK(21, 16)
|
||||
#define I2C_HS_INTERFACE_TIMING_THD_STA GENMASK(13, 8)
|
||||
#define I2C_HS_INTERFACE_TIMING_TSU_STA GENMASK(5, 0)
|
||||
|
||||
#define I2C_MST_FIFO_CONTROL 0x0b4
|
||||
#define I2C_MST_FIFO_CONTROL_RX_FLUSH BIT(0)
|
||||
#define I2C_MST_FIFO_CONTROL_TX_FLUSH BIT(1)
|
||||
#define I2C_MST_FIFO_CONTROL_RX_TRIG(x) (((x) - 1) << 4)
|
||||
#define I2C_MST_FIFO_CONTROL_TX_TRIG(x) (((x) - 1) << 16)
|
||||
|
||||
#define I2C_MST_FIFO_STATUS 0x0b8
|
||||
#define I2C_MST_FIFO_STATUS_TX GENMASK(23, 16)
|
||||
#define I2C_MST_FIFO_STATUS_RX GENMASK(7, 0)
|
||||
|
||||
#define I2C_MASTER_RESET_CNTRL 0x0a8
|
||||
|
||||
#define I2C_SW_MUTEX 0x0ec
|
||||
#define I2C_SW_MUTEX_REQUEST GENMASK(3, 0)
|
||||
#define I2C_SW_MUTEX_GRANT GENMASK(7, 4)
|
||||
#define I2C_SW_MUTEX_ID_CCPLEX 9
|
||||
|
|
@ -159,6 +138,171 @@
|
|||
*/
|
||||
#define I2C_PIO_MODE_PREFERRED_LEN 32
|
||||
|
||||
struct tegra_i2c_regs {
|
||||
unsigned int cnfg;
|
||||
unsigned int status;
|
||||
unsigned int sl_cnfg;
|
||||
unsigned int sl_addr1;
|
||||
unsigned int sl_addr2;
|
||||
unsigned int tlow_sext;
|
||||
unsigned int tx_fifo;
|
||||
unsigned int rx_fifo;
|
||||
unsigned int packet_transfer_status;
|
||||
unsigned int fifo_control;
|
||||
unsigned int fifo_status;
|
||||
unsigned int int_mask;
|
||||
unsigned int int_status;
|
||||
unsigned int clk_divisor;
|
||||
unsigned int bus_clear_cnfg;
|
||||
unsigned int bus_clear_status;
|
||||
unsigned int config_load;
|
||||
unsigned int clken_override;
|
||||
unsigned int interface_timing_0;
|
||||
unsigned int interface_timing_1;
|
||||
unsigned int hs_interface_timing_0;
|
||||
unsigned int hs_interface_timing_1;
|
||||
unsigned int master_reset_cntrl;
|
||||
unsigned int mst_fifo_control;
|
||||
unsigned int mst_fifo_status;
|
||||
unsigned int sw_mutex;
|
||||
};
|
||||
|
||||
static const struct tegra_i2c_regs tegra20_i2c_regs = {
|
||||
.cnfg = 0x000,
|
||||
.status = 0x01c,
|
||||
.sl_cnfg = 0x020,
|
||||
.sl_addr1 = 0x02c,
|
||||
.sl_addr2 = 0x030,
|
||||
.tx_fifo = 0x050,
|
||||
.rx_fifo = 0x054,
|
||||
.packet_transfer_status = 0x058,
|
||||
.fifo_control = 0x05c,
|
||||
.fifo_status = 0x060,
|
||||
.int_mask = 0x064,
|
||||
.int_status = 0x068,
|
||||
.clk_divisor = 0x06c,
|
||||
.bus_clear_cnfg = 0x084,
|
||||
.bus_clear_status = 0x088,
|
||||
.config_load = 0x08c,
|
||||
.clken_override = 0x090,
|
||||
.interface_timing_0 = 0x094,
|
||||
.interface_timing_1 = 0x098,
|
||||
.hs_interface_timing_0 = 0x09c,
|
||||
.hs_interface_timing_1 = 0x0a0,
|
||||
.master_reset_cntrl = 0x0a8,
|
||||
.mst_fifo_control = 0x0b4,
|
||||
.mst_fifo_status = 0x0b8,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)
|
||||
static const struct tegra_i2c_regs tegra20_dvc_i2c_regs = {
|
||||
.cnfg = 0x040,
|
||||
.status = 0x05c,
|
||||
.tx_fifo = 0x060,
|
||||
.rx_fifo = 0x064,
|
||||
.packet_transfer_status = 0x068,
|
||||
.fifo_control = 0x06c,
|
||||
.fifo_status = 0x070,
|
||||
.int_mask = 0x074,
|
||||
.int_status = 0x078,
|
||||
.clk_divisor = 0x07c,
|
||||
.bus_clear_cnfg = 0x094,
|
||||
.bus_clear_status = 0x098,
|
||||
.config_load = 0x09c,
|
||||
.clken_override = 0x0a0,
|
||||
.interface_timing_0 = 0x0a4,
|
||||
.interface_timing_1 = 0x0a8,
|
||||
.hs_interface_timing_0 = 0x0ac,
|
||||
.hs_interface_timing_1 = 0x0b0,
|
||||
.master_reset_cntrl = 0x0b8,
|
||||
.mst_fifo_control = 0x0c4,
|
||||
.mst_fifo_status = 0x0c8,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
|
||||
static const struct tegra_i2c_regs tegra210_vi_i2c_regs = {
|
||||
.cnfg = 0x0c00,
|
||||
.status = 0x0c70,
|
||||
.tlow_sext = 0x0cd0,
|
||||
.tx_fifo = 0x0d40,
|
||||
.rx_fifo = 0x0d50,
|
||||
.packet_transfer_status = 0x0d60,
|
||||
.fifo_control = 0x0d70,
|
||||
.fifo_status = 0x0d80,
|
||||
.int_mask = 0x0d90,
|
||||
.int_status = 0x0da0,
|
||||
.clk_divisor = 0x0db0,
|
||||
.bus_clear_cnfg = 0x0e10,
|
||||
.bus_clear_status = 0x0e20,
|
||||
.config_load = 0x0e30,
|
||||
.clken_override = 0x0e40,
|
||||
.interface_timing_0 = 0x0e50,
|
||||
.interface_timing_1 = 0x0e60,
|
||||
.hs_interface_timing_0 = 0x0e70,
|
||||
.hs_interface_timing_1 = 0x0e80,
|
||||
.master_reset_cntrl = 0x0ea0,
|
||||
.mst_fifo_control = 0x0ed0,
|
||||
.mst_fifo_status = 0x0ee0,
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct tegra_i2c_regs tegra264_i2c_regs = {
|
||||
.cnfg = 0x000,
|
||||
.status = 0x01c,
|
||||
.sl_cnfg = 0x020,
|
||||
.sl_addr1 = 0x02c,
|
||||
.sl_addr2 = 0x030,
|
||||
.tx_fifo = 0x050,
|
||||
.rx_fifo = 0x054,
|
||||
.packet_transfer_status = 0x058,
|
||||
.fifo_control = 0x05c,
|
||||
.fifo_status = 0x060,
|
||||
.int_mask = 0x064,
|
||||
.int_status = 0x068,
|
||||
.clk_divisor = 0x06c,
|
||||
.bus_clear_cnfg = 0x084,
|
||||
.bus_clear_status = 0x088,
|
||||
.config_load = 0x08c,
|
||||
.clken_override = 0x090,
|
||||
.interface_timing_0 = 0x094,
|
||||
.interface_timing_1 = 0x098,
|
||||
.hs_interface_timing_0 = 0x09c,
|
||||
.hs_interface_timing_1 = 0x0a0,
|
||||
.master_reset_cntrl = 0x0a8,
|
||||
.mst_fifo_control = 0x0b4,
|
||||
.mst_fifo_status = 0x0b8,
|
||||
.sw_mutex = 0x0ec,
|
||||
};
|
||||
|
||||
static const struct tegra_i2c_regs tegra410_i2c_regs = {
|
||||
.cnfg = 0x000,
|
||||
.status = 0x01c,
|
||||
.sl_cnfg = 0x020,
|
||||
.sl_addr1 = 0x02c,
|
||||
.sl_addr2 = 0x030,
|
||||
.tx_fifo = 0x054,
|
||||
.rx_fifo = 0x058,
|
||||
.packet_transfer_status = 0x05c,
|
||||
.fifo_control = 0x060,
|
||||
.fifo_status = 0x064,
|
||||
.int_mask = 0x068,
|
||||
.int_status = 0x06c,
|
||||
.clk_divisor = 0x070,
|
||||
.bus_clear_cnfg = 0x088,
|
||||
.bus_clear_status = 0x08c,
|
||||
.config_load = 0x090,
|
||||
.clken_override = 0x094,
|
||||
.interface_timing_0 = 0x098,
|
||||
.interface_timing_1 = 0x09c,
|
||||
.hs_interface_timing_0 = 0x0a0,
|
||||
.hs_interface_timing_1 = 0x0a4,
|
||||
.master_reset_cntrl = 0x0ac,
|
||||
.mst_fifo_control = 0x0b8,
|
||||
.mst_fifo_status = 0x0bc,
|
||||
.sw_mutex = 0x0f0,
|
||||
};
|
||||
|
||||
/*
|
||||
* msg_end_type: The bus control which needs to be sent at end of transfer.
|
||||
* @MSG_END_STOP: Send stop pulse.
|
||||
|
|
@ -171,6 +315,18 @@ enum msg_end_type {
|
|||
MSG_END_CONTINUE,
|
||||
};
|
||||
|
||||
/*
|
||||
* tegra_i2c_variant: Identifies the variant of I2C controller.
|
||||
* @TEGRA_I2C_VARIANT_DEFAULT: Identifies the default I2C controller.
|
||||
* @TEGRA_I2C_VARIANT_DVC: Identifies the DVC I2C controller, has a different register layout.
|
||||
* @TEGRA_I2C_VARIANT_VI: Identifies the VI I2C controller, has a different register layout.
|
||||
*/
|
||||
enum tegra_i2c_variant {
|
||||
TEGRA_I2C_VARIANT_DEFAULT,
|
||||
TEGRA_I2C_VARIANT_DVC,
|
||||
TEGRA_I2C_VARIANT_VI,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tegra_i2c_hw_feature : per hardware generation features
|
||||
* @has_continue_xfer_support: continue-transfer supported
|
||||
|
|
@ -223,6 +379,8 @@ enum msg_end_type {
|
|||
* timing settings.
|
||||
* @enable_hs_mode_support: Enable support for high speed (HS) mode transfers.
|
||||
* @has_mutex: Has mutex register for mutual exclusion with other firmwares or VMs.
|
||||
* @variant: This represents the I2C controller variant.
|
||||
* @regs: Register offsets for the specific SoC variant.
|
||||
*/
|
||||
struct tegra_i2c_hw_feature {
|
||||
bool has_continue_xfer_support;
|
||||
|
|
@ -254,6 +412,8 @@ struct tegra_i2c_hw_feature {
|
|||
bool has_interface_timing_reg;
|
||||
bool enable_hs_mode_support;
|
||||
bool has_mutex;
|
||||
enum tegra_i2c_variant variant;
|
||||
const struct tegra_i2c_regs *regs;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -268,8 +428,6 @@ struct tegra_i2c_hw_feature {
|
|||
* @base_phys: physical base address of the I2C controller
|
||||
* @cont_id: I2C controller ID, used for packet header
|
||||
* @irq: IRQ number of transfer complete interrupt
|
||||
* @is_dvc: identifies the DVC I2C controller, has a different register layout
|
||||
* @is_vi: identifies the VI I2C controller, has a different register layout
|
||||
* @msg_complete: transfer completion notifier
|
||||
* @msg_buf_remaining: size of unsent data in the message buffer
|
||||
* @msg_len: length of message in current transfer
|
||||
|
|
@ -321,12 +479,12 @@ struct tegra_i2c_dev {
|
|||
bool atomic_mode;
|
||||
bool dma_mode;
|
||||
bool msg_read;
|
||||
bool is_dvc;
|
||||
bool is_vi;
|
||||
};
|
||||
|
||||
#define IS_DVC(dev) (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && (dev)->is_dvc)
|
||||
#define IS_VI(dev) (IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) && (dev)->is_vi)
|
||||
#define IS_DVC(dev) (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && \
|
||||
(dev)->hw->variant == TEGRA_I2C_VARIANT_DVC)
|
||||
#define IS_VI(dev) (IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) && \
|
||||
(dev)->hw->variant == TEGRA_I2C_VARIANT_VI)
|
||||
|
||||
static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
|
||||
unsigned int reg)
|
||||
|
|
@ -339,40 +497,26 @@ static u32 dvc_readl(struct tegra_i2c_dev *i2c_dev, unsigned int reg)
|
|||
return readl_relaxed(i2c_dev->base + reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* If necessary, i2c_writel() and i2c_readl() will offset the register
|
||||
* in order to talk to the I2C block inside the DVC block.
|
||||
*/
|
||||
static u32 tegra_i2c_reg_addr(struct tegra_i2c_dev *i2c_dev, unsigned int reg)
|
||||
{
|
||||
if (IS_DVC(i2c_dev))
|
||||
reg += (reg >= I2C_TX_FIFO) ? 0x10 : 0x40;
|
||||
else if (IS_VI(i2c_dev))
|
||||
reg = 0xc00 + (reg << 2);
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned int reg)
|
||||
{
|
||||
writel_relaxed(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
|
||||
writel_relaxed(val, i2c_dev->base + reg);
|
||||
|
||||
/* read back register to make sure that register writes completed */
|
||||
if (reg != I2C_TX_FIFO)
|
||||
readl_relaxed(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
|
||||
if (reg != i2c_dev->hw->regs->tx_fifo)
|
||||
readl_relaxed(i2c_dev->base + reg);
|
||||
else if (IS_VI(i2c_dev))
|
||||
readl_relaxed(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, I2C_INT_STATUS));
|
||||
readl_relaxed(i2c_dev->base + i2c_dev->hw->regs->int_status);
|
||||
}
|
||||
|
||||
static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned int reg)
|
||||
{
|
||||
return readl_relaxed(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
|
||||
return readl_relaxed(i2c_dev->base + reg);
|
||||
}
|
||||
|
||||
static void i2c_writesl(struct tegra_i2c_dev *i2c_dev, void *data,
|
||||
unsigned int reg, unsigned int len)
|
||||
{
|
||||
writesl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
|
||||
writesl(i2c_dev->base + reg, data, len);
|
||||
}
|
||||
|
||||
static void i2c_writesl_vi(struct tegra_i2c_dev *i2c_dev, void *data,
|
||||
|
|
@ -393,12 +537,12 @@ static void i2c_writesl_vi(struct tegra_i2c_dev *i2c_dev, void *data,
|
|||
static void i2c_readsl(struct tegra_i2c_dev *i2c_dev, void *data,
|
||||
unsigned int reg, unsigned int len)
|
||||
{
|
||||
readsl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
|
||||
readsl(i2c_dev->base + reg, data, len);
|
||||
}
|
||||
|
||||
static bool tegra_i2c_mutex_acquired(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
unsigned int reg = tegra_i2c_reg_addr(i2c_dev, I2C_SW_MUTEX);
|
||||
unsigned int reg = i2c_dev->hw->regs->sw_mutex;
|
||||
u32 val, id;
|
||||
|
||||
val = readl(i2c_dev->base + reg);
|
||||
|
|
@ -409,7 +553,7 @@ static bool tegra_i2c_mutex_acquired(struct tegra_i2c_dev *i2c_dev)
|
|||
|
||||
static bool tegra_i2c_mutex_trylock(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
unsigned int reg = tegra_i2c_reg_addr(i2c_dev, I2C_SW_MUTEX);
|
||||
unsigned int reg = i2c_dev->hw->regs->sw_mutex;
|
||||
u32 val, id;
|
||||
|
||||
val = readl(i2c_dev->base + reg);
|
||||
|
|
@ -447,7 +591,7 @@ static int tegra_i2c_mutex_lock(struct tegra_i2c_dev *i2c_dev)
|
|||
|
||||
static int tegra_i2c_mutex_unlock(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
unsigned int reg = tegra_i2c_reg_addr(i2c_dev, I2C_SW_MUTEX);
|
||||
unsigned int reg = i2c_dev->hw->regs->sw_mutex;
|
||||
u32 val, id;
|
||||
|
||||
if (!i2c_dev->hw->has_mutex)
|
||||
|
|
@ -470,16 +614,16 @@ static void tegra_i2c_mask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
|
|||
{
|
||||
u32 int_mask;
|
||||
|
||||
int_mask = i2c_readl(i2c_dev, I2C_INT_MASK) & ~mask;
|
||||
i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
|
||||
int_mask = i2c_readl(i2c_dev, i2c_dev->hw->regs->int_mask) & ~mask;
|
||||
i2c_writel(i2c_dev, int_mask, i2c_dev->hw->regs->int_mask);
|
||||
}
|
||||
|
||||
static void tegra_i2c_unmask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
|
||||
{
|
||||
u32 int_mask;
|
||||
|
||||
int_mask = i2c_readl(i2c_dev, I2C_INT_MASK) | mask;
|
||||
i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
|
||||
int_mask = i2c_readl(i2c_dev, i2c_dev->hw->regs->int_mask) | mask;
|
||||
i2c_writel(i2c_dev, int_mask, i2c_dev->hw->regs->int_mask);
|
||||
}
|
||||
|
||||
static void tegra_i2c_dma_complete(void *args)
|
||||
|
|
@ -623,34 +767,34 @@ static void tegra_i2c_vi_init(struct tegra_i2c_dev *i2c_dev)
|
|||
|
||||
value = FIELD_PREP(I2C_INTERFACE_TIMING_THIGH, 2) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_TLOW, 4);
|
||||
i2c_writel(i2c_dev, value, I2C_INTERFACE_TIMING_0);
|
||||
i2c_writel(i2c_dev, value, i2c_dev->hw->regs->interface_timing_0);
|
||||
|
||||
value = FIELD_PREP(I2C_INTERFACE_TIMING_TBUF, 4) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_TSU_STO, 7) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_THD_STA, 4) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_TSU_STA, 4);
|
||||
i2c_writel(i2c_dev, value, I2C_INTERFACE_TIMING_1);
|
||||
i2c_writel(i2c_dev, value, i2c_dev->hw->regs->interface_timing_1);
|
||||
|
||||
value = FIELD_PREP(I2C_HS_INTERFACE_TIMING_THIGH, 3) |
|
||||
FIELD_PREP(I2C_HS_INTERFACE_TIMING_TLOW, 8);
|
||||
i2c_writel(i2c_dev, value, I2C_HS_INTERFACE_TIMING_0);
|
||||
i2c_writel(i2c_dev, value, i2c_dev->hw->regs->hs_interface_timing_0);
|
||||
|
||||
value = FIELD_PREP(I2C_HS_INTERFACE_TIMING_TSU_STO, 11) |
|
||||
FIELD_PREP(I2C_HS_INTERFACE_TIMING_THD_STA, 11) |
|
||||
FIELD_PREP(I2C_HS_INTERFACE_TIMING_TSU_STA, 11);
|
||||
i2c_writel(i2c_dev, value, I2C_HS_INTERFACE_TIMING_1);
|
||||
i2c_writel(i2c_dev, value, i2c_dev->hw->regs->hs_interface_timing_1);
|
||||
|
||||
value = FIELD_PREP(I2C_BC_SCLK_THRESHOLD, 9) | I2C_BC_STOP_COND;
|
||||
i2c_writel(i2c_dev, value, I2C_BUS_CLEAR_CNFG);
|
||||
i2c_writel(i2c_dev, value, i2c_dev->hw->regs->bus_clear_cnfg);
|
||||
|
||||
i2c_writel(i2c_dev, 0x0, I2C_TLOW_SEXT);
|
||||
i2c_writel(i2c_dev, 0x0, i2c_dev->hw->regs->tlow_sext);
|
||||
}
|
||||
|
||||
static int tegra_i2c_poll_register(struct tegra_i2c_dev *i2c_dev,
|
||||
u32 reg, u32 mask, u32 delay_us,
|
||||
u32 timeout_us)
|
||||
{
|
||||
void __iomem *addr = i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg);
|
||||
void __iomem *addr = i2c_dev->base + reg;
|
||||
u32 val;
|
||||
|
||||
if (!i2c_dev->atomic_mode)
|
||||
|
|
@ -669,11 +813,11 @@ static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev)
|
|||
if (i2c_dev->hw->has_mst_fifo) {
|
||||
mask = I2C_MST_FIFO_CONTROL_TX_FLUSH |
|
||||
I2C_MST_FIFO_CONTROL_RX_FLUSH;
|
||||
offset = I2C_MST_FIFO_CONTROL;
|
||||
offset = i2c_dev->hw->regs->mst_fifo_control;
|
||||
} else {
|
||||
mask = I2C_FIFO_CONTROL_TX_FLUSH |
|
||||
I2C_FIFO_CONTROL_RX_FLUSH;
|
||||
offset = I2C_FIFO_CONTROL;
|
||||
offset = i2c_dev->hw->regs->fifo_control;
|
||||
}
|
||||
|
||||
val = i2c_readl(i2c_dev, offset);
|
||||
|
|
@ -696,9 +840,9 @@ static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev)
|
|||
if (!i2c_dev->hw->has_config_load_reg)
|
||||
return 0;
|
||||
|
||||
i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD);
|
||||
i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, i2c_dev->hw->regs->config_load);
|
||||
|
||||
err = tegra_i2c_poll_register(i2c_dev, I2C_CONFIG_LOAD, 0xffffffff,
|
||||
err = tegra_i2c_poll_register(i2c_dev, i2c_dev->hw->regs->config_load, 0xffffffff,
|
||||
1000, I2C_CONFIG_LOAD_TIMEOUT);
|
||||
if (err) {
|
||||
dev_err(i2c_dev->dev, "failed to load config\n");
|
||||
|
|
@ -719,10 +863,10 @@ static int tegra_i2c_master_reset(struct tegra_i2c_dev *i2c_dev)
|
|||
* SW needs to wait for 2us after assertion and de-assertion of this soft
|
||||
* reset.
|
||||
*/
|
||||
i2c_writel(i2c_dev, 0x1, I2C_MASTER_RESET_CNTRL);
|
||||
i2c_writel(i2c_dev, 0x1, i2c_dev->hw->regs->master_reset_cntrl);
|
||||
fsleep(2);
|
||||
|
||||
i2c_writel(i2c_dev, 0x0, I2C_MASTER_RESET_CNTRL);
|
||||
i2c_writel(i2c_dev, 0x0, i2c_dev->hw->regs->master_reset_cntrl);
|
||||
fsleep(2);
|
||||
|
||||
return 0;
|
||||
|
|
@ -764,8 +908,8 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
|
|||
if (i2c_dev->hw->has_multi_master_mode)
|
||||
val |= I2C_CNFG_MULTI_MASTER_MODE;
|
||||
|
||||
i2c_writel(i2c_dev, val, I2C_CNFG);
|
||||
i2c_writel(i2c_dev, 0, I2C_INT_MASK);
|
||||
i2c_writel(i2c_dev, val, i2c_dev->hw->regs->cnfg);
|
||||
i2c_writel(i2c_dev, 0, i2c_dev->hw->regs->int_mask);
|
||||
|
||||
if (IS_VI(i2c_dev))
|
||||
tegra_i2c_vi_init(i2c_dev);
|
||||
|
|
@ -810,12 +954,12 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
|
|||
clk_divisor = FIELD_PREP(I2C_CLK_DIVISOR_HSMODE,
|
||||
i2c_dev->hw->clk_divisor_hs_mode) |
|
||||
FIELD_PREP(I2C_CLK_DIVISOR_STD_FAST_MODE, non_hs_mode);
|
||||
i2c_writel(i2c_dev, clk_divisor, I2C_CLK_DIVISOR);
|
||||
i2c_writel(i2c_dev, clk_divisor, i2c_dev->hw->regs->clk_divisor);
|
||||
|
||||
if (i2c_dev->hw->has_interface_timing_reg) {
|
||||
val = FIELD_PREP(I2C_INTERFACE_TIMING_THIGH, thigh) |
|
||||
FIELD_PREP(I2C_INTERFACE_TIMING_TLOW, tlow);
|
||||
i2c_writel(i2c_dev, val, I2C_INTERFACE_TIMING_0);
|
||||
i2c_writel(i2c_dev, val, i2c_dev->hw->regs->interface_timing_0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -823,7 +967,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
|
|||
* Otherwise, preserve the chip default values.
|
||||
*/
|
||||
if (i2c_dev->hw->has_interface_timing_reg && tsu_thd)
|
||||
i2c_writel(i2c_dev, tsu_thd, I2C_INTERFACE_TIMING_1);
|
||||
i2c_writel(i2c_dev, tsu_thd, i2c_dev->hw->regs->interface_timing_1);
|
||||
|
||||
/* Write HS mode registers. These will get used only for HS mode*/
|
||||
if (i2c_dev->hw->enable_hs_mode_support) {
|
||||
|
|
@ -833,8 +977,8 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
|
|||
|
||||
val = FIELD_PREP(I2C_HS_INTERFACE_TIMING_THIGH, thigh) |
|
||||
FIELD_PREP(I2C_HS_INTERFACE_TIMING_TLOW, tlow);
|
||||
i2c_writel(i2c_dev, val, I2C_HS_INTERFACE_TIMING_0);
|
||||
i2c_writel(i2c_dev, tsu_thd, I2C_HS_INTERFACE_TIMING_1);
|
||||
i2c_writel(i2c_dev, val, i2c_dev->hw->regs->hs_interface_timing_0);
|
||||
i2c_writel(i2c_dev, tsu_thd, i2c_dev->hw->regs->hs_interface_timing_1);
|
||||
}
|
||||
|
||||
clk_multiplier = (tlow + thigh + 2) * (non_hs_mode + 1);
|
||||
|
|
@ -847,12 +991,12 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
|
|||
}
|
||||
|
||||
if (!IS_DVC(i2c_dev) && !IS_VI(i2c_dev)) {
|
||||
u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG);
|
||||
u32 sl_cfg = i2c_readl(i2c_dev, i2c_dev->hw->regs->sl_cnfg);
|
||||
|
||||
sl_cfg |= I2C_SL_CNFG_NACK | I2C_SL_CNFG_NEWSL;
|
||||
i2c_writel(i2c_dev, sl_cfg, I2C_SL_CNFG);
|
||||
i2c_writel(i2c_dev, 0xfc, I2C_SL_ADDR1);
|
||||
i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2);
|
||||
i2c_writel(i2c_dev, sl_cfg, i2c_dev->hw->regs->sl_cnfg);
|
||||
i2c_writel(i2c_dev, 0xfc, i2c_dev->hw->regs->sl_addr1);
|
||||
i2c_writel(i2c_dev, 0x00, i2c_dev->hw->regs->sl_addr2);
|
||||
}
|
||||
|
||||
err = tegra_i2c_flush_fifos(i2c_dev);
|
||||
|
|
@ -860,7 +1004,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
|
|||
return err;
|
||||
|
||||
if (i2c_dev->multimaster_mode && i2c_dev->hw->has_slcg_override_reg)
|
||||
i2c_writel(i2c_dev, I2C_MST_CORE_CLKEN_OVR, I2C_CLKEN_OVERRIDE);
|
||||
i2c_writel(i2c_dev, I2C_MST_CORE_CLKEN_OVR, i2c_dev->hw->regs->clken_override);
|
||||
|
||||
err = tegra_i2c_wait_for_config_load(i2c_dev);
|
||||
if (err)
|
||||
|
|
@ -881,9 +1025,9 @@ static int tegra_i2c_disable_packet_mode(struct tegra_i2c_dev *i2c_dev)
|
|||
*/
|
||||
udelay(DIV_ROUND_UP(2 * 1000000, i2c_dev->timings.bus_freq_hz));
|
||||
|
||||
cnfg = i2c_readl(i2c_dev, I2C_CNFG);
|
||||
cnfg = i2c_readl(i2c_dev, i2c_dev->hw->regs->cnfg);
|
||||
if (cnfg & I2C_CNFG_PACKET_MODE_EN)
|
||||
i2c_writel(i2c_dev, cnfg & ~I2C_CNFG_PACKET_MODE_EN, I2C_CNFG);
|
||||
i2c_writel(i2c_dev, cnfg & ~I2C_CNFG_PACKET_MODE_EN, i2c_dev->hw->regs->cnfg);
|
||||
|
||||
return tegra_i2c_wait_for_config_load(i2c_dev);
|
||||
}
|
||||
|
|
@ -903,10 +1047,10 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
|
|||
return -EINVAL;
|
||||
|
||||
if (i2c_dev->hw->has_mst_fifo) {
|
||||
val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS);
|
||||
val = i2c_readl(i2c_dev, i2c_dev->hw->regs->mst_fifo_status);
|
||||
rx_fifo_avail = FIELD_GET(I2C_MST_FIFO_STATUS_RX, val);
|
||||
} else {
|
||||
val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
|
||||
val = i2c_readl(i2c_dev, i2c_dev->hw->regs->fifo_status);
|
||||
rx_fifo_avail = FIELD_GET(I2C_FIFO_STATUS_RX, val);
|
||||
}
|
||||
|
||||
|
|
@ -915,7 +1059,7 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
|
|||
if (words_to_transfer > rx_fifo_avail)
|
||||
words_to_transfer = rx_fifo_avail;
|
||||
|
||||
i2c_readsl(i2c_dev, buf, I2C_RX_FIFO, words_to_transfer);
|
||||
i2c_readsl(i2c_dev, buf, i2c_dev->hw->regs->rx_fifo, words_to_transfer);
|
||||
|
||||
buf += words_to_transfer * BYTES_PER_FIFO_WORD;
|
||||
buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
|
||||
|
|
@ -931,7 +1075,7 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
|
|||
* when (words_to_transfer was > rx_fifo_avail) earlier
|
||||
* in this function.
|
||||
*/
|
||||
val = i2c_readl(i2c_dev, I2C_RX_FIFO);
|
||||
val = i2c_readl(i2c_dev, i2c_dev->hw->regs->rx_fifo);
|
||||
val = cpu_to_le32(val);
|
||||
memcpy(buf, &val, buf_remaining);
|
||||
buf_remaining = 0;
|
||||
|
|
@ -956,10 +1100,10 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
|
|||
u32 val;
|
||||
|
||||
if (i2c_dev->hw->has_mst_fifo) {
|
||||
val = i2c_readl(i2c_dev, I2C_MST_FIFO_STATUS);
|
||||
val = i2c_readl(i2c_dev, i2c_dev->hw->regs->mst_fifo_status);
|
||||
tx_fifo_avail = FIELD_GET(I2C_MST_FIFO_STATUS_TX, val);
|
||||
} else {
|
||||
val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
|
||||
val = i2c_readl(i2c_dev, i2c_dev->hw->regs->fifo_status);
|
||||
tx_fifo_avail = FIELD_GET(I2C_FIFO_STATUS_TX, val);
|
||||
}
|
||||
|
||||
|
|
@ -990,9 +1134,9 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
|
|||
i2c_dev->msg_buf = buf + words_to_transfer * BYTES_PER_FIFO_WORD;
|
||||
|
||||
if (IS_VI(i2c_dev))
|
||||
i2c_writesl_vi(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer);
|
||||
i2c_writesl_vi(i2c_dev, buf, i2c_dev->hw->regs->tx_fifo, words_to_transfer);
|
||||
else
|
||||
i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer);
|
||||
i2c_writesl(i2c_dev, buf, i2c_dev->hw->regs->tx_fifo, words_to_transfer);
|
||||
|
||||
buf += words_to_transfer * BYTES_PER_FIFO_WORD;
|
||||
}
|
||||
|
|
@ -1014,7 +1158,7 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
|
|||
i2c_dev->msg_buf_remaining = 0;
|
||||
i2c_dev->msg_buf = NULL;
|
||||
|
||||
i2c_writel(i2c_dev, val, I2C_TX_FIFO);
|
||||
i2c_writel(i2c_dev, val, i2c_dev->hw->regs->tx_fifo);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1026,13 +1170,13 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
|
|||
struct tegra_i2c_dev *i2c_dev = dev_id;
|
||||
u32 status;
|
||||
|
||||
status = i2c_readl(i2c_dev, I2C_INT_STATUS);
|
||||
status = i2c_readl(i2c_dev, i2c_dev->hw->regs->int_status);
|
||||
|
||||
if (status == 0) {
|
||||
dev_warn(i2c_dev->dev, "IRQ status 0 %08x %08x %08x\n",
|
||||
i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
|
||||
i2c_readl(i2c_dev, I2C_STATUS),
|
||||
i2c_readl(i2c_dev, I2C_CNFG));
|
||||
i2c_readl(i2c_dev, i2c_dev->hw->regs->packet_transfer_status),
|
||||
i2c_readl(i2c_dev, i2c_dev->hw->regs->status),
|
||||
i2c_readl(i2c_dev, i2c_dev->hw->regs->cnfg));
|
||||
i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT;
|
||||
goto err;
|
||||
}
|
||||
|
|
@ -1075,7 +1219,7 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
|
|||
}
|
||||
}
|
||||
|
||||
i2c_writel(i2c_dev, status, I2C_INT_STATUS);
|
||||
i2c_writel(i2c_dev, status, i2c_dev->hw->regs->int_status);
|
||||
if (IS_DVC(i2c_dev))
|
||||
dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
|
||||
|
||||
|
|
@ -1113,7 +1257,7 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
|
|||
if (i2c_dev->hw->supports_bus_clear)
|
||||
tegra_i2c_mask_irq(i2c_dev, I2C_INT_BUS_CLR_DONE);
|
||||
|
||||
i2c_writel(i2c_dev, status, I2C_INT_STATUS);
|
||||
i2c_writel(i2c_dev, status, i2c_dev->hw->regs->int_status);
|
||||
|
||||
if (IS_DVC(i2c_dev))
|
||||
dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
|
||||
|
|
@ -1136,9 +1280,9 @@ static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev,
|
|||
int err;
|
||||
|
||||
if (i2c_dev->hw->has_mst_fifo)
|
||||
reg = I2C_MST_FIFO_CONTROL;
|
||||
reg = i2c_dev->hw->regs->mst_fifo_control;
|
||||
else
|
||||
reg = I2C_FIFO_CONTROL;
|
||||
reg = i2c_dev->hw->regs->fifo_control;
|
||||
|
||||
if (i2c_dev->dma_mode) {
|
||||
if (len & 0xF)
|
||||
|
|
@ -1149,7 +1293,7 @@ static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev,
|
|||
dma_burst = 8;
|
||||
|
||||
if (i2c_dev->msg_read) {
|
||||
reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_RX_FIFO);
|
||||
reg_offset = i2c_dev->hw->regs->rx_fifo;
|
||||
|
||||
slv_config.src_addr = i2c_dev->base_phys + reg_offset;
|
||||
slv_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
|
|
@ -1160,7 +1304,7 @@ static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev,
|
|||
else
|
||||
val = I2C_FIFO_CONTROL_RX_TRIG(dma_burst);
|
||||
} else {
|
||||
reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_TX_FIFO);
|
||||
reg_offset = i2c_dev->hw->regs->tx_fifo;
|
||||
|
||||
slv_config.dst_addr = i2c_dev->base_phys + reg_offset;
|
||||
slv_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
|
|
@ -1203,7 +1347,7 @@ static unsigned long tegra_i2c_poll_completion(struct tegra_i2c_dev *i2c_dev,
|
|||
ktime_t ktimeout = ktime_add_ms(ktime, timeout_ms);
|
||||
|
||||
do {
|
||||
u32 status = i2c_readl(i2c_dev, I2C_INT_STATUS);
|
||||
u32 status = i2c_readl(i2c_dev, i2c_dev->hw->regs->int_status);
|
||||
|
||||
if (status)
|
||||
tegra_i2c_isr(i2c_dev->irq, i2c_dev);
|
||||
|
|
@ -1262,14 +1406,14 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
|
|||
|
||||
val = FIELD_PREP(I2C_BC_SCLK_THRESHOLD, 9) | I2C_BC_STOP_COND |
|
||||
I2C_BC_TERMINATE;
|
||||
i2c_writel(i2c_dev, val, I2C_BUS_CLEAR_CNFG);
|
||||
i2c_writel(i2c_dev, val, i2c_dev->hw->regs->bus_clear_cnfg);
|
||||
|
||||
err = tegra_i2c_wait_for_config_load(i2c_dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
val |= I2C_BC_ENABLE;
|
||||
i2c_writel(i2c_dev, val, I2C_BUS_CLEAR_CNFG);
|
||||
i2c_writel(i2c_dev, val, i2c_dev->hw->regs->bus_clear_cnfg);
|
||||
tegra_i2c_unmask_irq(i2c_dev, I2C_INT_BUS_CLR_DONE);
|
||||
|
||||
time_left = tegra_i2c_wait_completion(i2c_dev, &i2c_dev->msg_complete, 50);
|
||||
|
|
@ -1280,7 +1424,7 @@ static int tegra_i2c_issue_bus_clear(struct i2c_adapter *adap)
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
val = i2c_readl(i2c_dev, I2C_BUS_CLEAR_STATUS);
|
||||
val = i2c_readl(i2c_dev, i2c_dev->hw->regs->bus_clear_status);
|
||||
if (!(val & I2C_BC_STATUS)) {
|
||||
dev_err(i2c_dev->dev, "un-recovered arbitration lost\n");
|
||||
return -EIO;
|
||||
|
|
@ -1305,14 +1449,14 @@ static void tegra_i2c_push_packet_header(struct tegra_i2c_dev *i2c_dev,
|
|||
if (i2c_dev->dma_mode && !i2c_dev->msg_read)
|
||||
*dma_buf++ = packet_header;
|
||||
else
|
||||
i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
|
||||
i2c_writel(i2c_dev, packet_header, i2c_dev->hw->regs->tx_fifo);
|
||||
|
||||
packet_header = i2c_dev->msg_len - 1;
|
||||
|
||||
if (i2c_dev->dma_mode && !i2c_dev->msg_read)
|
||||
*dma_buf++ = packet_header;
|
||||
else
|
||||
i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
|
||||
i2c_writel(i2c_dev, packet_header, i2c_dev->hw->regs->tx_fifo);
|
||||
|
||||
packet_header = I2C_HEADER_IE_ENABLE;
|
||||
|
||||
|
|
@ -1340,7 +1484,7 @@ static void tegra_i2c_push_packet_header(struct tegra_i2c_dev *i2c_dev,
|
|||
if (i2c_dev->dma_mode && !i2c_dev->msg_read)
|
||||
*dma_buf++ = packet_header;
|
||||
else
|
||||
i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
|
||||
i2c_writel(i2c_dev, packet_header, i2c_dev->hw->regs->tx_fifo);
|
||||
}
|
||||
|
||||
static int tegra_i2c_error_recover(struct tegra_i2c_dev *i2c_dev,
|
||||
|
|
@ -1461,7 +1605,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
|
|||
|
||||
tegra_i2c_unmask_irq(i2c_dev, int_mask);
|
||||
dev_dbg(i2c_dev->dev, "unmasked IRQ: %02x\n",
|
||||
i2c_readl(i2c_dev, I2C_INT_MASK));
|
||||
i2c_readl(i2c_dev, i2c_dev->hw->regs->int_mask));
|
||||
|
||||
if (i2c_dev->dma_mode) {
|
||||
time_left = tegra_i2c_wait_completion(i2c_dev,
|
||||
|
|
@ -1635,8 +1779,44 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
|
|||
.has_interface_timing_reg = false,
|
||||
.enable_hs_mode_support = false,
|
||||
.has_mutex = false,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra20_i2c_regs,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)
|
||||
static const struct tegra_i2c_hw_feature tegra20_dvc_i2c_hw = {
|
||||
.has_continue_xfer_support = false,
|
||||
.has_per_pkt_xfer_complete_irq = false,
|
||||
.clk_divisor_hs_mode = 3,
|
||||
.clk_divisor_std_mode = 0,
|
||||
.clk_divisor_fast_mode = 0,
|
||||
.clk_divisor_fast_plus_mode = 0,
|
||||
.has_config_load_reg = false,
|
||||
.has_multi_master_mode = false,
|
||||
.has_slcg_override_reg = false,
|
||||
.has_mst_fifo = false,
|
||||
.has_mst_reset = false,
|
||||
.quirks = &tegra_i2c_quirks,
|
||||
.supports_bus_clear = false,
|
||||
.has_apb_dma = true,
|
||||
.tlow_std_mode = 0x4,
|
||||
.thigh_std_mode = 0x2,
|
||||
.tlow_fast_mode = 0x4,
|
||||
.thigh_fast_mode = 0x2,
|
||||
.tlow_fastplus_mode = 0x4,
|
||||
.thigh_fastplus_mode = 0x2,
|
||||
.setup_hold_time_std_mode = 0x0,
|
||||
.setup_hold_time_fast_mode = 0x0,
|
||||
.setup_hold_time_fastplus_mode = 0x0,
|
||||
.setup_hold_time_hs_mode = 0x0,
|
||||
.has_interface_timing_reg = false,
|
||||
.enable_hs_mode_support = false,
|
||||
.has_mutex = false,
|
||||
.variant = TEGRA_I2C_VARIANT_DVC,
|
||||
.regs = &tegra20_dvc_i2c_regs,
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
|
||||
.has_continue_xfer_support = true,
|
||||
.has_per_pkt_xfer_complete_irq = false,
|
||||
|
|
@ -1665,6 +1845,8 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
|
|||
.has_interface_timing_reg = false,
|
||||
.enable_hs_mode_support = false,
|
||||
.has_mutex = false,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra20_i2c_regs,
|
||||
};
|
||||
|
||||
static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
|
||||
|
|
@ -1695,6 +1877,8 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
|
|||
.has_interface_timing_reg = false,
|
||||
.enable_hs_mode_support = false,
|
||||
.has_mutex = false,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra20_i2c_regs,
|
||||
};
|
||||
|
||||
static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
|
||||
|
|
@ -1725,6 +1909,8 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
|
|||
.has_interface_timing_reg = true,
|
||||
.enable_hs_mode_support = false,
|
||||
.has_mutex = false,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra20_i2c_regs,
|
||||
};
|
||||
|
||||
static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
|
||||
|
|
@ -1755,8 +1941,44 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
|
|||
.has_interface_timing_reg = true,
|
||||
.enable_hs_mode_support = false,
|
||||
.has_mutex = false,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra20_i2c_regs,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
|
||||
static const struct tegra_i2c_hw_feature tegra210_vi_i2c_hw = {
|
||||
.has_continue_xfer_support = true,
|
||||
.has_per_pkt_xfer_complete_irq = true,
|
||||
.clk_divisor_hs_mode = 1,
|
||||
.clk_divisor_std_mode = 0x19,
|
||||
.clk_divisor_fast_mode = 0x19,
|
||||
.clk_divisor_fast_plus_mode = 0x10,
|
||||
.has_config_load_reg = true,
|
||||
.has_multi_master_mode = false,
|
||||
.has_slcg_override_reg = true,
|
||||
.has_mst_fifo = false,
|
||||
.has_mst_reset = false,
|
||||
.quirks = &tegra_i2c_quirks,
|
||||
.supports_bus_clear = true,
|
||||
.has_apb_dma = true,
|
||||
.tlow_std_mode = 0x4,
|
||||
.thigh_std_mode = 0x2,
|
||||
.tlow_fast_mode = 0x4,
|
||||
.thigh_fast_mode = 0x2,
|
||||
.tlow_fastplus_mode = 0x4,
|
||||
.thigh_fastplus_mode = 0x2,
|
||||
.setup_hold_time_std_mode = 0,
|
||||
.setup_hold_time_fast_mode = 0,
|
||||
.setup_hold_time_fastplus_mode = 0,
|
||||
.setup_hold_time_hs_mode = 0,
|
||||
.has_interface_timing_reg = true,
|
||||
.enable_hs_mode_support = false,
|
||||
.has_mutex = false,
|
||||
.variant = TEGRA_I2C_VARIANT_VI,
|
||||
.regs = &tegra210_vi_i2c_regs,
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
|
||||
.has_continue_xfer_support = true,
|
||||
.has_per_pkt_xfer_complete_irq = true,
|
||||
|
|
@ -1785,6 +2007,8 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
|
|||
.has_interface_timing_reg = true,
|
||||
.enable_hs_mode_support = false,
|
||||
.has_mutex = false,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra20_i2c_regs,
|
||||
};
|
||||
|
||||
static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
|
||||
|
|
@ -1817,6 +2041,8 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
|
|||
.has_interface_timing_reg = true,
|
||||
.enable_hs_mode_support = true,
|
||||
.has_mutex = false,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra20_i2c_regs,
|
||||
};
|
||||
|
||||
static const struct tegra_i2c_hw_feature tegra256_i2c_hw = {
|
||||
|
|
@ -1849,6 +2075,8 @@ static const struct tegra_i2c_hw_feature tegra256_i2c_hw = {
|
|||
.has_interface_timing_reg = true,
|
||||
.enable_hs_mode_support = true,
|
||||
.has_mutex = true,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra264_i2c_regs,
|
||||
};
|
||||
|
||||
static const struct tegra_i2c_hw_feature tegra264_i2c_hw = {
|
||||
|
|
@ -1881,6 +2109,42 @@ static const struct tegra_i2c_hw_feature tegra264_i2c_hw = {
|
|||
.has_interface_timing_reg = true,
|
||||
.enable_hs_mode_support = true,
|
||||
.has_mutex = true,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra264_i2c_regs,
|
||||
};
|
||||
|
||||
static const struct tegra_i2c_hw_feature tegra410_i2c_hw = {
|
||||
.has_continue_xfer_support = true,
|
||||
.has_per_pkt_xfer_complete_irq = true,
|
||||
.clk_divisor_hs_mode = 1,
|
||||
.clk_divisor_std_mode = 0x3f,
|
||||
.clk_divisor_fast_mode = 0x2c,
|
||||
.clk_divisor_fast_plus_mode = 0x11,
|
||||
.has_config_load_reg = true,
|
||||
.has_multi_master_mode = true,
|
||||
.has_slcg_override_reg = true,
|
||||
.has_mst_fifo = true,
|
||||
.has_mst_reset = true,
|
||||
.quirks = &tegra194_i2c_quirks,
|
||||
.supports_bus_clear = true,
|
||||
.has_apb_dma = false,
|
||||
.tlow_std_mode = 0x8,
|
||||
.thigh_std_mode = 0x7,
|
||||
.tlow_fast_mode = 0x2,
|
||||
.thigh_fast_mode = 0x2,
|
||||
.tlow_fastplus_mode = 0x2,
|
||||
.thigh_fastplus_mode = 0x2,
|
||||
.tlow_hs_mode = 0x8,
|
||||
.thigh_hs_mode = 0x6,
|
||||
.setup_hold_time_std_mode = 0x08080808,
|
||||
.setup_hold_time_fast_mode = 0x02020202,
|
||||
.setup_hold_time_fastplus_mode = 0x02020202,
|
||||
.setup_hold_time_hs_mode = 0x0b0b0b,
|
||||
.has_interface_timing_reg = true,
|
||||
.enable_hs_mode_support = true,
|
||||
.has_mutex = true,
|
||||
.variant = TEGRA_I2C_VARIANT_DEFAULT,
|
||||
.regs = &tegra410_i2c_regs,
|
||||
};
|
||||
|
||||
static const struct of_device_id tegra_i2c_of_match[] = {
|
||||
|
|
@ -1889,7 +2153,7 @@ static const struct of_device_id tegra_i2c_of_match[] = {
|
|||
{ .compatible = "nvidia,tegra194-i2c", .data = &tegra194_i2c_hw, },
|
||||
{ .compatible = "nvidia,tegra186-i2c", .data = &tegra186_i2c_hw, },
|
||||
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
|
||||
{ .compatible = "nvidia,tegra210-i2c-vi", .data = &tegra210_i2c_hw, },
|
||||
{ .compatible = "nvidia,tegra210-i2c-vi", .data = &tegra210_vi_i2c_hw, },
|
||||
#endif
|
||||
{ .compatible = "nvidia,tegra210-i2c", .data = &tegra210_i2c_hw, },
|
||||
{ .compatible = "nvidia,tegra124-i2c", .data = &tegra124_i2c_hw, },
|
||||
|
|
@ -1897,7 +2161,7 @@ static const struct of_device_id tegra_i2c_of_match[] = {
|
|||
{ .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, },
|
||||
{ .compatible = "nvidia,tegra20-i2c", .data = &tegra20_i2c_hw, },
|
||||
#if IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC)
|
||||
{ .compatible = "nvidia,tegra20-i2c-dvc", .data = &tegra20_i2c_hw, },
|
||||
{ .compatible = "nvidia,tegra20-i2c-dvc", .data = &tegra20_dvc_i2c_hw, },
|
||||
#endif
|
||||
{},
|
||||
};
|
||||
|
|
@ -1905,21 +2169,12 @@ MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);
|
|||
|
||||
static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev)
|
||||
{
|
||||
struct device_node *np = i2c_dev->dev->of_node;
|
||||
bool multi_mode;
|
||||
|
||||
i2c_parse_fw_timings(i2c_dev->dev, &i2c_dev->timings, true);
|
||||
|
||||
multi_mode = device_property_read_bool(i2c_dev->dev, "multi-master");
|
||||
i2c_dev->multimaster_mode = multi_mode;
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) &&
|
||||
of_device_is_compatible(np, "nvidia,tegra20-i2c-dvc"))
|
||||
i2c_dev->is_dvc = true;
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) &&
|
||||
of_device_is_compatible(np, "nvidia,tegra210-i2c-vi"))
|
||||
i2c_dev->is_vi = true;
|
||||
}
|
||||
|
||||
static int tegra_i2c_init_clocks(struct tegra_i2c_dev *i2c_dev)
|
||||
|
|
@ -2205,6 +2460,7 @@ static const struct acpi_device_id tegra_i2c_acpi_match[] = {
|
|||
{.id = "NVDA0101", .driver_data = (kernel_ulong_t)&tegra210_i2c_hw},
|
||||
{.id = "NVDA0201", .driver_data = (kernel_ulong_t)&tegra186_i2c_hw},
|
||||
{.id = "NVDA0301", .driver_data = (kernel_ulong_t)&tegra194_i2c_hw},
|
||||
{.id = "NVDA2017", .driver_data = (kernel_ulong_t)&tegra410_i2c_hw},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, tegra_i2c_acpi_match);
|
||||
|
|
|
|||
|
|
@ -213,12 +213,6 @@ static int usb_write(struct i2c_adapter *adapter, int cmd,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev)
|
||||
{
|
||||
usb_put_dev(dev->usb_dev);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
static int i2c_tiny_usb_probe(struct usb_interface *interface,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
|
|
@ -237,7 +231,7 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface,
|
|||
if (!dev)
|
||||
goto error;
|
||||
|
||||
dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
|
||||
dev->usb_dev = interface_to_usbdev(interface);
|
||||
dev->interface = interface;
|
||||
|
||||
/* save our data pointer in this interface device */
|
||||
|
|
@ -277,8 +271,7 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface,
|
|||
return 0;
|
||||
|
||||
error:
|
||||
if (dev)
|
||||
i2c_tiny_usb_free(dev);
|
||||
kfree(dev);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -289,7 +282,7 @@ static void i2c_tiny_usb_disconnect(struct usb_interface *interface)
|
|||
|
||||
i2c_del_adapter(&dev->adapter);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
i2c_tiny_usb_free(dev);
|
||||
kfree(dev);
|
||||
|
||||
dev_dbg(&interface->dev, "disconnected\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ static const struct acpi_device_id usbio_i2c_acpi_hids[] = {
|
|||
{ "INTC10B6" }, /* LNL */
|
||||
{ "INTC10D2" }, /* MTL-CVF */
|
||||
{ "INTC10E3" }, /* PTL */
|
||||
{ "INTC1118" }, /* NVL */
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@
|
|||
#include <linux/platform_data/i2c-xiic.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
|
@ -1408,7 +1407,6 @@ static const struct i2c_adapter xiic_adapter = {
|
|||
.algo = &xiic_algorithm,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct xiic_version_data xiic_2_00 = {
|
||||
.quirks = DYNAMIC_MODE_READ_BROKEN_BIT,
|
||||
};
|
||||
|
|
@ -1419,28 +1417,26 @@ static const struct of_device_id xiic_of_match[] = {
|
|||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, xiic_of_match);
|
||||
#endif
|
||||
|
||||
static int xiic_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct fwnode_handle *fwnode = dev_fwnode(dev);
|
||||
struct xiic_i2c *i2c;
|
||||
struct xiic_i2c_platform_data *pdata;
|
||||
const struct of_device_id *match;
|
||||
const struct xiic_version_data *data;
|
||||
struct resource *res;
|
||||
int ret, irq;
|
||||
u8 i;
|
||||
u32 sr;
|
||||
|
||||
i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
|
||||
i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
|
||||
if (!i2c)
|
||||
return -ENOMEM;
|
||||
|
||||
match = of_match_node(xiic_of_match, pdev->dev.of_node);
|
||||
if (match && match->data) {
|
||||
const struct xiic_version_data *data = match->data;
|
||||
|
||||
data = device_get_match_data(dev);
|
||||
if (data)
|
||||
i2c->quirks = data->quirks;
|
||||
}
|
||||
|
||||
i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(i2c->base))
|
||||
|
|
@ -1450,50 +1446,52 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
|||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
pdata = dev_get_platdata(dev);
|
||||
|
||||
/* hook up driver to tree */
|
||||
platform_set_drvdata(pdev, i2c);
|
||||
i2c->adap = xiic_adapter;
|
||||
i2c->adap.nr = pdev->id;
|
||||
i2c_set_adapdata(&i2c->adap, i2c);
|
||||
i2c->adap.dev.parent = &pdev->dev;
|
||||
i2c->adap.dev.of_node = pdev->dev.of_node;
|
||||
device_set_node(&i2c->adap.dev, fwnode);
|
||||
snprintf(i2c->adap.name, sizeof(i2c->adap.name),
|
||||
DRIVER_NAME " %s", pdev->name);
|
||||
|
||||
mutex_init(&i2c->lock);
|
||||
ret = devm_mutex_init(dev, &i2c->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spin_lock_init(&i2c->atomic_lock);
|
||||
|
||||
i2c->clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
||||
if (is_of_node(fwnode)) {
|
||||
i2c->clk = devm_clk_get_enabled(dev, NULL);
|
||||
if (IS_ERR(i2c->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(i2c->clk),
|
||||
return dev_err_probe(dev, PTR_ERR(i2c->clk),
|
||||
"failed to enable input clock.\n");
|
||||
}
|
||||
|
||||
i2c->dev = &pdev->dev;
|
||||
pm_runtime_set_autosuspend_delay(i2c->dev, XIIC_PM_TIMEOUT);
|
||||
pm_runtime_use_autosuspend(i2c->dev);
|
||||
pm_runtime_set_active(i2c->dev);
|
||||
pm_runtime_enable(i2c->dev);
|
||||
i2c->dev = dev;
|
||||
|
||||
pm_runtime_set_autosuspend_delay(dev, XIIC_PM_TIMEOUT);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
ret = devm_pm_runtime_set_active_enabled(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* SCL frequency configuration */
|
||||
i2c->input_clk = clk_get_rate(i2c->clk);
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
|
||||
&i2c->i2c_clk);
|
||||
ret = device_property_read_u32(dev, "clock-frequency", &i2c->i2c_clk);
|
||||
/* If clock-frequency not specified in DT, do not configure in SW */
|
||||
if (ret || i2c->i2c_clk > I2C_MAX_FAST_MODE_PLUS_FREQ)
|
||||
i2c->i2c_clk = 0;
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||
xiic_process, IRQF_ONESHOT,
|
||||
pdev->name, i2c);
|
||||
ret = devm_request_threaded_irq(dev, irq, NULL, xiic_process,
|
||||
IRQF_ONESHOT, pdev->name, i2c);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err_probe(&pdev->dev, ret, "Cannot claim IRQ\n");
|
||||
goto err_pm_disable;
|
||||
}
|
||||
|
||||
i2c->singlemaster =
|
||||
of_property_read_bool(pdev->dev.of_node, "single-master");
|
||||
i2c->singlemaster = device_property_read_bool(dev, "single-master");
|
||||
|
||||
/*
|
||||
* Detect endianness
|
||||
|
|
@ -1508,16 +1506,14 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
|||
i2c->endianness = BIG;
|
||||
|
||||
ret = xiic_reinit(i2c);
|
||||
if (ret < 0) {
|
||||
dev_err_probe(&pdev->dev, ret, "Cannot xiic_reinit\n");
|
||||
goto err_pm_disable;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Cannot xiic_reinit\n");
|
||||
|
||||
/* add i2c adapter to i2c tree */
|
||||
ret = i2c_add_adapter(&i2c->adap);
|
||||
ret = i2c_add_numbered_adapter(&i2c->adap);
|
||||
if (ret) {
|
||||
xiic_deinit(i2c);
|
||||
goto err_pm_disable;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pdata) {
|
||||
|
|
@ -1526,38 +1522,29 @@ static int xiic_i2c_probe(struct platform_device *pdev)
|
|||
i2c_new_client_device(&i2c->adap, pdata->devices + i);
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "mmio %08lx irq %d scl clock frequency %d\n",
|
||||
(unsigned long)res->start, irq, i2c->i2c_clk);
|
||||
dev_dbg(dev, "mmio %pR irq %d scl clock frequency %d\n",
|
||||
res, irq, i2c->i2c_clk);
|
||||
|
||||
return 0;
|
||||
|
||||
err_pm_disable:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void xiic_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct xiic_i2c *i2c = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
/* remove adapter & data */
|
||||
i2c_del_adapter(&i2c->adap);
|
||||
|
||||
ret = pm_runtime_get_sync(i2c->dev);
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0)
|
||||
dev_warn(&pdev->dev, "Failed to activate device for removal (%pe)\n",
|
||||
dev_warn(dev, "Failed to activate device for removal (%pe)\n",
|
||||
ERR_PTR(ret));
|
||||
else
|
||||
xiic_deinit(i2c);
|
||||
|
||||
pm_runtime_put_sync(i2c->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_put_sync(dev);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops xiic_dev_pm_ops = {
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ struct i2c_atr_alias_pair {
|
|||
* @shared: Indicates if this alias pool is shared by multiple channels
|
||||
*
|
||||
* @lock: Lock protecting @aliases and @use_mask
|
||||
* @aliases: Array of aliases, must hold exactly @size elements
|
||||
* @use_mask: Mask of used aliases
|
||||
* @aliases: Array of aliases, must hold exactly @size elements
|
||||
*/
|
||||
struct i2c_atr_alias_pool {
|
||||
size_t size;
|
||||
|
|
@ -58,8 +58,8 @@ struct i2c_atr_alias_pool {
|
|||
|
||||
/* Protects aliases and use_mask */
|
||||
spinlock_t lock;
|
||||
u16 *aliases;
|
||||
unsigned long *use_mask;
|
||||
u16 aliases[] __counted_by(size);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -137,22 +137,16 @@ static struct i2c_atr_alias_pool *i2c_atr_alloc_alias_pool(size_t num_aliases, b
|
|||
struct i2c_atr_alias_pool *alias_pool;
|
||||
int ret;
|
||||
|
||||
alias_pool = kzalloc_obj(*alias_pool);
|
||||
alias_pool = kzalloc_flex(*alias_pool, aliases, num_aliases);
|
||||
if (!alias_pool)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
alias_pool->size = num_aliases;
|
||||
|
||||
alias_pool->aliases = kcalloc(num_aliases, sizeof(*alias_pool->aliases), GFP_KERNEL);
|
||||
if (!alias_pool->aliases) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_alias_pool;
|
||||
}
|
||||
|
||||
alias_pool->use_mask = bitmap_zalloc(num_aliases, GFP_KERNEL);
|
||||
if (!alias_pool->use_mask) {
|
||||
ret = -ENOMEM;
|
||||
goto err_free_aliases;
|
||||
goto err_free_alias_pool;
|
||||
}
|
||||
|
||||
alias_pool->shared = shared;
|
||||
|
|
@ -161,8 +155,6 @@ static struct i2c_atr_alias_pool *i2c_atr_alloc_alias_pool(size_t num_aliases, b
|
|||
|
||||
return alias_pool;
|
||||
|
||||
err_free_aliases:
|
||||
kfree(alias_pool->aliases);
|
||||
err_free_alias_pool:
|
||||
kfree(alias_pool);
|
||||
return ERR_PTR(ret);
|
||||
|
|
@ -171,7 +163,6 @@ static struct i2c_atr_alias_pool *i2c_atr_alloc_alias_pool(size_t num_aliases, b
|
|||
static void i2c_atr_free_alias_pool(struct i2c_atr_alias_pool *alias_pool)
|
||||
{
|
||||
bitmap_free(alias_pool->use_mask);
|
||||
kfree(alias_pool->aliases);
|
||||
kfree(alias_pool);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user