From a5969cabbb4660eab42b6ef0412cbbd1200cf14d Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Sat, 12 Oct 2024 07:10:09 +0000 Subject: [PATCH] 修改led为gpio --- kernel/drivers/i2c/busses/i2c-rcar.c | 267 +++++++++++++++++++++++++++++++++++------------------ 1 files changed, 175 insertions(+), 92 deletions(-) diff --git a/kernel/drivers/i2c/busses/i2c-rcar.c b/kernel/drivers/i2c/busses/i2c-rcar.c index 3ea2cee..6a7a7a0 100644 --- a/kernel/drivers/i2c/busses/i2c-rcar.c +++ b/kernel/drivers/i2c/busses/i2c-rcar.c @@ -2,8 +2,8 @@ /* * Driver for the Renesas R-Car I2C unit * - * Copyright (C) 2014-15 Wolfram Sang <wsa@sang-engineering.com> - * Copyright (C) 2011-2015 Renesas Electronics Corporation + * Copyright (C) 2014-19 Wolfram Sang <wsa@sang-engineering.com> + * Copyright (C) 2011-2019 Renesas Electronics Corporation * * Copyright (C) 2012-14 Renesas Solutions Corp. * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> @@ -19,7 +19,9 @@ #include <linux/err.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/i2c.h> +#include <linux/i2c-smbus.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of_device.h> @@ -39,8 +41,8 @@ #define ICSAR 0x1C /* slave address */ #define ICMAR 0x20 /* master address */ #define ICRXTX 0x24 /* data port */ -#define ICDMAER 0x3c /* DMA enable */ -#define ICFBSCR 0x38 /* first bit setup cycle */ +#define ICFBSCR 0x38 /* first bit setup cycle (Gen3) */ +#define ICDMAER 0x3c /* DMA enable (Gen3) */ /* ICSCR */ #define SDBS (1 << 3) /* slave data buffer select */ @@ -83,13 +85,12 @@ #define TMDMAE (1 << 0) /* DMA Master Transmitted Enable */ /* ICFBSCR */ -#define TCYC06 0x04 /* 6*Tcyc delay 1st bit between SDA and SCL */ #define TCYC17 0x0f /* 17*Tcyc delay 1st bit between SDA and SCL */ +#define RCAR_MIN_DMA_LEN 8 #define RCAR_BUS_PHASE_START (MDBS | MIE | ESG) #define RCAR_BUS_PHASE_DATA (MDBS | MIE) -#define RCAR_BUS_MASK_DATA (~(ESG | FSB) & 0xFF) #define RCAR_BUS_PHASE_STOP (MDBS | MIE | FSB) #define RCAR_IRQ_SEND (MNR | MAL | MST | MAT | MDE) @@ -105,10 +106,11 @@ #define ID_ARBLOST (1 << 3) #define ID_NACK (1 << 4) /* persistent flags */ +#define ID_P_HOST_NOTIFY BIT(28) #define ID_P_REP_AFTER_RD BIT(29) #define ID_P_NO_RXDMA BIT(30) /* HW forbids RXDMA sometimes */ #define ID_P_PM_BLOCKED BIT(31) -#define ID_P_MASK GENMASK(31, 29) +#define ID_P_MASK GENMASK(31, 28) enum rcar_i2c_type { I2C_RCAR_GEN1, @@ -140,13 +142,12 @@ struct reset_control *rstc; int irq; + + struct i2c_client *host_notify_client; }; #define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent) #define rcar_i2c_is_recv(p) ((p)->msg->flags & I2C_M_RD) - -#define LOOP_TIMEOUT 1024 - static void rcar_i2c_write(struct rcar_i2c_priv *priv, int reg, u32 val) { @@ -213,35 +214,42 @@ rcar_i2c_write(priv, ICMSR, 0); /* start clock */ rcar_i2c_write(priv, ICCCR, priv->icccr); + + if (priv->devtype == I2C_RCAR_GEN3) + rcar_i2c_write(priv, ICFBSCR, TCYC17); + } static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) { - int i; + int ret; + u32 val; - for (i = 0; i < LOOP_TIMEOUT; i++) { - /* make sure that bus is not busy */ - if (!(rcar_i2c_read(priv, ICMCR) & FSDA)) - return 0; - udelay(1); + ret = readl_poll_timeout(priv->io + ICMCR, val, !(val & FSDA), 10, + priv->adap.timeout); + if (ret) { + /* Waiting did not help, try to recover */ + priv->recovery_icmcr = MDBS | OBPC | FSDA | FSCL; + ret = i2c_recover_bus(&priv->adap); } - /* Waiting did not help, try to recover */ - priv->recovery_icmcr = MDBS | OBPC | FSDA | FSCL; - return i2c_recover_bus(&priv->adap); + return ret; } -static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, struct i2c_timings *t) +static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv) { u32 scgd, cdf, round, ick, sum, scl, cdf_width; unsigned long rate; struct device *dev = rcar_i2c_priv_to_dev(priv); + struct i2c_timings t = { + .bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ, + .scl_fall_ns = 35, + .scl_rise_ns = 200, + .scl_int_delay_ns = 50, + }; /* Fall back to previously used values if not supplied */ - t->bus_freq_hz = t->bus_freq_hz ?: 100000; - t->scl_fall_ns = t->scl_fall_ns ?: 35; - t->scl_rise_ns = t->scl_rise_ns ?: 200; - t->scl_int_delay_ns = t->scl_int_delay_ns ?: 50; + i2c_parse_fw_timings(dev, &t, false); switch (priv->devtype) { case I2C_RCAR_GEN1: @@ -287,7 +295,7 @@ * = F[sum * ick / 1000000000] * = F[(ick / 1000000) * sum / 1000] */ - sum = t->scl_fall_ns + t->scl_rise_ns + t->scl_int_delay_ns; + sum = t.scl_fall_ns + t.scl_rise_ns + t.scl_int_delay_ns; round = (ick + 500000) / 1000000 * sum; round = (round + 500) / 1000; @@ -305,7 +313,7 @@ */ for (scgd = 0; scgd < 0x40; scgd++) { scl = ick / (20 + (scgd * 8) + round); - if (scl <= t->bus_freq_hz) + if (scl <= t.bus_freq_hz) goto scgd_find; } dev_err(dev, "it is impossible to calculate best SCL\n"); @@ -313,7 +321,7 @@ scgd_find: dev_dbg(dev, "clk %d/%d(%lu), round %u, CDF:0x%x, SCGD: 0x%x\n", - scl, t->bus_freq_hz, clk_get_rate(priv->clk), round, cdf, scgd); + scl, t.bus_freq_hz, rate, round, cdf, scgd); /* keep icccr value */ priv->icccr = scgd << cdf_width | cdf; @@ -356,19 +364,10 @@ rcar_i2c_prepare_msg(priv); } -/* - * interrupt functions - */ static void rcar_i2c_dma_unmap(struct rcar_i2c_priv *priv) { struct dma_chan *chan = priv->dma_direction == DMA_FROM_DEVICE ? priv->dma_rx : priv->dma_tx; - - /* Disable DMA Master Received/Transmitted */ - rcar_i2c_write(priv, ICDMAER, 0); - - /* Reset default delay */ - rcar_i2c_write(priv, ICFBSCR, TCYC06); dma_unmap_single(chan->device->dev, sg_dma_address(&priv->sg), sg_dma_len(&priv->sg), priv->dma_direction); @@ -379,6 +378,9 @@ priv->flags |= ID_P_NO_RXDMA; priv->dma_direction = DMA_NONE; + + /* Disable DMA Master Received/Transmitted, must be last! */ + rcar_i2c_write(priv, ICDMAER, 0); } static void rcar_i2c_cleanup_dma(struct rcar_i2c_priv *priv) @@ -402,7 +404,7 @@ rcar_i2c_dma_unmap(priv); } -static void rcar_i2c_dma(struct rcar_i2c_priv *priv) +static bool rcar_i2c_dma(struct rcar_i2c_priv *priv) { struct device *dev = rcar_i2c_priv_to_dev(priv); struct i2c_msg *msg = priv->msg; @@ -416,9 +418,9 @@ int len; /* Do various checks to see if DMA is feasible at all */ - if (IS_ERR(chan) || msg->len < 8 || !(msg->flags & I2C_M_DMA_SAFE) || - (read && priv->flags & ID_P_NO_RXDMA)) - return; + if (IS_ERR(chan) || msg->len < RCAR_MIN_DMA_LEN || + !(msg->flags & I2C_M_DMA_SAFE) || (read && priv->flags & ID_P_NO_RXDMA)) + return false; if (read) { /* @@ -438,7 +440,7 @@ dma_addr = dma_map_single(chan->device->dev, buf, len, dir); if (dma_mapping_error(chan->device->dev, dma_addr)) { dev_dbg(dev, "dma map failed, using PIO\n"); - return; + return false; } sg_dma_len(&priv->sg) = len; @@ -452,7 +454,7 @@ if (!txdesc) { dev_dbg(dev, "dma prep slave sg failed, using PIO\n"); rcar_i2c_cleanup_dma(priv); - return; + return false; } txdesc->callback = rcar_i2c_dma_callback; @@ -462,11 +464,8 @@ if (dma_submit_error(cookie)) { dev_dbg(dev, "submitting dma failed, using PIO\n"); rcar_i2c_cleanup_dma(priv); - return; + return false; } - - /* Set delay for DMA operations */ - rcar_i2c_write(priv, ICFBSCR, TCYC17); /* Enable DMA Master Received/Transmitted */ if (read) @@ -475,6 +474,7 @@ rcar_i2c_write(priv, ICDMAER, TMDMAE); dma_async_issue_pending(chan); + return true; } static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) @@ -483,6 +483,10 @@ /* FIXME: sometimes, unknown interrupt happened. Do nothing */ if (!(msr & MDE)) + return; + + /* Check if DMA can be enabled and take over */ + if (priv->pos == 1 && rcar_i2c_dma(priv)) return; if (priv->pos < msg->len) { @@ -495,13 +499,6 @@ */ rcar_i2c_write(priv, ICRXTX, msg->buf[priv->pos]); priv->pos++; - - /* - * Try to use DMA to transmit the rest of the data if - * address transfer phase just finished. - */ - if (msr & MAT) - rcar_i2c_dma(priv); } else { /* * The last data was pushed to ICRXTX on _PREV_ empty irq. @@ -620,21 +617,19 @@ return true; } -static irqreturn_t rcar_i2c_irq(int irq, void *ptr) +/* + * This driver has a lock-free design because there are IP cores (at least + * R-Car Gen2) which have an inherent race condition in their hardware design. + * There, we need to switch to RCAR_BUS_PHASE_DATA as soon as possible after + * the interrupt was generated, otherwise an unwanted repeated message gets + * generated. It turned out that taking a spinlock at the beginning of the ISR + * was already causing repeated messages. Thus, this driver was converted to + * the now lockless behaviour. Please keep this in mind when hacking the driver. + * R-Car Gen3 seems to have this fixed but earlier versions than R-Car Gen2 are + * likely affected. Therefore, we have different interrupt handler entries. + */ +static irqreturn_t rcar_i2c_irq(int irq, struct rcar_i2c_priv *priv, u32 msr) { - struct rcar_i2c_priv *priv = ptr; - u32 msr, val; - - /* Clear START or STOP immediately, except for REPSTART after read */ - if (likely(!(priv->flags & ID_P_REP_AFTER_RD))) { - val = rcar_i2c_read(priv, ICMCR); - rcar_i2c_write(priv, ICMCR, val & RCAR_BUS_MASK_DATA); - } - - msr = rcar_i2c_read(priv, ICMSR); - - /* Only handle interrupts that are currently enabled */ - msr &= rcar_i2c_read(priv, ICMIER); if (!msr) { if (rcar_i2c_slave_irq(priv)) return IRQ_HANDLED; @@ -676,6 +671,41 @@ } return IRQ_HANDLED; +} + +static irqreturn_t rcar_i2c_gen2_irq(int irq, void *ptr) +{ + struct rcar_i2c_priv *priv = ptr; + u32 msr; + + /* Clear START or STOP immediately, except for REPSTART after read */ + if (likely(!(priv->flags & ID_P_REP_AFTER_RD))) + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA); + + /* Only handle interrupts that are currently enabled */ + msr = rcar_i2c_read(priv, ICMSR); + msr &= rcar_i2c_read(priv, ICMIER); + + return rcar_i2c_irq(irq, priv, msr); +} + +static irqreturn_t rcar_i2c_gen3_irq(int irq, void *ptr) +{ + struct rcar_i2c_priv *priv = ptr; + u32 msr; + + /* Only handle interrupts that are currently enabled */ + msr = rcar_i2c_read(priv, ICMSR); + msr &= rcar_i2c_read(priv, ICMIER); + + /* + * Clear START or STOP immediately, except for REPSTART after read or + * if a spurious interrupt was detected. + */ + if (likely(!(priv->flags & ID_P_REP_AFTER_RD) && msr)) + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA); + + return rcar_i2c_irq(irq, priv, msr); } static struct dma_chan *rcar_i2c_request_dma_chan(struct device *dev, @@ -755,20 +785,14 @@ /* I2C is a special case, we need to poll the status of a reset */ static int rcar_i2c_do_reset(struct rcar_i2c_priv *priv) { - int i, ret; + int ret; ret = reset_control_reset(priv->rstc); if (ret) return ret; - for (i = 0; i < LOOP_TIMEOUT; i++) { - ret = reset_control_status(priv->rstc); - if (ret == 0) - return 0; - udelay(1); - } - - return -ETIMEDOUT; + return read_poll_timeout_atomic(reset_control_status, ret, ret == 0, 1, + 100, false, priv->rstc); } static int rcar_i2c_master_xfer(struct i2c_adapter *adap, @@ -879,14 +903,21 @@ static u32 rcar_i2c_func(struct i2c_adapter *adap) { + struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); + /* * This HW can't do: * I2C_SMBUS_QUICK (setting FSB during START didn't work) * I2C_M_NOSTART (automatically sends address after START) * I2C_M_IGNORE_NAK (automatically sends STOP after NAK) */ - return I2C_FUNC_I2C | I2C_FUNC_SLAVE | - (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); + u32 func = I2C_FUNC_I2C | I2C_FUNC_SLAVE | + (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); + + if (priv->flags & ID_P_HOST_NOTIFY) + func |= I2C_FUNC_SMBUS_HOST_NOTIFY; + + return func; } static const struct i2c_algorithm rcar_i2c_algo = { @@ -923,8 +954,12 @@ struct rcar_i2c_priv *priv; struct i2c_adapter *adap; struct device *dev = &pdev->dev; - struct i2c_timings i2c_t; + unsigned long irqflags = 0; + irqreturn_t (*irqhandler)(int irq, void *ptr) = rcar_i2c_gen3_irq; int ret; + + /* Otherwise logic will break because some bytes must always use PIO */ + BUILD_BUG_ON_MSG(RCAR_MIN_DMA_LEN < 3, "Invalid min DMA length"); priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL); if (!priv) @@ -936,9 +971,7 @@ return PTR_ERR(priv->clk); } - priv->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - priv->io = devm_ioremap_resource(dev, priv->res); + priv->io = devm_platform_get_and_ioremap_resource(pdev, 0, &priv->res); if (IS_ERR(priv->io)) return PTR_ERR(priv->io); @@ -957,8 +990,6 @@ i2c_set_adapdata(adap, priv); strlcpy(adap->name, pdev->name, sizeof(adap->name)); - i2c_parse_fw_timings(dev, &i2c_t, false); - /* Init DMA */ sg_init_table(&priv->sg, 1); priv->dma_direction = DMA_NONE; @@ -967,11 +998,18 @@ /* Activate device for clock calculation */ pm_runtime_enable(dev); pm_runtime_get_sync(dev); - ret = rcar_i2c_clock_calculate(priv, &i2c_t); - if (ret < 0) - goto out_pm_put; + ret = rcar_i2c_clock_calculate(priv); + if (ret < 0) { + pm_runtime_put(dev); + goto out_pm_disable; + } rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */ + + if (priv->devtype < I2C_RCAR_GEN3) { + irqflags |= IRQF_NO_THREAD; + irqhandler = rcar_i2c_gen2_irq; + } if (priv->devtype == I2C_RCAR_GEN3) { priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); @@ -988,26 +1026,42 @@ else pm_runtime_put(dev); + if (of_property_read_bool(dev->of_node, "smbus")) + priv->flags |= ID_P_HOST_NOTIFY; - priv->irq = platform_get_irq(pdev, 0); - ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, 0, dev_name(dev), priv); + ret = platform_get_irq(pdev, 0); + if (ret < 0) + goto out_pm_put; + priv->irq = ret; + ret = devm_request_irq(dev, priv->irq, irqhandler, irqflags, dev_name(dev), priv); if (ret < 0) { dev_err(dev, "cannot get irq %d\n", priv->irq); - goto out_pm_disable; + goto out_pm_put; } platform_set_drvdata(pdev, priv); ret = i2c_add_numbered_adapter(adap); if (ret < 0) - goto out_pm_disable; + goto out_pm_put; + + if (priv->flags & ID_P_HOST_NOTIFY) { + priv->host_notify_client = i2c_new_slave_host_notify_device(adap); + if (IS_ERR(priv->host_notify_client)) { + ret = PTR_ERR(priv->host_notify_client); + goto out_del_device; + } + } dev_info(dev, "probed\n"); return 0; + out_del_device: + i2c_del_adapter(&priv->adap); out_pm_put: - pm_runtime_put(dev); + if (priv->flags & ID_P_PM_BLOCKED) + pm_runtime_put(dev); out_pm_disable: pm_runtime_disable(dev); return ret; @@ -1018,6 +1072,8 @@ struct rcar_i2c_priv *priv = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; + if (priv->host_notify_client) + i2c_free_slave_host_notify_device(priv->host_notify_client); i2c_del_adapter(&priv->adap); rcar_i2c_release_dma(priv); if (priv->flags & ID_P_PM_BLOCKED) @@ -1027,10 +1083,37 @@ return 0; } +#ifdef CONFIG_PM_SLEEP +static int rcar_i2c_suspend(struct device *dev) +{ + struct rcar_i2c_priv *priv = dev_get_drvdata(dev); + + i2c_mark_adapter_suspended(&priv->adap); + return 0; +} + +static int rcar_i2c_resume(struct device *dev) +{ + struct rcar_i2c_priv *priv = dev_get_drvdata(dev); + + i2c_mark_adapter_resumed(&priv->adap); + return 0; +} + +static const struct dev_pm_ops rcar_i2c_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rcar_i2c_suspend, rcar_i2c_resume) +}; + +#define DEV_PM_OPS (&rcar_i2c_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + static struct platform_driver rcar_i2c_driver = { .driver = { .name = "i2c-rcar", .of_match_table = rcar_i2c_dt_ids, + .pm = DEV_PM_OPS, }, .probe = rcar_i2c_probe, .remove = rcar_i2c_remove, -- Gitblit v1.6.2