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-rk3x.c | 105 +++++++++++++++++++++++++++++++++++++--------------- 1 files changed, 75 insertions(+), 30 deletions(-) diff --git a/kernel/drivers/i2c/busses/i2c-rk3x.c b/kernel/drivers/i2c/busses/i2c-rk3x.c index 71592ed..4fe2e04 100644 --- a/kernel/drivers/i2c/busses/i2c-rk3x.c +++ b/kernel/drivers/i2c/busses/i2c-rk3x.c @@ -18,6 +18,7 @@ #include <linux/io.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/reset.h> #include <linux/spinlock.h> #include <linux/clk.h> #include <linux/wait.h> @@ -39,6 +40,7 @@ #define REG_IEN 0x18 /* interrupt enable */ #define REG_IPD 0x1c /* interrupt pending */ #define REG_FCNT 0x20 /* finished count */ +#define REG_SCL_OE_DB 0x24 /* Slave hold scl debounce */ #define REG_CON1 0x228 /* control register1 */ /* Data buffer offsets */ @@ -87,6 +89,7 @@ #define REG_INT_START BIT(4) /* START condition generated */ #define REG_INT_STOP BIT(5) /* STOP condition generated */ #define REG_INT_NAKRCV BIT(6) /* NACK received */ +#define REG_INT_SLV_HDSCL BIT(7) /* slave hold scl */ #define REG_INT_ALL 0xff /* Disable i2c all irqs */ @@ -97,11 +100,11 @@ #define REG_CON1_NACK_AUTO_STOP BIT(2) /* Constants */ -#define WAIT_TIMEOUT 1000 /* ms */ +#define WAIT_TIMEOUT 200 /* ms */ #define DEFAULT_SCL_RATE (100 * 1000) /* Hz */ /** - * struct i2c_spec_values: + * struct i2c_spec_values - I2C specification values for various modes * @min_hold_start_ns: min hold time (repeated) START condition * @min_low_ns: min LOW period of the SCL clock * @min_high_ns: min HIGH period of the SCL cloc @@ -157,7 +160,7 @@ }; /** - * struct rk3x_i2c_calced_timings: + * struct rk3x_i2c_calced_timings - calculated V1 timings * @div_low: Divider output for low * @div_high: Divider output for high * @tuning: Used to adjust setup/hold data time, @@ -179,7 +182,7 @@ }; /** - * struct rk3x_i2c_soc_data: + * struct rk3x_i2c_soc_data - SOC-specific data * @grf_offset: offset inside the grf regmap for setting the i2c type * @calc_timings: Callback function for i2c timing information calculated */ @@ -224,6 +227,9 @@ struct clk *pclk; struct notifier_block clk_rate_nb; bool autostop_supported; + + struct reset_control *reset; + struct reset_control *reset_apb; /* Settings */ struct i2c_timings t; @@ -307,6 +313,13 @@ if (len > 32) goto out; + /* For tx mode, one byte of the device address also needs to be counted, + * if the data length is equal to 32, which is actually 33 bytes, it would + * need to be divided into two parts, and needs to jump out of autostop. + */ + if (i2c->msg->len == 32 && i2c->mode == REG_CON_MOD_TX && !i2c->processed) + goto out; + i2c->state = STATE_STOP; con1 |= REG_CON1_TRANSFER_AUTO_STOP | REG_CON1_AUTO_STOP; @@ -324,7 +337,8 @@ } /** - * Generate a START condition, which triggers a REG_INT_START interrupt. + * rk3x_i2c_start - Generate a START condition, which triggers a REG_INT_START interrupt. + * @i2c: target controller data */ static void rk3x_i2c_start(struct rk3x_i2c *i2c) { @@ -364,8 +378,8 @@ } /** - * Generate a STOP condition, which triggers a REG_INT_STOP interrupt. - * + * rk3x_i2c_stop - Generate a STOP condition, which triggers a REG_INT_STOP interrupt. + * @i2c: target controller data * @error: Error code to return in rk3x_i2c_xfer */ static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error) @@ -373,7 +387,6 @@ unsigned int ctrl; i2c->processed = 0; - i2c->msg = NULL; i2c->error = error; if (i2c->is_last_msg) { @@ -390,6 +403,7 @@ /* Signal rk3x_i2c_xfer to start the next message. */ i2c->busy = false; i2c->state = STATE_IDLE; + i2c->msg = NULL; /* * The HW is actually not capable of REPEATED START. But we can @@ -405,7 +419,8 @@ } /** - * Setup a read according to i2c->msg + * rk3x_i2c_prepare_read - Setup a read according to i2c->msg + * @i2c: target controller data */ static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c) { @@ -438,7 +453,8 @@ } /** - * Fill the transmit buffer with data from i2c->msg + * rk3x_i2c_fill_transmit_buf - Fill the transmit buffer with data from i2c->msg + * @i2c: target controller data */ static int rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c, bool sendend) { @@ -556,7 +572,6 @@ } i2c->processed = 0; - i2c->msg = NULL; } /* ack interrupt */ @@ -571,6 +586,7 @@ i2c->busy = false; i2c->state = STATE_IDLE; + i2c->msg = NULL; /* signal rk3x_i2c_xfer that we are finished */ rk3x_i2c_wake_up(i2c); @@ -595,7 +611,7 @@ dev_dbg(i2c->dev, "IRQ: state %d, ipd: %x\n", i2c->state, ipd); /* Clean interrupt bits we don't care about */ - ipd &= ~(REG_INT_BRF | REG_INT_BTF); + ipd &= ~(REG_INT_BRF | REG_INT_BTF | REG_INT_START); if (ipd & REG_INT_NAKRCV) { /* @@ -642,11 +658,10 @@ } /** - * Get timing values of I2C specification - * + * rk3x_i2c_get_spec - Get timing values of I2C specification * @speed: Desired SCL frequency * - * Returns: Matched i2c spec values. + * Return: Matched i2c_spec_values. */ static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed) { @@ -659,13 +674,12 @@ } /** - * Calculate divider values for desired SCL frequency - * + * rk3x_i2c_v0_calc_timings - Calculate divider values for desired SCL frequency * @clk_rate: I2C input clock rate * @t: Known I2C timing information * @t_calc: Caculated rk3x private timings that would be written into regs * - * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case + * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case * a best-effort divider value is returned in divs. If the target rate is * too high, we silently use the highest possible rate. */ @@ -820,13 +834,12 @@ } /** - * Calculate timing values for desired SCL frequency - * + * rk3x_i2c_v1_calc_timings - Calculate timing values for desired SCL frequency * @clk_rate: I2C input clock rate * @t: Known I2C timing information * @t_calc: Caculated rk3x private timings that would be written into regs * - * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case + * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case * a best-effort divider value is returned in divs. If the target rate is * too high, we silently use the highest possible rate. * The following formulas are v1's method to calculate timings. @@ -983,9 +996,10 @@ { struct i2c_timings *t = &i2c->t; struct rk3x_i2c_calced_timings calc; + unsigned long period, time_hold = (WAIT_TIMEOUT / 2) * 1000000; u64 t_low_ns, t_high_ns; unsigned long flags; - u32 val; + u32 val, cnt; int ret; ret = i2c->soc_data->calc_timings(clk_rate, t, &calc); @@ -1000,6 +1014,10 @@ i2c_writel(i2c, val, REG_CON); i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff), REG_CLKDIV); + + period = DIV_ROUND_UP(1000000000, clk_rate); + cnt = DIV_ROUND_UP(time_hold, period); + i2c_writel(i2c, cnt, REG_SCL_OE_DB); spin_unlock_irqrestore(&i2c->lock, flags); clk_disable(i2c->pclk); @@ -1070,14 +1088,14 @@ } /** - * Setup I2C registers for an I2C operation specified by msgs, num. - * - * Must be called with i2c->lock held. - * + * rk3x_i2c_setup - Setup I2C registers for an I2C operation specified by msgs, num. + * @i2c: target controller data * @msgs: I2C msgs to process * @num: Number of msgs * - * returns: Number of I2C msgs processed or negative in case of error + * Must be called with i2c->lock held. + * + * Return: Number of I2C msgs processed or negative in case of error */ static int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num) { @@ -1165,12 +1183,30 @@ return !i2c->busy; } +/* + * Reset i2c controller, reset all i2c registers. + */ +static void rk3x_i2c_reset_controller(struct rk3x_i2c *i2c) +{ + if (!IS_ERR_OR_NULL(i2c->reset)) { + reset_control_assert(i2c->reset); + udelay(10); + reset_control_deassert(i2c->reset); + } + + if (!IS_ERR_OR_NULL(i2c->reset_apb)) { + reset_control_assert(i2c->reset_apb); + udelay(10); + reset_control_deassert(i2c->reset_apb); + } +} + static int rk3x_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg *msgs, int num, bool polling) { struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data; unsigned long timeout, flags; - u32 val; + u32 val, ipd = 0; int ret = 0; int i; @@ -1189,7 +1225,7 @@ * rk3x_i2c_setup()). */ for (i = 0; i < num; i += ret) { - unsigned long xfer_time = 100; + unsigned long xfer_time = WAIT_TIMEOUT; int len; ret = rk3x_i2c_setup(i2c, msgs + i, num - i); @@ -1227,8 +1263,9 @@ spin_lock_irqsave(&i2c->lock, flags); if (timeout == 0) { + ipd = i2c_readl(i2c, REG_IPD); dev_err(i2c->dev, "timeout, ipd: 0x%02x, state: %d\n", - i2c_readl(i2c, REG_IPD), i2c->state); + ipd, i2c->state); /* Force a STOP condition without interrupt */ rk3x_i2c_disable_irq(i2c); @@ -1255,6 +1292,12 @@ clk_disable(i2c->clk); spin_unlock_irqrestore(&i2c->lock, flags); + + if ((ret == -ETIMEDOUT) && (ipd & REG_INT_SLV_HDSCL)) { + rk3x_i2c_reset_controller(i2c); + dev_err(i2c->dev, "SCL hold by slave, check your device.\n"); + rk3x_i2c_adapt_div(i2c, clk_get_rate(i2c->clk)); + } return ret < 0 ? ret : num; } @@ -1602,6 +1645,7 @@ platform_set_drvdata(pdev, i2c); + i2c->reset = devm_reset_control_get(&pdev->dev, "i2c"); if (!has_acpi_companion(&pdev->dev)) { if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) { /* Only one clock to use for bus clock and peripheral clock */ @@ -1610,6 +1654,7 @@ } else { i2c->clk = devm_clk_get(&pdev->dev, "i2c"); i2c->pclk = devm_clk_get(&pdev->dev, "pclk"); + i2c->reset_apb = devm_reset_control_get(&pdev->dev, "apb"); } if (IS_ERR(i2c->clk)) -- Gitblit v1.6.2