2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-11-27 03:55:37 +08:00

Merge branch 'i2c/i2c-host' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git

This commit is contained in:
Stephen Rothwell 2024-03-28 09:33:42 +11:00
commit 8d8905f347
4 changed files with 146 additions and 78 deletions

View File

@ -1,34 +0,0 @@
* NXP PNX I2C Controller
Required properties:
- reg: Offset and length of the register set for the device
- compatible: should be "nxp,pnx-i2c"
- interrupts: configure one interrupt line
- #address-cells: always 1 (for i2c addresses)
- #size-cells: always 0
Optional properties:
- clock-frequency: desired I2C bus clock frequency in Hz, Default: 100000 Hz
Examples:
i2c1: i2c@400a0000 {
compatible = "nxp,pnx-i2c";
reg = <0x400a0000 0x100>;
interrupt-parent = <&mic>;
interrupts = <51 0>;
#address-cells = <1>;
#size-cells = <0>;
};
i2c2: i2c@400a8000 {
compatible = "nxp,pnx-i2c";
reg = <0x400a8000 0x100>;
interrupt-parent = <&mic>;
interrupts = <50 0>;
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <100000>;
};

View File

@ -0,0 +1,46 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/nxp,pnx-i2c.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP PNX I2C Controller
maintainers:
- Animesh Agarwal <animeshagarwal28@gmail.com>
allOf:
- $ref: /schemas/i2c/i2c-controller.yaml#
properties:
compatible:
const: nxp,pnx-i2c
reg:
maxItems: 1
interrupts:
maxItems: 1
clock-frequency:
default: 100000
required:
- compatible
- reg
- interrupts
- "#address-cells"
- "#size-cells"
unevaluatedProperties: false
examples:
- |
i2c@400a0000 {
compatible = "nxp,pnx-i2c";
reg = <0x400a0000 0x100>;
interrupt-parent = <&mic>;
interrupts = <51 0>;
#address-cells = <1>;
#size-cells = <0>;
};

View File

@ -15,14 +15,17 @@ allOf:
properties:
compatible:
items:
- enum:
- renesas,riic-r7s72100 # RZ/A1H
- renesas,riic-r7s9210 # RZ/A2M
- renesas,riic-r9a07g043 # RZ/G2UL and RZ/Five
- renesas,riic-r9a07g044 # RZ/G2{L,LC}
- renesas,riic-r9a07g054 # RZ/V2L
- const: renesas,riic-rz # RZ/A or RZ/G2L
oneOf:
- items:
- enum:
- renesas,riic-r7s72100 # RZ/A1H
- renesas,riic-r7s9210 # RZ/A2M
- renesas,riic-r9a07g043 # RZ/G2UL and RZ/Five
- renesas,riic-r9a07g044 # RZ/G2{L,LC}
- renesas,riic-r9a07g054 # RZ/V2L
- const: renesas,riic-rz # RZ/A or RZ/G2L
- const: renesas,riic-r9a09g057 # RZ/V2H(P)
reg:
maxItems: 1

View File

