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 | 484 +++++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 377 insertions(+), 107 deletions(-) diff --git a/kernel/drivers/i2c/busses/i2c-rk3x.c b/kernel/drivers/i2c/busses/i2c-rk3x.c index d62af80..4fe2e04 100644 --- a/kernel/drivers/i2c/busses/i2c-rk3x.c +++ b/kernel/drivers/i2c/busses/i2c-rk3x.c @@ -1,24 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for I2C adapter in Rockchip RK3xxx SoC * * Max Schwarz <max.schwarz@online.de> * based on the patches by Rockchip Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ +#include <linux/acpi.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/i2c.h> #include <linux/interrupt.h> +#include <linux/iopoll.h> #include <linux/errno.h> #include <linux/err.h> #include <linux/platform_device.h> #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> @@ -27,6 +27,7 @@ #include <linux/math64.h> #include <linux/reboot.h> #include <linux/delay.h> +#include <linux/soc/rockchip/rockchip_thunderboot_service.h> /* Register Map */ @@ -39,6 +40,8 @@ #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 */ #define TXBUFFER_BASE 0x100 @@ -66,6 +69,15 @@ #define REG_CON_STA_CFG(cfg) ((cfg) << 12) #define REG_CON_STO_CFG(cfg) ((cfg) << 14) +enum { + RK_I2C_VERSION0 = 0, + RK_I2C_VERSION1, + RK_I2C_VERSION5 = 5, +}; + +#define REG_CON_VERSION GENMASK_ULL(24, 16) +#define REG_CON_VERSION_SHIFT 16 + /* REG_MRXADDR bits */ #define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */ @@ -77,17 +89,22 @@ #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 */ #define IEN_ALL_DISABLE 0 +#define REG_CON1_AUTO_STOP BIT(0) +#define REG_CON1_TRANSFER_AUTO_STOP BIT(1) +#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 @@ -143,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, @@ -165,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 */ @@ -197,6 +214,7 @@ * @error: error code for i2c transfer * @i2c_restart_nb: make sure the i2c transfer to be finished * @system_restarting: true if system is restarting + * @tb_cl: client for rockchip thunder boot service */ struct rk3x_i2c { struct i2c_adapter adap; @@ -208,6 +226,10 @@ struct clk *clk; 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; @@ -231,10 +253,12 @@ struct notifier_block i2c_restart_nb; bool system_restarting; + struct rk_tb_client tb_cl; + int irq; }; -static int rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c, bool sended); static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c); +static int rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c, bool sended); static inline void rk3x_i2c_wake_up(struct rk3x_i2c *i2c) { @@ -271,23 +295,70 @@ i2c_writel(i2c, val, REG_CON); } +static bool rk3x_i2c_auto_stop(struct rk3x_i2c *i2c) +{ + unsigned int len, con1 = 0; + + if (!i2c->autostop_supported) + return false; + + if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) + con1 = REG_CON1_NACK_AUTO_STOP | REG_CON1_AUTO_STOP; + + if (!i2c->is_last_msg) + goto out; + + len = i2c->msg->len - i2c->processed; + + 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; + i2c_writel(i2c, con1, REG_CON1); + if (con1 & REG_CON1_NACK_AUTO_STOP) + i2c_writel(i2c, REG_INT_STOP, REG_IEN); + else + i2c_writel(i2c, REG_INT_STOP | REG_INT_NAKRCV, REG_IEN); + + return true; + +out: + i2c_writel(i2c, con1, REG_CON1); + return false; +} + /** - * 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) { u32 val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; + bool auto_stop = rk3x_i2c_auto_stop(i2c); int length = 0; /* enable appropriate interrupts */ if (i2c->mode == REG_CON_MOD_TX) { - i2c_writel(i2c, REG_INT_MBTF | REG_INT_NAKRCV, REG_IEN); - i2c->state = STATE_WRITE; + if (!auto_stop) { + i2c_writel(i2c, REG_INT_MBTF | REG_INT_NAKRCV, REG_IEN); + i2c->state = STATE_WRITE; + } length = rk3x_i2c_fill_transmit_buf(i2c, false); } else { /* in any other case, we are going to be reading. */ - i2c_writel(i2c, REG_INT_MBRF | REG_INT_NAKRCV, REG_IEN); - i2c->state = STATE_READ; + if (!auto_stop) { + i2c_writel(i2c, REG_INT_MBRF | REG_INT_NAKRCV, REG_IEN); + i2c->state = STATE_READ; + } } /* enable adapter with correct mode, send START condition */ @@ -307,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) @@ -316,7 +387,6 @@ unsigned int ctrl; i2c->processed = 0; - i2c->msg = NULL; i2c->error = error; if (i2c->is_last_msg) { @@ -333,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 @@ -348,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) { @@ -381,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) { @@ -424,7 +497,7 @@ { if (!(ipd & REG_INT_MBTF)) { rk3x_i2c_stop(i2c, -EIO); - dev_err(i2c->dev, "unexpected irq in WRITE: 0x%x\n", ipd); + dev_warn_ratelimited(i2c->dev, "unexpected irq in WRITE: 0x%x\n", ipd); rk3x_i2c_clean_ipd(i2c); return; } @@ -432,6 +505,7 @@ /* ack interrupt */ i2c_writel(i2c, REG_INT_MBTF, REG_IPD); + rk3x_i2c_auto_stop(i2c); /* are we finished? */ if (i2c->processed == i2c->msg->len) rk3x_i2c_stop(i2c, i2c->error); @@ -439,19 +513,12 @@ rk3x_i2c_fill_transmit_buf(i2c, true); } -static void rk3x_i2c_handle_read(struct rk3x_i2c *i2c, unsigned int ipd) +static void rk3x_i2c_read(struct rk3x_i2c *i2c) { unsigned int i; unsigned int len = i2c->msg->len - i2c->processed; - u32 uninitialized_var(val); + u32 val; u8 byte; - - /* we only care for MBRF here. */ - if (!(ipd & REG_INT_MBRF)) - return; - - /* ack interrupt (read also produces a spurious START flag, clear it too) */ - i2c_writel(i2c, REG_INT_MBRF | REG_INT_START, REG_IPD); /* Can only handle a maximum of 32 bytes at a time */ if (len > 32) @@ -465,7 +532,21 @@ byte = (val >> ((i % 4) * 8)) & 0xff; i2c->msg->buf[i2c->processed++] = byte; } +} +static void rk3x_i2c_handle_read(struct rk3x_i2c *i2c, unsigned int ipd) +{ + /* we only care for MBRF here. */ + if (!(ipd & REG_INT_MBRF)) + return; + + /* ack interrupt (read also produces a spurious START flag, clear it too) */ + i2c_writel(i2c, REG_INT_MBRF | REG_INT_START, REG_IPD); + + /* read the data from receive buffer */ + rk3x_i2c_read(i2c); + + rk3x_i2c_auto_stop(i2c); /* are we finished? */ if (i2c->processed == i2c->msg->len) rk3x_i2c_stop(i2c, i2c->error); @@ -479,9 +560,18 @@ if (!(ipd & REG_INT_STOP)) { rk3x_i2c_stop(i2c, -EIO); - dev_err(i2c->dev, "unexpected irq in STOP: 0x%x\n", ipd); + dev_warn_ratelimited(i2c->dev, "unexpected irq in STOP: 0x%x\n", ipd); rk3x_i2c_clean_ipd(i2c); return; + } + + if (i2c->autostop_supported && !i2c->error) { + if (i2c->mode != REG_CON_MOD_TX && i2c->msg) { + if ((i2c->msg->len - i2c->processed) > 0) + rk3x_i2c_read(i2c); + } + + i2c->processed = 0; } /* ack interrupt */ @@ -490,10 +580,13 @@ /* disable STOP bit */ con = i2c_readl(i2c, REG_CON); con &= ~REG_CON_STOP; + if (i2c->autostop_supported) + con &= ~REG_CON_START; i2c_writel(i2c, con, REG_CON); i2c->busy = false; i2c->state = STATE_IDLE; + i2c->msg = NULL; /* signal rk3x_i2c_xfer that we are finished */ rk3x_i2c_wake_up(i2c); @@ -518,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) { /* @@ -531,8 +624,13 @@ ipd &= ~REG_INT_NAKRCV; if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) { - rk3x_i2c_stop(i2c, -ENXIO); - goto out; + if (i2c->autostop_supported) { + i2c->error = -ENXIO; + i2c->state = STATE_STOP; + } else { + rk3x_i2c_stop(i2c, -ENXIO); + goto out; + } } } @@ -560,30 +658,28 @@ } /** - * 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) { - if (speed <= 100000) + if (speed <= I2C_MAX_STANDARD_MODE_FREQ) return &standard_mode_spec; - else if (speed <= 400000) + else if (speed <= I2C_MAX_FAST_MODE_FREQ) return &fast_mode_spec; else return &fast_mode_plus_spec; } /** - * 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. */ @@ -607,8 +703,8 @@ int ret = 0; /* Only support standard-mode and fast-mode */ - if (WARN_ON(t->bus_freq_hz > 400000)) - t->bus_freq_hz = 400000; + if (WARN_ON(t->bus_freq_hz > I2C_MAX_FAST_MODE_FREQ)) + t->bus_freq_hz = I2C_MAX_FAST_MODE_FREQ; /* prevent scl_rate_khz from becoming 0 */ if (WARN_ON(t->bus_freq_hz < 1000)) @@ -738,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. @@ -787,8 +882,8 @@ int ret = 0; /* Support standard-mode, fast-mode and fast-mode plus */ - if (WARN_ON(t->bus_freq_hz > 1000000)) - t->bus_freq_hz = 1000000; + if (WARN_ON(t->bus_freq_hz > I2C_MAX_FAST_MODE_PLUS_FREQ)) + t->bus_freq_hz = I2C_MAX_FAST_MODE_PLUS_FREQ; /* prevent scl_rate_khz from becoming 0 */ if (WARN_ON(t->bus_freq_hz < 1000)) @@ -901,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); @@ -918,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); @@ -988,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) { @@ -1064,16 +1164,49 @@ i2c->error = 0; rk3x_i2c_clean_ipd(i2c); + if (i2c->autostop_supported) + i2c_writel(i2c, 0, REG_CON1); return ret; } -static int rk3x_i2c_xfer(struct i2c_adapter *adap, - struct i2c_msg *msgs, int num) +static int rk3x_i2c_wait_xfer_poll(struct rk3x_i2c *i2c, unsigned long xfer_time) +{ + ktime_t timeout = ktime_add_ms(ktime_get(), xfer_time); + + while (READ_ONCE(i2c->busy) && + ktime_compare(ktime_get(), timeout) < 0) { + udelay(5); + rk3x_i2c_irq(0, i2c); + } + + 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; @@ -1092,12 +1225,26 @@ * rk3x_i2c_setup()). */ for (i = 0; i < num; i += ret) { - ret = rk3x_i2c_setup(i2c, msgs + i, num - i); + unsigned long xfer_time = WAIT_TIMEOUT; + int len; + ret = rk3x_i2c_setup(i2c, msgs + i, num - i); if (ret < 0) { dev_err(i2c->dev, "rk3x_i2c_setup() failed\n"); break; } + + /* + * Transfer time in mSec = Total bits / transfer rate + interval time + * Total bits = 9 bits per byte (including ACK bit) + Start & stop bits + */ + if (ret == 2) + len = msgs[i + 1].len; + else + len = msgs[i].len; + xfer_time += len / 64; + xfer_time += DIV_ROUND_CLOSEST(((len * 9) + 2) * MSEC_PER_SEC, + i2c->t.bus_freq_hz); if (i + ret >= num) i2c->is_last_msg = true; @@ -1106,14 +1253,19 @@ spin_unlock_irqrestore(&i2c->lock, flags); - timeout = wait_event_timeout(i2c->wait, !i2c->busy, - msecs_to_jiffies(WAIT_TIMEOUT)); + if (!polling) { + timeout = wait_event_timeout(i2c->wait, !i2c->busy, + msecs_to_jiffies(xfer_time)); + } else { + timeout = rk3x_i2c_wait_xfer_poll(i2c, xfer_time); + } 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); @@ -1141,7 +1293,25 @@ 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; +} + +static int rk3x_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + return rk3x_i2c_xfer_common(adap, msgs, num, false); +} + +static int rk3x_i2c_xfer_polling(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + return rk3x_i2c_xfer_common(adap, msgs, num, true); } static int rk3x_i2c_restart_notify(struct notifier_block *this, @@ -1177,6 +1347,57 @@ return NOTIFY_DONE; } + +static unsigned int rk3x_i2c_get_version(struct rk3x_i2c *i2c) +{ + unsigned int version; + + clk_enable(i2c->pclk); + version = i2c_readl(i2c, REG_CON) & REG_CON_VERSION; + clk_disable(i2c->pclk); + version >>= REG_CON_VERSION_SHIFT; + + return version; +} + +static int rk3x_i2c_of_get_bus_id(struct device *dev, struct rk3x_i2c *priv) +{ + int bus_id = -1; + + if (IS_ENABLED(CONFIG_OF) && dev->of_node) + bus_id = of_alias_get_id(dev->of_node, "i2c"); + + return bus_id; +} + +#ifdef CONFIG_ACPI +static int rk3x_i2c_acpi_get_bus_id(struct device *dev, struct rk3x_i2c *priv) +{ + struct acpi_device *adev; + unsigned long bus_id = -1; + const char *uid; + int ret; + + adev = ACPI_COMPANION(dev); + if (!adev) + return -ENXIO; + + uid = acpi_device_uid(adev); + if (!uid || !(*uid)) { + dev_err(dev, "Cannot retrieve UID\n"); + return -ENODEV; + } + + ret = kstrtoul(uid, 0, &bus_id); + + return !ret ? bus_id : -ERANGE; +} +#else +static int rk3x_i2c_acpi_get_bus_id(struct device *dev, struct rk3x_i2c *priv) +{ + return -ENOENT; +} +#endif /* CONFIG_ACPI */ static __maybe_unused int rk3x_i2c_suspend_noirq(struct device *dev) { @@ -1217,6 +1438,7 @@ static const struct i2c_algorithm rk3x_i2c_algorithm = { .master_xfer = rk3x_i2c_xfer, + .master_xfer_atomic = rk3x_i2c_xfer_polling, .functionality = rk3x_i2c_func, }; @@ -1288,12 +1510,38 @@ }; MODULE_DEVICE_TABLE(of, rk3x_i2c_match); +static void rk3x_i2c_tb_cb(void *data) +{ + unsigned long clk_rate; + int ret; + struct rk3x_i2c *i2c = (struct rk3x_i2c *)data; + + if (i2c->clk) { + i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb; + ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb); + if (ret != 0) { + dev_err(i2c->dev, "Unable to register clock notifier\n"); + clk_unprepare(i2c->pclk); + clk_unprepare(i2c->clk); + return; + } + } + + clk_rate = clk_get_rate(i2c->clk); + if (!clk_rate) + device_property_read_u32(i2c->dev, "i2c,clk-rate", (u32 *)&clk_rate); + + rk3x_i2c_adapt_div(i2c, clk_rate); + if (rk3x_i2c_get_version(i2c) >= RK_I2C_VERSION5) + i2c->autostop_supported = true; + enable_irq(i2c->irq); +} + static int rk3x_i2c_probe(struct platform_device *pdev) { + struct fwnode_handle *fw = dev_fwnode(&pdev->dev); struct device_node *np = pdev->dev.of_node; - const struct of_device_id *match; struct rk3x_i2c *i2c; - struct resource *mem; int ret = 0; u32 value; int irq; @@ -1303,8 +1551,16 @@ if (!i2c) return -ENOMEM; - match = of_match_node(rk3x_i2c_match, np); - i2c->soc_data = match->data; + i2c->soc_data = (struct rk3x_i2c_soc_data *)device_get_match_data(&pdev->dev); + + ret = rk3x_i2c_acpi_get_bus_id(&pdev->dev, i2c); + if (ret < 0) { + ret = rk3x_i2c_of_get_bus_id(&pdev->dev, i2c); + if (ret < 0) + return ret; + } + + i2c->adap.nr = ret; /* use common interface to get I2C timing properties */ i2c_parse_fw_timings(&pdev->dev, &i2c->t, true); @@ -1313,9 +1569,10 @@ i2c->adap.owner = THIS_MODULE; i2c->adap.algo = &rk3x_i2c_algorithm; i2c->adap.retries = 3; - i2c->adap.dev.of_node = np; + i2c->adap.dev.of_node = pdev->dev.of_node; i2c->adap.algo_data = i2c; i2c->adap.dev.parent = &pdev->dev; + i2c->adap.dev.fwnode = fw; i2c->dev = &pdev->dev; @@ -1330,8 +1587,7 @@ return ret; } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2c->regs = devm_ioremap_resource(&pdev->dev, mem); + i2c->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(i2c->regs)) return PTR_ERR(i2c->regs); @@ -1344,14 +1600,7 @@ grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); if (!IS_ERR(grf)) { - int bus_nr; - - /* Try to set the I2C adapter number from dt */ - bus_nr = of_alias_get_id(np, "i2c"); - if (bus_nr < 0) { - dev_err(&pdev->dev, "rk3x-i2c needs i2cX alias"); - return -EINVAL; - } + int bus_nr = i2c->adap.nr; if (i2c->soc_data == &rv1108_soc_data && bus_nr == 2) /* rv1108 i2c2 set grf offset-0x408, bit-10 */ @@ -1376,9 +1625,15 @@ /* IRQ setup */ irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "cannot find rk3x IRQ\n"); + if (irq < 0) return irq; + i2c->irq = irq; + + if (IS_ENABLED(CONFIG_ROCKCHIP_THUNDER_BOOT_SERVICE) && + device_property_read_bool(&pdev->dev, "rockchip,amp-shared")) { + i2c->tb_cl.data = i2c; + i2c->tb_cl.cb = rk3x_i2c_tb_cb; + irq_set_status_flags(irq, IRQ_NOAUTOEN); } ret = devm_request_irq(&pdev->dev, irq, rk3x_i2c_irq, @@ -1390,26 +1645,25 @@ platform_set_drvdata(pdev, i2c); - if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) { - /* Only one clock to use for bus clock and peripheral clock */ - i2c->clk = devm_clk_get(&pdev->dev, NULL); - i2c->pclk = i2c->clk; - } else { - i2c->clk = devm_clk_get(&pdev->dev, "i2c"); - i2c->pclk = devm_clk_get(&pdev->dev, "pclk"); - } + 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 */ + i2c->clk = devm_clk_get(&pdev->dev, NULL); + i2c->pclk = i2c->clk; + } 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)) { - ret = PTR_ERR(i2c->clk); - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "Can't get bus clk: %d\n", ret); - return ret; - } - if (IS_ERR(i2c->pclk)) { - ret = PTR_ERR(i2c->pclk); - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "Can't get periph clk: %d\n", ret); - return ret; + if (IS_ERR(i2c->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2c->clk), + "Can't get bus clk\n"); + + if (IS_ERR(i2c->pclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2c->pclk), + "Can't get periph clk\n"); } ret = clk_prepare(i2c->clk); @@ -1423,17 +1677,29 @@ goto err_clk; } - i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb; - ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb); - if (ret != 0) { - dev_err(&pdev->dev, "Unable to register clock notifier\n"); - goto err_pclk; + if (IS_ENABLED(CONFIG_ROCKCHIP_THUNDER_BOOT_SERVICE) && i2c->tb_cl.cb) { + rk_tb_client_register_cb(&i2c->tb_cl); + } else { + if (i2c->clk) { + i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb; + ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb); + if (ret != 0) { + dev_err(&pdev->dev, "Unable to register clock notifier\n"); + goto err_pclk; + } + } + + clk_rate = clk_get_rate(i2c->clk); + if (!clk_rate) + device_property_read_u32(&pdev->dev, "i2c,clk-rate", (u32 *)&clk_rate); + + rk3x_i2c_adapt_div(i2c, clk_rate); + + if (rk3x_i2c_get_version(i2c) >= RK_I2C_VERSION5) + i2c->autostop_supported = true; } - clk_rate = clk_get_rate(i2c->clk); - rk3x_i2c_adapt_div(i2c, clk_rate); - - ret = i2c_add_adapter(&i2c->adap); + ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) goto err_clk_notifier; @@ -1462,7 +1728,7 @@ return 0; } -const static struct dev_pm_ops rk3x_i2c_pm_ops = { +static const struct dev_pm_ops rk3x_i2c_pm_ops = { SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rk3x_i2c_suspend_noirq, rk3x_i2c_resume_noirq) }; @@ -1482,7 +1748,11 @@ { return platform_driver_register(&rk3x_i2c_driver); } +#ifdef CONFIG_INITCALL_ASYNC subsys_initcall_sync(rk3x_i2c_driver_init); +#else +subsys_initcall(rk3x_i2c_driver_init); +#endif static void __exit rk3x_i2c_driver_exit(void) { -- Gitblit v1.6.2