@ -46,18 +46,6 @@
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#define RIIC_ICCR1 0x00
#define RIIC_ICCR2 0x04
#define RIIC_ICMR1 0x08
#define RIIC_ICMR3 0x10
#define RIIC_ICSER 0x18
#define RIIC_ICIER 0x1c
#define RIIC_ICSR2 0x24
#define RIIC_ICBRL 0x34
#define RIIC_ICBRH 0x38
#define RIIC_ICDRT 0x3c
#define RIIC_ICDRR 0x40
#define ICCR1_ICE 0x80
#define ICCR1_IICRST 0x40
#define ICCR1_SOWP 0x10
@ -87,6 +75,25 @@
#define RIIC_INIT_MSG -1
enum riic_reg_list {
RIIC_ICCR1 = 0,
RIIC_ICCR2,
RIIC_ICMR1,
RIIC_ICMR3,
RIIC_ICSER,
RIIC_ICIER,
RIIC_ICSR2,
RIIC_ICBRL,
RIIC_ICBRH,
RIIC_ICDRT,
RIIC_ICDRR,
RIIC_REG_END,
};
struct riic_of_data {
u8 regs[RIIC_REG_END];
};
struct riic_dev {
void __iomem *base;
u8 *buf;
@ -94,6 +101,7 @@ struct riic_dev {
int bytes_left;
int err;
int is_last;
const struct riic_of_data *info;
struct completion msg_done;
struct i2c_adapter adapter;
struct clk *clk;
@ -105,9 +113,19 @@ struct riic_irq_desc {
char *name;
};
static inline void riic_writeb(struct riic_dev *riic, u8 val, u8 offset)
{
writeb(val, riic->base + riic->info->regs[offset]);
}
static inline u8 riic_readb(struct riic_dev *riic, u8 offset)
{
return readb(riic->base + riic->info->regs[offset]);
}
static inline void riic_clear_set_bit(struct riic_dev *riic, u8 clear, u8 set, u8 reg)
{
writeb((readb(riic->base + reg) & ~clear) | set, riic->base + reg);
riic_writeb(riic, (riic_readb(riic, reg) & ~clear) | set, reg);
}
static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
@ -119,7 +137,7 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
pm_runtime_get_sync(adap->dev.parent);
if (readb(riic->base + RIIC_ICCR2) & ICCR2_BBSY) {
if (riic_readb(riic, RIIC_ICCR2) & ICCR2_BBSY) {
riic->err = -EBUSY;
goto out;
}
@ -127,7 +145,7 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
reinit_completion(&riic->msg_done);
riic->err = 0;
writeb(0, riic->base + RIIC_ICSR2);
riic_writeb(riic, 0, RIIC_ICSR2);
for (i = 0, start_bit = ICCR2_ST; i < num; i++) {
riic->bytes_left = RIIC_INIT_MSG;
@ -135,9 +153,9 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
riic->msg = &msgs[i];
riic->is_last = (i == num - 1);
writeb(ICIER_NAKIE | ICIER_TIE, riic->base + RIIC_ICIER);
riic_writeb(riic, ICIER_NAKIE | ICIER_TIE, RIIC_ICIER);
writeb(start_bit, riic->base + RIIC_ICCR2);
riic_writeb(riic, start_bit, RIIC_ICCR2);
time_left = wait_for_completion_timeout(&riic->msg_done, riic->adapter.timeout);
if (time_left == 0)
@ -191,7 +209,7 @@ static irqreturn_t riic_tdre_isr(int irq, void *data)
* value could be moved to the shadow shift register right away. So
* this must be after updates to ICIER (where we want to disable TIE)!
*/
writeb(val, riic->base + RIIC_ICDRT);
riic_writeb(riic, val, RIIC_ICDRT);
return IRQ_HANDLED;
}
@ -200,9 +218,9 @@ static irqreturn_t riic_tend_isr(int irq, void *data)
{
struct riic_dev *riic = data;
if (readb(riic->base + RIIC_ICSR2) & ICSR2_NACKF) {
if (riic_readb(riic, RIIC_ICSR2) & ICSR2_NACKF) {
/* We got a NACKIE */
readb(riic->base + RIIC_ICDRR); /* dummy read */
riic_readb(riic, RIIC_ICDRR); /* dummy read */
riic_clear_set_bit(riic, ICSR2_NACKF, 0, RIIC_ICSR2);
riic->err = -ENXIO;
} else if (riic->bytes_left) {
@ -211,7 +229,7 @@ static irqreturn_t riic_tend_isr(int irq, void *data)
if (riic->is_last || riic->err) {
riic_clear_set_bit(riic, ICIER_TEIE, ICIER_SPIE, RIIC_ICIER);
writeb(ICCR2_SP, riic->base + RIIC_ICCR2);
riic_writeb(riic, ICCR2_SP, RIIC_ICCR2);
} else {
/* Transfer is complete, but do not send STOP */
riic_clear_set_bit(riic, ICIER_TEIE, 0, RIIC_ICIER);
@ -230,7 +248,7 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data)
if (riic->bytes_left == RIIC_INIT_MSG) {
riic->bytes_left = riic->msg->len;
readb(riic->base + RIIC_ICDRR); /* dummy read */
riic_readb(riic, RIIC_ICDRR); /* dummy read */
return IRQ_HANDLED;
}
@ -238,7 +256,7 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data)
/* STOP must come before we set ACKBT! */
if (riic->is_last) {
riic_clear_set_bit(riic, 0, ICIER_SPIE, RIIC_ICIER);
writeb(ICCR2_SP, riic->base + RIIC_ICCR2);
riic_writeb(riic, ICCR2_SP, RIIC_ICCR2);
}
riic_clear_set_bit(riic, 0, ICMR3_ACKBT, RIIC_ICMR3);
@ -248,7 +266,7 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data)
}
/* Reading acks the RIE interrupt */
*riic->buf = readb(riic->base + RIIC_ICDRR);
*riic->buf = riic_readb(riic, RIIC_ICDRR);
riic->buf++;
riic->bytes_left--;
@ -260,10 +278,10 @@ static irqreturn_t riic_stop_isr(int irq, void *data)
struct riic_dev *riic = data;
/* read back registers to confirm writes have fully propagated */
writeb(0, riic->base + RIIC_ICSR2);
readb(riic->base + RIIC_ICSR2);
writeb(0, riic->base + RIIC_ICIER);
readb(riic->base + RIIC_ICIER);
riic_writeb(riic, 0, RIIC_ICSR2);
riic_readb(riic, RIIC_ICSR2);
riic_writeb(riic, 0, RIIC_ICIER);
riic_readb(riic, RIIC_ICIER);
complete(&riic->msg_done);
@ -365,15 +383,15 @@ static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t)
t->scl_rise_ns / (1000000000 / rate), cks, brl, brh);
/* Changing the order of accessing IICRST and ICE may break things! */
writeb(ICCR1_IICRST | ICCR1_SOWP, riic->base + RIIC_ICCR1);
riic_writeb(riic, ICCR1_IICRST | ICCR1_SOWP, RIIC_ICCR1);
riic_clear_set_bit(riic, 0, ICCR1_ICE, RIIC_ICCR1);
writeb(ICMR1_CKS(cks), riic->base + RIIC_ICMR1);
writeb(brh | ICBR_RESERVED, riic->base + RIIC_ICBRH);
writeb(brl | ICBR_RESERVED, riic->base + RIIC_ICBRL);
riic_writeb(riic, ICMR1_CKS(cks), RIIC_ICMR1);
riic_writeb(riic, brh | ICBR_RESERVED, RIIC_ICBRH);
riic_writeb(riic, brl | ICBR_RESERVED, RIIC_ICBRL);
writeb(0, riic->base + RIIC_ICSER);
writeb(ICMR3_ACKWP | ICMR3_RDRFS, riic->base + RIIC_ICMR3);
riic_writeb(riic, 0, RIIC_ICSER);
riic_writeb(riic, ICMR3_ACKWP | ICMR3_RDRFS, RIIC_ICMR3);
riic_clear_set_bit(riic, ICCR1_IICRST, 0, RIIC_ICCR1);
@ -443,6 +461,8 @@ static int riic_i2c_probe(struct platform_device *pdev)
}
}
riic->info = of_device_get_match_data(&pdev->dev);
adap = &riic->adapter;
i2c_set_adapdata(adap, riic);
strscpy(adap->name, "Renesas RIIC adapter", sizeof(adap->name));
@ -481,14 +501,47 @@ static void riic_i2c_remove(struct platform_device *pdev)
struct riic_dev *riic = platform_get_drvdata(pdev);
pm_runtime_get_sync(&pdev->dev);
writeb(0, riic->base + RIIC_ICIER);
riic_writeb(riic, 0, RIIC_ICIER);
pm_runtime_put(&pdev->dev);
i2c_del_adapter(&riic->adapter);
pm_runtime_disable(&pdev->dev);
}
static const struct riic_of_data riic_rz_a_info = {
.regs = {
[RIIC_ICCR1] = 0x00,
[RIIC_ICCR2] = 0x04,
[RIIC_ICMR1] = 0x08,
[RIIC_ICMR3] = 0x10,
[RIIC_ICSER] = 0x18,
[RIIC_ICIER] = 0x1c,
[RIIC_ICSR2] = 0x24,
[RIIC_ICBRL] = 0x34,
[RIIC_ICBRH] = 0x38,
[RIIC_ICDRT] = 0x3c,
[RIIC_ICDRR] = 0x40,
},
};
static const struct riic_of_data riic_rz_v2h_info = {
.regs = {
[RIIC_ICCR1] = 0x00,
[RIIC_ICCR2] = 0x01,
[RIIC_ICMR1] = 0x02,
[RIIC_ICMR3] = 0x04,
[RIIC_ICSER] = 0x06,
[RIIC_ICIER] = 0x07,
[RIIC_ICSR2] = 0x09,
[RIIC_ICBRL] = 0x10,
[RIIC_ICBRH] = 0x11,
[RIIC_ICDRT] = 0x12,
[RIIC_ICDRR] = 0x13,
},
};
static const struct of_device_id riic_i2c_dt_ids[] = {
{ .compatible = "renesas,riic-rz", },
{ .compatible = "renesas,riic-rz", .data = &riic_rz_a_info },
{ .compatible = "renesas,riic-r9a09g057", .data = &riic_rz_v2h_info },
{ /* Sentinel */ },
};