162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for I2C adapter in Rockchip RK3xxx SoC 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Max Schwarz <max.schwarz@online.de> 662306a36Sopenharmony_ci * based on the patches by Rockchip Inc. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/i2c.h> 1262306a36Sopenharmony_ci#include <linux/interrupt.h> 1362306a36Sopenharmony_ci#include <linux/iopoll.h> 1462306a36Sopenharmony_ci#include <linux/errno.h> 1562306a36Sopenharmony_ci#include <linux/err.h> 1662306a36Sopenharmony_ci#include <linux/platform_device.h> 1762306a36Sopenharmony_ci#include <linux/io.h> 1862306a36Sopenharmony_ci#include <linux/of_address.h> 1962306a36Sopenharmony_ci#include <linux/of_irq.h> 2062306a36Sopenharmony_ci#include <linux/spinlock.h> 2162306a36Sopenharmony_ci#include <linux/clk.h> 2262306a36Sopenharmony_ci#include <linux/wait.h> 2362306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 2462306a36Sopenharmony_ci#include <linux/regmap.h> 2562306a36Sopenharmony_ci#include <linux/math64.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* Register Map */ 2962306a36Sopenharmony_ci#define REG_CON 0x00 /* control register */ 3062306a36Sopenharmony_ci#define REG_CLKDIV 0x04 /* clock divisor register */ 3162306a36Sopenharmony_ci#define REG_MRXADDR 0x08 /* slave address for REGISTER_TX */ 3262306a36Sopenharmony_ci#define REG_MRXRADDR 0x0c /* slave register address for REGISTER_TX */ 3362306a36Sopenharmony_ci#define REG_MTXCNT 0x10 /* number of bytes to be transmitted */ 3462306a36Sopenharmony_ci#define REG_MRXCNT 0x14 /* number of bytes to be received */ 3562306a36Sopenharmony_ci#define REG_IEN 0x18 /* interrupt enable */ 3662306a36Sopenharmony_ci#define REG_IPD 0x1c /* interrupt pending */ 3762306a36Sopenharmony_ci#define REG_FCNT 0x20 /* finished count */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* Data buffer offsets */ 4062306a36Sopenharmony_ci#define TXBUFFER_BASE 0x100 4162306a36Sopenharmony_ci#define RXBUFFER_BASE 0x200 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* REG_CON bits */ 4462306a36Sopenharmony_ci#define REG_CON_EN BIT(0) 4562306a36Sopenharmony_cienum { 4662306a36Sopenharmony_ci REG_CON_MOD_TX = 0, /* transmit data */ 4762306a36Sopenharmony_ci REG_CON_MOD_REGISTER_TX, /* select register and restart */ 4862306a36Sopenharmony_ci REG_CON_MOD_RX, /* receive data */ 4962306a36Sopenharmony_ci REG_CON_MOD_REGISTER_RX, /* broken: transmits read addr AND writes 5062306a36Sopenharmony_ci * register addr */ 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci#define REG_CON_MOD(mod) ((mod) << 1) 5362306a36Sopenharmony_ci#define REG_CON_MOD_MASK (BIT(1) | BIT(2)) 5462306a36Sopenharmony_ci#define REG_CON_START BIT(3) 5562306a36Sopenharmony_ci#define REG_CON_STOP BIT(4) 5662306a36Sopenharmony_ci#define REG_CON_LASTACK BIT(5) /* 1: send NACK after last received byte */ 5762306a36Sopenharmony_ci#define REG_CON_ACTACK BIT(6) /* 1: stop if NACK is received */ 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define REG_CON_TUNING_MASK GENMASK_ULL(15, 8) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define REG_CON_SDA_CFG(cfg) ((cfg) << 8) 6262306a36Sopenharmony_ci#define REG_CON_STA_CFG(cfg) ((cfg) << 12) 6362306a36Sopenharmony_ci#define REG_CON_STO_CFG(cfg) ((cfg) << 14) 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* REG_MRXADDR bits */ 6662306a36Sopenharmony_ci#define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */ 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* REG_IEN/REG_IPD bits */ 6962306a36Sopenharmony_ci#define REG_INT_BTF BIT(0) /* a byte was transmitted */ 7062306a36Sopenharmony_ci#define REG_INT_BRF BIT(1) /* a byte was received */ 7162306a36Sopenharmony_ci#define REG_INT_MBTF BIT(2) /* master data transmit finished */ 7262306a36Sopenharmony_ci#define REG_INT_MBRF BIT(3) /* master data receive finished */ 7362306a36Sopenharmony_ci#define REG_INT_START BIT(4) /* START condition generated */ 7462306a36Sopenharmony_ci#define REG_INT_STOP BIT(5) /* STOP condition generated */ 7562306a36Sopenharmony_ci#define REG_INT_NAKRCV BIT(6) /* NACK received */ 7662306a36Sopenharmony_ci#define REG_INT_ALL 0x7f 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* Constants */ 7962306a36Sopenharmony_ci#define WAIT_TIMEOUT 1000 /* ms */ 8062306a36Sopenharmony_ci#define DEFAULT_SCL_RATE (100 * 1000) /* Hz */ 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/** 8362306a36Sopenharmony_ci * struct i2c_spec_values - I2C specification values for various modes 8462306a36Sopenharmony_ci * @min_hold_start_ns: min hold time (repeated) START condition 8562306a36Sopenharmony_ci * @min_low_ns: min LOW period of the SCL clock 8662306a36Sopenharmony_ci * @min_high_ns: min HIGH period of the SCL cloc 8762306a36Sopenharmony_ci * @min_setup_start_ns: min set-up time for a repeated START conditio 8862306a36Sopenharmony_ci * @max_data_hold_ns: max data hold time 8962306a36Sopenharmony_ci * @min_data_setup_ns: min data set-up time 9062306a36Sopenharmony_ci * @min_setup_stop_ns: min set-up time for STOP condition 9162306a36Sopenharmony_ci * @min_hold_buffer_ns: min bus free time between a STOP and 9262306a36Sopenharmony_ci * START condition 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_cistruct i2c_spec_values { 9562306a36Sopenharmony_ci unsigned long min_hold_start_ns; 9662306a36Sopenharmony_ci unsigned long min_low_ns; 9762306a36Sopenharmony_ci unsigned long min_high_ns; 9862306a36Sopenharmony_ci unsigned long min_setup_start_ns; 9962306a36Sopenharmony_ci unsigned long max_data_hold_ns; 10062306a36Sopenharmony_ci unsigned long min_data_setup_ns; 10162306a36Sopenharmony_ci unsigned long min_setup_stop_ns; 10262306a36Sopenharmony_ci unsigned long min_hold_buffer_ns; 10362306a36Sopenharmony_ci}; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic const struct i2c_spec_values standard_mode_spec = { 10662306a36Sopenharmony_ci .min_hold_start_ns = 4000, 10762306a36Sopenharmony_ci .min_low_ns = 4700, 10862306a36Sopenharmony_ci .min_high_ns = 4000, 10962306a36Sopenharmony_ci .min_setup_start_ns = 4700, 11062306a36Sopenharmony_ci .max_data_hold_ns = 3450, 11162306a36Sopenharmony_ci .min_data_setup_ns = 250, 11262306a36Sopenharmony_ci .min_setup_stop_ns = 4000, 11362306a36Sopenharmony_ci .min_hold_buffer_ns = 4700, 11462306a36Sopenharmony_ci}; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic const struct i2c_spec_values fast_mode_spec = { 11762306a36Sopenharmony_ci .min_hold_start_ns = 600, 11862306a36Sopenharmony_ci .min_low_ns = 1300, 11962306a36Sopenharmony_ci .min_high_ns = 600, 12062306a36Sopenharmony_ci .min_setup_start_ns = 600, 12162306a36Sopenharmony_ci .max_data_hold_ns = 900, 12262306a36Sopenharmony_ci .min_data_setup_ns = 100, 12362306a36Sopenharmony_ci .min_setup_stop_ns = 600, 12462306a36Sopenharmony_ci .min_hold_buffer_ns = 1300, 12562306a36Sopenharmony_ci}; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic const struct i2c_spec_values fast_mode_plus_spec = { 12862306a36Sopenharmony_ci .min_hold_start_ns = 260, 12962306a36Sopenharmony_ci .min_low_ns = 500, 13062306a36Sopenharmony_ci .min_high_ns = 260, 13162306a36Sopenharmony_ci .min_setup_start_ns = 260, 13262306a36Sopenharmony_ci .max_data_hold_ns = 400, 13362306a36Sopenharmony_ci .min_data_setup_ns = 50, 13462306a36Sopenharmony_ci .min_setup_stop_ns = 260, 13562306a36Sopenharmony_ci .min_hold_buffer_ns = 500, 13662306a36Sopenharmony_ci}; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci/** 13962306a36Sopenharmony_ci * struct rk3x_i2c_calced_timings - calculated V1 timings 14062306a36Sopenharmony_ci * @div_low: Divider output for low 14162306a36Sopenharmony_ci * @div_high: Divider output for high 14262306a36Sopenharmony_ci * @tuning: Used to adjust setup/hold data time, 14362306a36Sopenharmony_ci * setup/hold start time and setup stop time for 14462306a36Sopenharmony_ci * v1's calc_timings, the tuning should all be 0 14562306a36Sopenharmony_ci * for old hardware anyone using v0's calc_timings. 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_cistruct rk3x_i2c_calced_timings { 14862306a36Sopenharmony_ci unsigned long div_low; 14962306a36Sopenharmony_ci unsigned long div_high; 15062306a36Sopenharmony_ci unsigned int tuning; 15162306a36Sopenharmony_ci}; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cienum rk3x_i2c_state { 15462306a36Sopenharmony_ci STATE_IDLE, 15562306a36Sopenharmony_ci STATE_START, 15662306a36Sopenharmony_ci STATE_READ, 15762306a36Sopenharmony_ci STATE_WRITE, 15862306a36Sopenharmony_ci STATE_STOP 15962306a36Sopenharmony_ci}; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/** 16262306a36Sopenharmony_ci * struct rk3x_i2c_soc_data - SOC-specific data 16362306a36Sopenharmony_ci * @grf_offset: offset inside the grf regmap for setting the i2c type 16462306a36Sopenharmony_ci * @calc_timings: Callback function for i2c timing information calculated 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_cistruct rk3x_i2c_soc_data { 16762306a36Sopenharmony_ci int grf_offset; 16862306a36Sopenharmony_ci int (*calc_timings)(unsigned long, struct i2c_timings *, 16962306a36Sopenharmony_ci struct rk3x_i2c_calced_timings *); 17062306a36Sopenharmony_ci}; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/** 17362306a36Sopenharmony_ci * struct rk3x_i2c - private data of the controller 17462306a36Sopenharmony_ci * @adap: corresponding I2C adapter 17562306a36Sopenharmony_ci * @dev: device for this controller 17662306a36Sopenharmony_ci * @soc_data: related soc data struct 17762306a36Sopenharmony_ci * @regs: virtual memory area 17862306a36Sopenharmony_ci * @clk: function clk for rk3399 or function & Bus clks for others 17962306a36Sopenharmony_ci * @pclk: Bus clk for rk3399 18062306a36Sopenharmony_ci * @clk_rate_nb: i2c clk rate change notify 18162306a36Sopenharmony_ci * @irq: irq number 18262306a36Sopenharmony_ci * @t: I2C known timing information 18362306a36Sopenharmony_ci * @lock: spinlock for the i2c bus 18462306a36Sopenharmony_ci * @wait: the waitqueue to wait for i2c transfer 18562306a36Sopenharmony_ci * @busy: the condition for the event to wait for 18662306a36Sopenharmony_ci * @msg: current i2c message 18762306a36Sopenharmony_ci * @addr: addr of i2c slave device 18862306a36Sopenharmony_ci * @mode: mode of i2c transfer 18962306a36Sopenharmony_ci * @is_last_msg: flag determines whether it is the last msg in this transfer 19062306a36Sopenharmony_ci * @state: state of i2c transfer 19162306a36Sopenharmony_ci * @processed: byte length which has been send or received 19262306a36Sopenharmony_ci * @error: error code for i2c transfer 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_cistruct rk3x_i2c { 19562306a36Sopenharmony_ci struct i2c_adapter adap; 19662306a36Sopenharmony_ci struct device *dev; 19762306a36Sopenharmony_ci const struct rk3x_i2c_soc_data *soc_data; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* Hardware resources */ 20062306a36Sopenharmony_ci void __iomem *regs; 20162306a36Sopenharmony_ci struct clk *clk; 20262306a36Sopenharmony_ci struct clk *pclk; 20362306a36Sopenharmony_ci struct notifier_block clk_rate_nb; 20462306a36Sopenharmony_ci int irq; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* Settings */ 20762306a36Sopenharmony_ci struct i2c_timings t; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* Synchronization & notification */ 21062306a36Sopenharmony_ci spinlock_t lock; 21162306a36Sopenharmony_ci wait_queue_head_t wait; 21262306a36Sopenharmony_ci bool busy; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* Current message */ 21562306a36Sopenharmony_ci struct i2c_msg *msg; 21662306a36Sopenharmony_ci u8 addr; 21762306a36Sopenharmony_ci unsigned int mode; 21862306a36Sopenharmony_ci bool is_last_msg; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* I2C state machine */ 22162306a36Sopenharmony_ci enum rk3x_i2c_state state; 22262306a36Sopenharmony_ci unsigned int processed; 22362306a36Sopenharmony_ci int error; 22462306a36Sopenharmony_ci}; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic inline void i2c_writel(struct rk3x_i2c *i2c, u32 value, 22762306a36Sopenharmony_ci unsigned int offset) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci writel(value, i2c->regs + offset); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic inline u32 i2c_readl(struct rk3x_i2c *i2c, unsigned int offset) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci return readl(i2c->regs + offset); 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci/* Reset all interrupt pending bits */ 23862306a36Sopenharmony_cistatic inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci i2c_writel(i2c, REG_INT_ALL, REG_IPD); 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci/** 24462306a36Sopenharmony_ci * rk3x_i2c_start - Generate a START condition, which triggers a REG_INT_START interrupt. 24562306a36Sopenharmony_ci * @i2c: target controller data 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_cistatic void rk3x_i2c_start(struct rk3x_i2c *i2c) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci u32 val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci i2c_writel(i2c, REG_INT_START, REG_IEN); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* enable adapter with correct mode, send START condition */ 25462306a36Sopenharmony_ci val |= REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci /* if we want to react to NACK, set ACTACK bit */ 25762306a36Sopenharmony_ci if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) 25862306a36Sopenharmony_ci val |= REG_CON_ACTACK; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci i2c_writel(i2c, val, REG_CON); 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci/** 26462306a36Sopenharmony_ci * rk3x_i2c_stop - Generate a STOP condition, which triggers a REG_INT_STOP interrupt. 26562306a36Sopenharmony_ci * @i2c: target controller data 26662306a36Sopenharmony_ci * @error: Error code to return in rk3x_i2c_xfer 26762306a36Sopenharmony_ci */ 26862306a36Sopenharmony_cistatic void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci unsigned int ctrl; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci i2c->processed = 0; 27362306a36Sopenharmony_ci i2c->msg = NULL; 27462306a36Sopenharmony_ci i2c->error = error; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (i2c->is_last_msg) { 27762306a36Sopenharmony_ci /* Enable stop interrupt */ 27862306a36Sopenharmony_ci i2c_writel(i2c, REG_INT_STOP, REG_IEN); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci i2c->state = STATE_STOP; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci ctrl = i2c_readl(i2c, REG_CON); 28362306a36Sopenharmony_ci ctrl |= REG_CON_STOP; 28462306a36Sopenharmony_ci i2c_writel(i2c, ctrl, REG_CON); 28562306a36Sopenharmony_ci } else { 28662306a36Sopenharmony_ci /* Signal rk3x_i2c_xfer to start the next message. */ 28762306a36Sopenharmony_ci i2c->busy = false; 28862306a36Sopenharmony_ci i2c->state = STATE_IDLE; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* 29162306a36Sopenharmony_ci * The HW is actually not capable of REPEATED START. But we can 29262306a36Sopenharmony_ci * get the intended effect by resetting its internal state 29362306a36Sopenharmony_ci * and issuing an ordinary START. 29462306a36Sopenharmony_ci */ 29562306a36Sopenharmony_ci ctrl = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; 29662306a36Sopenharmony_ci i2c_writel(i2c, ctrl, REG_CON); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci /* signal that we are finished with the current msg */ 29962306a36Sopenharmony_ci wake_up(&i2c->wait); 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci/** 30462306a36Sopenharmony_ci * rk3x_i2c_prepare_read - Setup a read according to i2c->msg 30562306a36Sopenharmony_ci * @i2c: target controller data 30662306a36Sopenharmony_ci */ 30762306a36Sopenharmony_cistatic void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci unsigned int len = i2c->msg->len - i2c->processed; 31062306a36Sopenharmony_ci u32 con; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci con = i2c_readl(i2c, REG_CON); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* 31562306a36Sopenharmony_ci * The hw can read up to 32 bytes at a time. If we need more than one 31662306a36Sopenharmony_ci * chunk, send an ACK after the last byte of the current chunk. 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_ci if (len > 32) { 31962306a36Sopenharmony_ci len = 32; 32062306a36Sopenharmony_ci con &= ~REG_CON_LASTACK; 32162306a36Sopenharmony_ci } else { 32262306a36Sopenharmony_ci con |= REG_CON_LASTACK; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* make sure we are in plain RX mode if we read a second chunk */ 32662306a36Sopenharmony_ci if (i2c->processed != 0) { 32762306a36Sopenharmony_ci con &= ~REG_CON_MOD_MASK; 32862306a36Sopenharmony_ci con |= REG_CON_MOD(REG_CON_MOD_RX); 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci i2c_writel(i2c, con, REG_CON); 33262306a36Sopenharmony_ci i2c_writel(i2c, len, REG_MRXCNT); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci/** 33662306a36Sopenharmony_ci * rk3x_i2c_fill_transmit_buf - Fill the transmit buffer with data from i2c->msg 33762306a36Sopenharmony_ci * @i2c: target controller data 33862306a36Sopenharmony_ci */ 33962306a36Sopenharmony_cistatic void rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci unsigned int i, j; 34262306a36Sopenharmony_ci u32 cnt = 0; 34362306a36Sopenharmony_ci u32 val; 34462306a36Sopenharmony_ci u8 byte; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci for (i = 0; i < 8; ++i) { 34762306a36Sopenharmony_ci val = 0; 34862306a36Sopenharmony_ci for (j = 0; j < 4; ++j) { 34962306a36Sopenharmony_ci if ((i2c->processed == i2c->msg->len) && (cnt != 0)) 35062306a36Sopenharmony_ci break; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (i2c->processed == 0 && cnt == 0) 35362306a36Sopenharmony_ci byte = (i2c->addr & 0x7f) << 1; 35462306a36Sopenharmony_ci else 35562306a36Sopenharmony_ci byte = i2c->msg->buf[i2c->processed++]; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci val |= byte << (j * 8); 35862306a36Sopenharmony_ci cnt++; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci i2c_writel(i2c, val, TXBUFFER_BASE + 4 * i); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (i2c->processed == i2c->msg->len) 36462306a36Sopenharmony_ci break; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci i2c_writel(i2c, cnt, REG_MTXCNT); 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci/* IRQ handlers for individual states */ 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic void rk3x_i2c_handle_start(struct rk3x_i2c *i2c, unsigned int ipd) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci if (!(ipd & REG_INT_START)) { 37662306a36Sopenharmony_ci rk3x_i2c_stop(i2c, -EIO); 37762306a36Sopenharmony_ci dev_warn(i2c->dev, "unexpected irq in START: 0x%x\n", ipd); 37862306a36Sopenharmony_ci rk3x_i2c_clean_ipd(i2c); 37962306a36Sopenharmony_ci return; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* ack interrupt */ 38362306a36Sopenharmony_ci i2c_writel(i2c, REG_INT_START, REG_IPD); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* disable start bit */ 38662306a36Sopenharmony_ci i2c_writel(i2c, i2c_readl(i2c, REG_CON) & ~REG_CON_START, REG_CON); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci /* enable appropriate interrupts and transition */ 38962306a36Sopenharmony_ci if (i2c->mode == REG_CON_MOD_TX) { 39062306a36Sopenharmony_ci i2c_writel(i2c, REG_INT_MBTF | REG_INT_NAKRCV, REG_IEN); 39162306a36Sopenharmony_ci i2c->state = STATE_WRITE; 39262306a36Sopenharmony_ci rk3x_i2c_fill_transmit_buf(i2c); 39362306a36Sopenharmony_ci } else { 39462306a36Sopenharmony_ci /* in any other case, we are going to be reading. */ 39562306a36Sopenharmony_ci i2c_writel(i2c, REG_INT_MBRF | REG_INT_NAKRCV, REG_IEN); 39662306a36Sopenharmony_ci i2c->state = STATE_READ; 39762306a36Sopenharmony_ci rk3x_i2c_prepare_read(i2c); 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic void rk3x_i2c_handle_write(struct rk3x_i2c *i2c, unsigned int ipd) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci if (!(ipd & REG_INT_MBTF)) { 40462306a36Sopenharmony_ci rk3x_i2c_stop(i2c, -EIO); 40562306a36Sopenharmony_ci dev_err(i2c->dev, "unexpected irq in WRITE: 0x%x\n", ipd); 40662306a36Sopenharmony_ci rk3x_i2c_clean_ipd(i2c); 40762306a36Sopenharmony_ci return; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* ack interrupt */ 41162306a36Sopenharmony_ci i2c_writel(i2c, REG_INT_MBTF, REG_IPD); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci /* are we finished? */ 41462306a36Sopenharmony_ci if (i2c->processed == i2c->msg->len) 41562306a36Sopenharmony_ci rk3x_i2c_stop(i2c, i2c->error); 41662306a36Sopenharmony_ci else 41762306a36Sopenharmony_ci rk3x_i2c_fill_transmit_buf(i2c); 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic void rk3x_i2c_handle_read(struct rk3x_i2c *i2c, unsigned int ipd) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci unsigned int i; 42362306a36Sopenharmony_ci unsigned int len = i2c->msg->len - i2c->processed; 42462306a36Sopenharmony_ci u32 val; 42562306a36Sopenharmony_ci u8 byte; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* we only care for MBRF here. */ 42862306a36Sopenharmony_ci if (!(ipd & REG_INT_MBRF)) 42962306a36Sopenharmony_ci return; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci /* ack interrupt (read also produces a spurious START flag, clear it too) */ 43262306a36Sopenharmony_ci i2c_writel(i2c, REG_INT_MBRF | REG_INT_START, REG_IPD); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci /* Can only handle a maximum of 32 bytes at a time */ 43562306a36Sopenharmony_ci if (len > 32) 43662306a36Sopenharmony_ci len = 32; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* read the data from receive buffer */ 43962306a36Sopenharmony_ci for (i = 0; i < len; ++i) { 44062306a36Sopenharmony_ci if (i % 4 == 0) 44162306a36Sopenharmony_ci val = i2c_readl(i2c, RXBUFFER_BASE + (i / 4) * 4); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci byte = (val >> ((i % 4) * 8)) & 0xff; 44462306a36Sopenharmony_ci i2c->msg->buf[i2c->processed++] = byte; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci /* are we finished? */ 44862306a36Sopenharmony_ci if (i2c->processed == i2c->msg->len) 44962306a36Sopenharmony_ci rk3x_i2c_stop(i2c, i2c->error); 45062306a36Sopenharmony_ci else 45162306a36Sopenharmony_ci rk3x_i2c_prepare_read(i2c); 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cistatic void rk3x_i2c_handle_stop(struct rk3x_i2c *i2c, unsigned int ipd) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci unsigned int con; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (!(ipd & REG_INT_STOP)) { 45962306a36Sopenharmony_ci rk3x_i2c_stop(i2c, -EIO); 46062306a36Sopenharmony_ci dev_err(i2c->dev, "unexpected irq in STOP: 0x%x\n", ipd); 46162306a36Sopenharmony_ci rk3x_i2c_clean_ipd(i2c); 46262306a36Sopenharmony_ci return; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci /* ack interrupt */ 46662306a36Sopenharmony_ci i2c_writel(i2c, REG_INT_STOP, REG_IPD); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* disable STOP bit */ 46962306a36Sopenharmony_ci con = i2c_readl(i2c, REG_CON); 47062306a36Sopenharmony_ci con &= ~REG_CON_STOP; 47162306a36Sopenharmony_ci i2c_writel(i2c, con, REG_CON); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci i2c->busy = false; 47462306a36Sopenharmony_ci i2c->state = STATE_IDLE; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci /* signal rk3x_i2c_xfer that we are finished */ 47762306a36Sopenharmony_ci wake_up(&i2c->wait); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci struct rk3x_i2c *i2c = dev_id; 48362306a36Sopenharmony_ci unsigned int ipd; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci spin_lock(&i2c->lock); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci ipd = i2c_readl(i2c, REG_IPD); 48862306a36Sopenharmony_ci if (i2c->state == STATE_IDLE) { 48962306a36Sopenharmony_ci dev_warn(i2c->dev, "irq in STATE_IDLE, ipd = 0x%x\n", ipd); 49062306a36Sopenharmony_ci rk3x_i2c_clean_ipd(i2c); 49162306a36Sopenharmony_ci goto out; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci dev_dbg(i2c->dev, "IRQ: state %d, ipd: %x\n", i2c->state, ipd); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci /* Clean interrupt bits we don't care about */ 49762306a36Sopenharmony_ci ipd &= ~(REG_INT_BRF | REG_INT_BTF); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (ipd & REG_INT_NAKRCV) { 50062306a36Sopenharmony_ci /* 50162306a36Sopenharmony_ci * We got a NACK in the last operation. Depending on whether 50262306a36Sopenharmony_ci * IGNORE_NAK is set, we have to stop the operation and report 50362306a36Sopenharmony_ci * an error. 50462306a36Sopenharmony_ci */ 50562306a36Sopenharmony_ci i2c_writel(i2c, REG_INT_NAKRCV, REG_IPD); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci ipd &= ~REG_INT_NAKRCV; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) 51062306a36Sopenharmony_ci rk3x_i2c_stop(i2c, -ENXIO); 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci /* is there anything left to handle? */ 51462306a36Sopenharmony_ci if ((ipd & REG_INT_ALL) == 0) 51562306a36Sopenharmony_ci goto out; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci switch (i2c->state) { 51862306a36Sopenharmony_ci case STATE_START: 51962306a36Sopenharmony_ci rk3x_i2c_handle_start(i2c, ipd); 52062306a36Sopenharmony_ci break; 52162306a36Sopenharmony_ci case STATE_WRITE: 52262306a36Sopenharmony_ci rk3x_i2c_handle_write(i2c, ipd); 52362306a36Sopenharmony_ci break; 52462306a36Sopenharmony_ci case STATE_READ: 52562306a36Sopenharmony_ci rk3x_i2c_handle_read(i2c, ipd); 52662306a36Sopenharmony_ci break; 52762306a36Sopenharmony_ci case STATE_STOP: 52862306a36Sopenharmony_ci rk3x_i2c_handle_stop(i2c, ipd); 52962306a36Sopenharmony_ci break; 53062306a36Sopenharmony_ci case STATE_IDLE: 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ciout: 53562306a36Sopenharmony_ci spin_unlock(&i2c->lock); 53662306a36Sopenharmony_ci return IRQ_HANDLED; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci/** 54062306a36Sopenharmony_ci * rk3x_i2c_get_spec - Get timing values of I2C specification 54162306a36Sopenharmony_ci * @speed: Desired SCL frequency 54262306a36Sopenharmony_ci * 54362306a36Sopenharmony_ci * Return: Matched i2c_spec_values. 54462306a36Sopenharmony_ci */ 54562306a36Sopenharmony_cistatic const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci if (speed <= I2C_MAX_STANDARD_MODE_FREQ) 54862306a36Sopenharmony_ci return &standard_mode_spec; 54962306a36Sopenharmony_ci else if (speed <= I2C_MAX_FAST_MODE_FREQ) 55062306a36Sopenharmony_ci return &fast_mode_spec; 55162306a36Sopenharmony_ci else 55262306a36Sopenharmony_ci return &fast_mode_plus_spec; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci/** 55662306a36Sopenharmony_ci * rk3x_i2c_v0_calc_timings - Calculate divider values for desired SCL frequency 55762306a36Sopenharmony_ci * @clk_rate: I2C input clock rate 55862306a36Sopenharmony_ci * @t: Known I2C timing information 55962306a36Sopenharmony_ci * @t_calc: Caculated rk3x private timings that would be written into regs 56062306a36Sopenharmony_ci * 56162306a36Sopenharmony_ci * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case 56262306a36Sopenharmony_ci * a best-effort divider value is returned in divs. If the target rate is 56362306a36Sopenharmony_ci * too high, we silently use the highest possible rate. 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_cistatic int rk3x_i2c_v0_calc_timings(unsigned long clk_rate, 56662306a36Sopenharmony_ci struct i2c_timings *t, 56762306a36Sopenharmony_ci struct rk3x_i2c_calced_timings *t_calc) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci unsigned long min_low_ns, min_high_ns; 57062306a36Sopenharmony_ci unsigned long max_low_ns, min_total_ns; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci unsigned long clk_rate_khz, scl_rate_khz; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci unsigned long min_low_div, min_high_div; 57562306a36Sopenharmony_ci unsigned long max_low_div; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci unsigned long min_div_for_hold, min_total_div; 57862306a36Sopenharmony_ci unsigned long extra_div, extra_low_div, ideal_low_div; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci unsigned long data_hold_buffer_ns = 50; 58162306a36Sopenharmony_ci const struct i2c_spec_values *spec; 58262306a36Sopenharmony_ci int ret = 0; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* Only support standard-mode and fast-mode */ 58562306a36Sopenharmony_ci if (WARN_ON(t->bus_freq_hz > I2C_MAX_FAST_MODE_FREQ)) 58662306a36Sopenharmony_ci t->bus_freq_hz = I2C_MAX_FAST_MODE_FREQ; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* prevent scl_rate_khz from becoming 0 */ 58962306a36Sopenharmony_ci if (WARN_ON(t->bus_freq_hz < 1000)) 59062306a36Sopenharmony_ci t->bus_freq_hz = 1000; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci /* 59362306a36Sopenharmony_ci * min_low_ns: The minimum number of ns we need to hold low to 59462306a36Sopenharmony_ci * meet I2C specification, should include fall time. 59562306a36Sopenharmony_ci * min_high_ns: The minimum number of ns we need to hold high to 59662306a36Sopenharmony_ci * meet I2C specification, should include rise time. 59762306a36Sopenharmony_ci * max_low_ns: The maximum number of ns we can hold low to meet 59862306a36Sopenharmony_ci * I2C specification. 59962306a36Sopenharmony_ci * 60062306a36Sopenharmony_ci * Note: max_low_ns should be (maximum data hold time * 2 - buffer) 60162306a36Sopenharmony_ci * This is because the i2c host on Rockchip holds the data line 60262306a36Sopenharmony_ci * for half the low time. 60362306a36Sopenharmony_ci */ 60462306a36Sopenharmony_ci spec = rk3x_i2c_get_spec(t->bus_freq_hz); 60562306a36Sopenharmony_ci min_high_ns = t->scl_rise_ns + spec->min_high_ns; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci /* 60862306a36Sopenharmony_ci * Timings for repeated start: 60962306a36Sopenharmony_ci * - controller appears to drop SDA at .875x (7/8) programmed clk high. 61062306a36Sopenharmony_ci * - controller appears to keep SCL high for 2x programmed clk high. 61162306a36Sopenharmony_ci * 61262306a36Sopenharmony_ci * We need to account for those rules in picking our "high" time so 61362306a36Sopenharmony_ci * we meet tSU;STA and tHD;STA times. 61462306a36Sopenharmony_ci */ 61562306a36Sopenharmony_ci min_high_ns = max(min_high_ns, DIV_ROUND_UP( 61662306a36Sopenharmony_ci (t->scl_rise_ns + spec->min_setup_start_ns) * 1000, 875)); 61762306a36Sopenharmony_ci min_high_ns = max(min_high_ns, DIV_ROUND_UP( 61862306a36Sopenharmony_ci (t->scl_rise_ns + spec->min_setup_start_ns + t->sda_fall_ns + 61962306a36Sopenharmony_ci spec->min_high_ns), 2)); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci min_low_ns = t->scl_fall_ns + spec->min_low_ns; 62262306a36Sopenharmony_ci max_low_ns = spec->max_data_hold_ns * 2 - data_hold_buffer_ns; 62362306a36Sopenharmony_ci min_total_ns = min_low_ns + min_high_ns; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci /* Adjust to avoid overflow */ 62662306a36Sopenharmony_ci clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000); 62762306a36Sopenharmony_ci scl_rate_khz = t->bus_freq_hz / 1000; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci /* 63062306a36Sopenharmony_ci * We need the total div to be >= this number 63162306a36Sopenharmony_ci * so we don't clock too fast. 63262306a36Sopenharmony_ci */ 63362306a36Sopenharmony_ci min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci /* These are the min dividers needed for min hold times. */ 63662306a36Sopenharmony_ci min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000); 63762306a36Sopenharmony_ci min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000); 63862306a36Sopenharmony_ci min_div_for_hold = (min_low_div + min_high_div); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* 64162306a36Sopenharmony_ci * This is the maximum divider so we don't go over the maximum. 64262306a36Sopenharmony_ci * We don't round up here (we round down) since this is a maximum. 64362306a36Sopenharmony_ci */ 64462306a36Sopenharmony_ci max_low_div = clk_rate_khz * max_low_ns / (8 * 1000000); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci if (min_low_div > max_low_div) { 64762306a36Sopenharmony_ci WARN_ONCE(true, 64862306a36Sopenharmony_ci "Conflicting, min_low_div %lu, max_low_div %lu\n", 64962306a36Sopenharmony_ci min_low_div, max_low_div); 65062306a36Sopenharmony_ci max_low_div = min_low_div; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci if (min_div_for_hold > min_total_div) { 65462306a36Sopenharmony_ci /* 65562306a36Sopenharmony_ci * Time needed to meet hold requirements is important. 65662306a36Sopenharmony_ci * Just use that. 65762306a36Sopenharmony_ci */ 65862306a36Sopenharmony_ci t_calc->div_low = min_low_div; 65962306a36Sopenharmony_ci t_calc->div_high = min_high_div; 66062306a36Sopenharmony_ci } else { 66162306a36Sopenharmony_ci /* 66262306a36Sopenharmony_ci * We've got to distribute some time among the low and high 66362306a36Sopenharmony_ci * so we don't run too fast. 66462306a36Sopenharmony_ci */ 66562306a36Sopenharmony_ci extra_div = min_total_div - min_div_for_hold; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* 66862306a36Sopenharmony_ci * We'll try to split things up perfectly evenly, 66962306a36Sopenharmony_ci * biasing slightly towards having a higher div 67062306a36Sopenharmony_ci * for low (spend more time low). 67162306a36Sopenharmony_ci */ 67262306a36Sopenharmony_ci ideal_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 67362306a36Sopenharmony_ci scl_rate_khz * 8 * min_total_ns); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* Don't allow it to go over the maximum */ 67662306a36Sopenharmony_ci if (ideal_low_div > max_low_div) 67762306a36Sopenharmony_ci ideal_low_div = max_low_div; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* 68062306a36Sopenharmony_ci * Handle when the ideal low div is going to take up 68162306a36Sopenharmony_ci * more than we have. 68262306a36Sopenharmony_ci */ 68362306a36Sopenharmony_ci if (ideal_low_div > min_low_div + extra_div) 68462306a36Sopenharmony_ci ideal_low_div = min_low_div + extra_div; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* Give low the "ideal" and give high whatever extra is left */ 68762306a36Sopenharmony_ci extra_low_div = ideal_low_div - min_low_div; 68862306a36Sopenharmony_ci t_calc->div_low = ideal_low_div; 68962306a36Sopenharmony_ci t_calc->div_high = min_high_div + (extra_div - extra_low_div); 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci /* 69362306a36Sopenharmony_ci * Adjust to the fact that the hardware has an implicit "+1". 69462306a36Sopenharmony_ci * NOTE: Above calculations always produce div_low > 0 and div_high > 0. 69562306a36Sopenharmony_ci */ 69662306a36Sopenharmony_ci t_calc->div_low--; 69762306a36Sopenharmony_ci t_calc->div_high--; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci /* Give the tuning value 0, that would not update con register */ 70062306a36Sopenharmony_ci t_calc->tuning = 0; 70162306a36Sopenharmony_ci /* Maximum divider supported by hw is 0xffff */ 70262306a36Sopenharmony_ci if (t_calc->div_low > 0xffff) { 70362306a36Sopenharmony_ci t_calc->div_low = 0xffff; 70462306a36Sopenharmony_ci ret = -EINVAL; 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci if (t_calc->div_high > 0xffff) { 70862306a36Sopenharmony_ci t_calc->div_high = 0xffff; 70962306a36Sopenharmony_ci ret = -EINVAL; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci return ret; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci/** 71662306a36Sopenharmony_ci * rk3x_i2c_v1_calc_timings - Calculate timing values for desired SCL frequency 71762306a36Sopenharmony_ci * @clk_rate: I2C input clock rate 71862306a36Sopenharmony_ci * @t: Known I2C timing information 71962306a36Sopenharmony_ci * @t_calc: Caculated rk3x private timings that would be written into regs 72062306a36Sopenharmony_ci * 72162306a36Sopenharmony_ci * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case 72262306a36Sopenharmony_ci * a best-effort divider value is returned in divs. If the target rate is 72362306a36Sopenharmony_ci * too high, we silently use the highest possible rate. 72462306a36Sopenharmony_ci * The following formulas are v1's method to calculate timings. 72562306a36Sopenharmony_ci * 72662306a36Sopenharmony_ci * l = divl + 1; 72762306a36Sopenharmony_ci * h = divh + 1; 72862306a36Sopenharmony_ci * s = sda_update_config + 1; 72962306a36Sopenharmony_ci * u = start_setup_config + 1; 73062306a36Sopenharmony_ci * p = stop_setup_config + 1; 73162306a36Sopenharmony_ci * T = Tclk_i2c; 73262306a36Sopenharmony_ci * 73362306a36Sopenharmony_ci * tHigh = 8 * h * T; 73462306a36Sopenharmony_ci * tLow = 8 * l * T; 73562306a36Sopenharmony_ci * 73662306a36Sopenharmony_ci * tHD;sda = (l * s + 1) * T; 73762306a36Sopenharmony_ci * tSU;sda = [(8 - s) * l + 1] * T; 73862306a36Sopenharmony_ci * tI2C = 8 * (l + h) * T; 73962306a36Sopenharmony_ci * 74062306a36Sopenharmony_ci * tSU;sta = (8h * u + 1) * T; 74162306a36Sopenharmony_ci * tHD;sta = [8h * (u + 1) - 1] * T; 74262306a36Sopenharmony_ci * tSU;sto = (8h * p + 1) * T; 74362306a36Sopenharmony_ci */ 74462306a36Sopenharmony_cistatic int rk3x_i2c_v1_calc_timings(unsigned long clk_rate, 74562306a36Sopenharmony_ci struct i2c_timings *t, 74662306a36Sopenharmony_ci struct rk3x_i2c_calced_timings *t_calc) 74762306a36Sopenharmony_ci{ 74862306a36Sopenharmony_ci unsigned long min_low_ns, min_high_ns; 74962306a36Sopenharmony_ci unsigned long min_setup_start_ns, min_setup_data_ns; 75062306a36Sopenharmony_ci unsigned long min_setup_stop_ns, max_hold_data_ns; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci unsigned long clk_rate_khz, scl_rate_khz; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci unsigned long min_low_div, min_high_div; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci unsigned long min_div_for_hold, min_total_div; 75762306a36Sopenharmony_ci unsigned long extra_div, extra_low_div; 75862306a36Sopenharmony_ci unsigned long sda_update_cfg, stp_sta_cfg, stp_sto_cfg; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci const struct i2c_spec_values *spec; 76162306a36Sopenharmony_ci int ret = 0; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci /* Support standard-mode, fast-mode and fast-mode plus */ 76462306a36Sopenharmony_ci if (WARN_ON(t->bus_freq_hz > I2C_MAX_FAST_MODE_PLUS_FREQ)) 76562306a36Sopenharmony_ci t->bus_freq_hz = I2C_MAX_FAST_MODE_PLUS_FREQ; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci /* prevent scl_rate_khz from becoming 0 */ 76862306a36Sopenharmony_ci if (WARN_ON(t->bus_freq_hz < 1000)) 76962306a36Sopenharmony_ci t->bus_freq_hz = 1000; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci /* 77262306a36Sopenharmony_ci * min_low_ns: The minimum number of ns we need to hold low to 77362306a36Sopenharmony_ci * meet I2C specification, should include fall time. 77462306a36Sopenharmony_ci * min_high_ns: The minimum number of ns we need to hold high to 77562306a36Sopenharmony_ci * meet I2C specification, should include rise time. 77662306a36Sopenharmony_ci */ 77762306a36Sopenharmony_ci spec = rk3x_i2c_get_spec(t->bus_freq_hz); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci /* calculate min-divh and min-divl */ 78062306a36Sopenharmony_ci clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000); 78162306a36Sopenharmony_ci scl_rate_khz = t->bus_freq_hz / 1000; 78262306a36Sopenharmony_ci min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci min_high_ns = t->scl_rise_ns + spec->min_high_ns; 78562306a36Sopenharmony_ci min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci min_low_ns = t->scl_fall_ns + spec->min_low_ns; 78862306a36Sopenharmony_ci min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci /* 79162306a36Sopenharmony_ci * Final divh and divl must be greater than 0, otherwise the 79262306a36Sopenharmony_ci * hardware would not output the i2c clk. 79362306a36Sopenharmony_ci */ 79462306a36Sopenharmony_ci min_high_div = (min_high_div < 1) ? 2 : min_high_div; 79562306a36Sopenharmony_ci min_low_div = (min_low_div < 1) ? 2 : min_low_div; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci /* These are the min dividers needed for min hold times. */ 79862306a36Sopenharmony_ci min_div_for_hold = (min_low_div + min_high_div); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci /* 80162306a36Sopenharmony_ci * This is the maximum divider so we don't go over the maximum. 80262306a36Sopenharmony_ci * We don't round up here (we round down) since this is a maximum. 80362306a36Sopenharmony_ci */ 80462306a36Sopenharmony_ci if (min_div_for_hold >= min_total_div) { 80562306a36Sopenharmony_ci /* 80662306a36Sopenharmony_ci * Time needed to meet hold requirements is important. 80762306a36Sopenharmony_ci * Just use that. 80862306a36Sopenharmony_ci */ 80962306a36Sopenharmony_ci t_calc->div_low = min_low_div; 81062306a36Sopenharmony_ci t_calc->div_high = min_high_div; 81162306a36Sopenharmony_ci } else { 81262306a36Sopenharmony_ci /* 81362306a36Sopenharmony_ci * We've got to distribute some time among the low and high 81462306a36Sopenharmony_ci * so we don't run too fast. 81562306a36Sopenharmony_ci * We'll try to split things up by the scale of min_low_div and 81662306a36Sopenharmony_ci * min_high_div, biasing slightly towards having a higher div 81762306a36Sopenharmony_ci * for low (spend more time low). 81862306a36Sopenharmony_ci */ 81962306a36Sopenharmony_ci extra_div = min_total_div - min_div_for_hold; 82062306a36Sopenharmony_ci extra_low_div = DIV_ROUND_UP(min_low_div * extra_div, 82162306a36Sopenharmony_ci min_div_for_hold); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci t_calc->div_low = min_low_div + extra_low_div; 82462306a36Sopenharmony_ci t_calc->div_high = min_high_div + (extra_div - extra_low_div); 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci /* 82862306a36Sopenharmony_ci * calculate sda data hold count by the rules, data_upd_st:3 82962306a36Sopenharmony_ci * is a appropriate value to reduce calculated times. 83062306a36Sopenharmony_ci */ 83162306a36Sopenharmony_ci for (sda_update_cfg = 3; sda_update_cfg > 0; sda_update_cfg--) { 83262306a36Sopenharmony_ci max_hold_data_ns = DIV_ROUND_UP((sda_update_cfg 83362306a36Sopenharmony_ci * (t_calc->div_low) + 1) 83462306a36Sopenharmony_ci * 1000000, clk_rate_khz); 83562306a36Sopenharmony_ci min_setup_data_ns = DIV_ROUND_UP(((8 - sda_update_cfg) 83662306a36Sopenharmony_ci * (t_calc->div_low) + 1) 83762306a36Sopenharmony_ci * 1000000, clk_rate_khz); 83862306a36Sopenharmony_ci if ((max_hold_data_ns < spec->max_data_hold_ns) && 83962306a36Sopenharmony_ci (min_setup_data_ns > spec->min_data_setup_ns)) 84062306a36Sopenharmony_ci break; 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci /* calculate setup start config */ 84462306a36Sopenharmony_ci min_setup_start_ns = t->scl_rise_ns + spec->min_setup_start_ns; 84562306a36Sopenharmony_ci stp_sta_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_start_ns 84662306a36Sopenharmony_ci - 1000000, 8 * 1000000 * (t_calc->div_high)); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci /* calculate setup stop config */ 84962306a36Sopenharmony_ci min_setup_stop_ns = t->scl_rise_ns + spec->min_setup_stop_ns; 85062306a36Sopenharmony_ci stp_sto_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_stop_ns 85162306a36Sopenharmony_ci - 1000000, 8 * 1000000 * (t_calc->div_high)); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci t_calc->tuning = REG_CON_SDA_CFG(--sda_update_cfg) | 85462306a36Sopenharmony_ci REG_CON_STA_CFG(--stp_sta_cfg) | 85562306a36Sopenharmony_ci REG_CON_STO_CFG(--stp_sto_cfg); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci t_calc->div_low--; 85862306a36Sopenharmony_ci t_calc->div_high--; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci /* Maximum divider supported by hw is 0xffff */ 86162306a36Sopenharmony_ci if (t_calc->div_low > 0xffff) { 86262306a36Sopenharmony_ci t_calc->div_low = 0xffff; 86362306a36Sopenharmony_ci ret = -EINVAL; 86462306a36Sopenharmony_ci } 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci if (t_calc->div_high > 0xffff) { 86762306a36Sopenharmony_ci t_calc->div_high = 0xffff; 86862306a36Sopenharmony_ci ret = -EINVAL; 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci return ret; 87262306a36Sopenharmony_ci} 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_cistatic void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate) 87562306a36Sopenharmony_ci{ 87662306a36Sopenharmony_ci struct i2c_timings *t = &i2c->t; 87762306a36Sopenharmony_ci struct rk3x_i2c_calced_timings calc; 87862306a36Sopenharmony_ci u64 t_low_ns, t_high_ns; 87962306a36Sopenharmony_ci unsigned long flags; 88062306a36Sopenharmony_ci u32 val; 88162306a36Sopenharmony_ci int ret; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci ret = i2c->soc_data->calc_timings(clk_rate, t, &calc); 88462306a36Sopenharmony_ci WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci clk_enable(i2c->pclk); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci spin_lock_irqsave(&i2c->lock, flags); 88962306a36Sopenharmony_ci val = i2c_readl(i2c, REG_CON); 89062306a36Sopenharmony_ci val &= ~REG_CON_TUNING_MASK; 89162306a36Sopenharmony_ci val |= calc.tuning; 89262306a36Sopenharmony_ci i2c_writel(i2c, val, REG_CON); 89362306a36Sopenharmony_ci i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff), 89462306a36Sopenharmony_ci REG_CLKDIV); 89562306a36Sopenharmony_ci spin_unlock_irqrestore(&i2c->lock, flags); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci clk_disable(i2c->pclk); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci t_low_ns = div_u64(((u64)calc.div_low + 1) * 8 * 1000000000, clk_rate); 90062306a36Sopenharmony_ci t_high_ns = div_u64(((u64)calc.div_high + 1) * 8 * 1000000000, 90162306a36Sopenharmony_ci clk_rate); 90262306a36Sopenharmony_ci dev_dbg(i2c->dev, 90362306a36Sopenharmony_ci "CLK %lukhz, Req %uns, Act low %lluns high %lluns\n", 90462306a36Sopenharmony_ci clk_rate / 1000, 90562306a36Sopenharmony_ci 1000000000 / t->bus_freq_hz, 90662306a36Sopenharmony_ci t_low_ns, t_high_ns); 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci/** 91062306a36Sopenharmony_ci * rk3x_i2c_clk_notifier_cb - Clock rate change callback 91162306a36Sopenharmony_ci * @nb: Pointer to notifier block 91262306a36Sopenharmony_ci * @event: Notification reason 91362306a36Sopenharmony_ci * @data: Pointer to notification data object 91462306a36Sopenharmony_ci * 91562306a36Sopenharmony_ci * The callback checks whether a valid bus frequency can be generated after the 91662306a36Sopenharmony_ci * change. If so, the change is acknowledged, otherwise the change is aborted. 91762306a36Sopenharmony_ci * New dividers are written to the HW in the pre- or post change notification 91862306a36Sopenharmony_ci * depending on the scaling direction. 91962306a36Sopenharmony_ci * 92062306a36Sopenharmony_ci * Code adapted from i2c-cadence.c. 92162306a36Sopenharmony_ci * 92262306a36Sopenharmony_ci * Return: NOTIFY_STOP if the rate change should be aborted, NOTIFY_OK 92362306a36Sopenharmony_ci * to acknowledge the change, NOTIFY_DONE if the notification is 92462306a36Sopenharmony_ci * considered irrelevant. 92562306a36Sopenharmony_ci */ 92662306a36Sopenharmony_cistatic int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long 92762306a36Sopenharmony_ci event, void *data) 92862306a36Sopenharmony_ci{ 92962306a36Sopenharmony_ci struct clk_notifier_data *ndata = data; 93062306a36Sopenharmony_ci struct rk3x_i2c *i2c = container_of(nb, struct rk3x_i2c, clk_rate_nb); 93162306a36Sopenharmony_ci struct rk3x_i2c_calced_timings calc; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci switch (event) { 93462306a36Sopenharmony_ci case PRE_RATE_CHANGE: 93562306a36Sopenharmony_ci /* 93662306a36Sopenharmony_ci * Try the calculation (but don't store the result) ahead of 93762306a36Sopenharmony_ci * time to see if we need to block the clock change. Timings 93862306a36Sopenharmony_ci * shouldn't actually take effect until rk3x_i2c_adapt_div(). 93962306a36Sopenharmony_ci */ 94062306a36Sopenharmony_ci if (i2c->soc_data->calc_timings(ndata->new_rate, &i2c->t, 94162306a36Sopenharmony_ci &calc) != 0) 94262306a36Sopenharmony_ci return NOTIFY_STOP; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci /* scale up */ 94562306a36Sopenharmony_ci if (ndata->new_rate > ndata->old_rate) 94662306a36Sopenharmony_ci rk3x_i2c_adapt_div(i2c, ndata->new_rate); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci return NOTIFY_OK; 94962306a36Sopenharmony_ci case POST_RATE_CHANGE: 95062306a36Sopenharmony_ci /* scale down */ 95162306a36Sopenharmony_ci if (ndata->new_rate < ndata->old_rate) 95262306a36Sopenharmony_ci rk3x_i2c_adapt_div(i2c, ndata->new_rate); 95362306a36Sopenharmony_ci return NOTIFY_OK; 95462306a36Sopenharmony_ci case ABORT_RATE_CHANGE: 95562306a36Sopenharmony_ci /* scale up */ 95662306a36Sopenharmony_ci if (ndata->new_rate > ndata->old_rate) 95762306a36Sopenharmony_ci rk3x_i2c_adapt_div(i2c, ndata->old_rate); 95862306a36Sopenharmony_ci return NOTIFY_OK; 95962306a36Sopenharmony_ci default: 96062306a36Sopenharmony_ci return NOTIFY_DONE; 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci} 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci/** 96562306a36Sopenharmony_ci * rk3x_i2c_setup - Setup I2C registers for an I2C operation specified by msgs, num. 96662306a36Sopenharmony_ci * @i2c: target controller data 96762306a36Sopenharmony_ci * @msgs: I2C msgs to process 96862306a36Sopenharmony_ci * @num: Number of msgs 96962306a36Sopenharmony_ci * 97062306a36Sopenharmony_ci * Must be called with i2c->lock held. 97162306a36Sopenharmony_ci * 97262306a36Sopenharmony_ci * Return: Number of I2C msgs processed or negative in case of error 97362306a36Sopenharmony_ci */ 97462306a36Sopenharmony_cistatic int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num) 97562306a36Sopenharmony_ci{ 97662306a36Sopenharmony_ci u32 addr = (msgs[0].addr & 0x7f) << 1; 97762306a36Sopenharmony_ci int ret = 0; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci /* 98062306a36Sopenharmony_ci * The I2C adapter can issue a small (len < 4) write packet before 98162306a36Sopenharmony_ci * reading. This speeds up SMBus-style register reads. 98262306a36Sopenharmony_ci * The MRXADDR/MRXRADDR hold the slave address and the slave register 98362306a36Sopenharmony_ci * address in this case. 98462306a36Sopenharmony_ci */ 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci if (num >= 2 && msgs[0].len < 4 && 98762306a36Sopenharmony_ci !(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD)) { 98862306a36Sopenharmony_ci u32 reg_addr = 0; 98962306a36Sopenharmony_ci int i; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci dev_dbg(i2c->dev, "Combined write/read from addr 0x%x\n", 99262306a36Sopenharmony_ci addr >> 1); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci /* Fill MRXRADDR with the register address(es) */ 99562306a36Sopenharmony_ci for (i = 0; i < msgs[0].len; ++i) { 99662306a36Sopenharmony_ci reg_addr |= msgs[0].buf[i] << (i * 8); 99762306a36Sopenharmony_ci reg_addr |= REG_MRXADDR_VALID(i); 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci /* msgs[0] is handled by hw. */ 100162306a36Sopenharmony_ci i2c->msg = &msgs[1]; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci i2c->mode = REG_CON_MOD_REGISTER_TX; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci i2c_writel(i2c, addr | REG_MRXADDR_VALID(0), REG_MRXADDR); 100662306a36Sopenharmony_ci i2c_writel(i2c, reg_addr, REG_MRXRADDR); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci ret = 2; 100962306a36Sopenharmony_ci } else { 101062306a36Sopenharmony_ci /* 101162306a36Sopenharmony_ci * We'll have to do it the boring way and process the msgs 101262306a36Sopenharmony_ci * one-by-one. 101362306a36Sopenharmony_ci */ 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci if (msgs[0].flags & I2C_M_RD) { 101662306a36Sopenharmony_ci addr |= 1; /* set read bit */ 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci /* 101962306a36Sopenharmony_ci * We have to transmit the slave addr first. Use 102062306a36Sopenharmony_ci * MOD_REGISTER_TX for that purpose. 102162306a36Sopenharmony_ci */ 102262306a36Sopenharmony_ci i2c->mode = REG_CON_MOD_REGISTER_TX; 102362306a36Sopenharmony_ci i2c_writel(i2c, addr | REG_MRXADDR_VALID(0), 102462306a36Sopenharmony_ci REG_MRXADDR); 102562306a36Sopenharmony_ci i2c_writel(i2c, 0, REG_MRXRADDR); 102662306a36Sopenharmony_ci } else { 102762306a36Sopenharmony_ci i2c->mode = REG_CON_MOD_TX; 102862306a36Sopenharmony_ci } 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci i2c->msg = &msgs[0]; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci ret = 1; 103362306a36Sopenharmony_ci } 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci i2c->addr = msgs[0].addr; 103662306a36Sopenharmony_ci i2c->busy = true; 103762306a36Sopenharmony_ci i2c->state = STATE_START; 103862306a36Sopenharmony_ci i2c->processed = 0; 103962306a36Sopenharmony_ci i2c->error = 0; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci rk3x_i2c_clean_ipd(i2c); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci return ret; 104462306a36Sopenharmony_ci} 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_cistatic int rk3x_i2c_wait_xfer_poll(struct rk3x_i2c *i2c) 104762306a36Sopenharmony_ci{ 104862306a36Sopenharmony_ci ktime_t timeout = ktime_add_ms(ktime_get(), WAIT_TIMEOUT); 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci while (READ_ONCE(i2c->busy) && 105162306a36Sopenharmony_ci ktime_compare(ktime_get(), timeout) < 0) { 105262306a36Sopenharmony_ci udelay(5); 105362306a36Sopenharmony_ci rk3x_i2c_irq(0, i2c); 105462306a36Sopenharmony_ci } 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci return !i2c->busy; 105762306a36Sopenharmony_ci} 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_cistatic int rk3x_i2c_xfer_common(struct i2c_adapter *adap, 106062306a36Sopenharmony_ci struct i2c_msg *msgs, int num, bool polling) 106162306a36Sopenharmony_ci{ 106262306a36Sopenharmony_ci struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data; 106362306a36Sopenharmony_ci unsigned long timeout, flags; 106462306a36Sopenharmony_ci u32 val; 106562306a36Sopenharmony_ci int ret = 0; 106662306a36Sopenharmony_ci int i; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci spin_lock_irqsave(&i2c->lock, flags); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci clk_enable(i2c->clk); 107162306a36Sopenharmony_ci clk_enable(i2c->pclk); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci i2c->is_last_msg = false; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci /* 107662306a36Sopenharmony_ci * Process msgs. We can handle more than one message at once (see 107762306a36Sopenharmony_ci * rk3x_i2c_setup()). 107862306a36Sopenharmony_ci */ 107962306a36Sopenharmony_ci for (i = 0; i < num; i += ret) { 108062306a36Sopenharmony_ci ret = rk3x_i2c_setup(i2c, msgs + i, num - i); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci if (ret < 0) { 108362306a36Sopenharmony_ci dev_err(i2c->dev, "rk3x_i2c_setup() failed\n"); 108462306a36Sopenharmony_ci break; 108562306a36Sopenharmony_ci } 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci if (i + ret >= num) 108862306a36Sopenharmony_ci i2c->is_last_msg = true; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci spin_unlock_irqrestore(&i2c->lock, flags); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci if (!polling) { 109362306a36Sopenharmony_ci rk3x_i2c_start(i2c); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci timeout = wait_event_timeout(i2c->wait, !i2c->busy, 109662306a36Sopenharmony_ci msecs_to_jiffies(WAIT_TIMEOUT)); 109762306a36Sopenharmony_ci } else { 109862306a36Sopenharmony_ci disable_irq(i2c->irq); 109962306a36Sopenharmony_ci rk3x_i2c_start(i2c); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci timeout = rk3x_i2c_wait_xfer_poll(i2c); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci enable_irq(i2c->irq); 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci spin_lock_irqsave(&i2c->lock, flags); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (timeout == 0) { 110962306a36Sopenharmony_ci dev_err(i2c->dev, "timeout, ipd: 0x%02x, state: %d\n", 111062306a36Sopenharmony_ci i2c_readl(i2c, REG_IPD), i2c->state); 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci /* Force a STOP condition without interrupt */ 111362306a36Sopenharmony_ci i2c_writel(i2c, 0, REG_IEN); 111462306a36Sopenharmony_ci val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; 111562306a36Sopenharmony_ci val |= REG_CON_EN | REG_CON_STOP; 111662306a36Sopenharmony_ci i2c_writel(i2c, val, REG_CON); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci i2c->state = STATE_IDLE; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci ret = -ETIMEDOUT; 112162306a36Sopenharmony_ci break; 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci if (i2c->error) { 112562306a36Sopenharmony_ci ret = i2c->error; 112662306a36Sopenharmony_ci break; 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci clk_disable(i2c->pclk); 113162306a36Sopenharmony_ci clk_disable(i2c->clk); 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci spin_unlock_irqrestore(&i2c->lock, flags); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci return ret < 0 ? ret : num; 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cistatic int rk3x_i2c_xfer(struct i2c_adapter *adap, 113962306a36Sopenharmony_ci struct i2c_msg *msgs, int num) 114062306a36Sopenharmony_ci{ 114162306a36Sopenharmony_ci return rk3x_i2c_xfer_common(adap, msgs, num, false); 114262306a36Sopenharmony_ci} 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_cistatic int rk3x_i2c_xfer_polling(struct i2c_adapter *adap, 114562306a36Sopenharmony_ci struct i2c_msg *msgs, int num) 114662306a36Sopenharmony_ci{ 114762306a36Sopenharmony_ci return rk3x_i2c_xfer_common(adap, msgs, num, true); 114862306a36Sopenharmony_ci} 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_cistatic __maybe_unused int rk3x_i2c_resume(struct device *dev) 115162306a36Sopenharmony_ci{ 115262306a36Sopenharmony_ci struct rk3x_i2c *i2c = dev_get_drvdata(dev); 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci rk3x_i2c_adapt_div(i2c, clk_get_rate(i2c->clk)); 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci return 0; 115762306a36Sopenharmony_ci} 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_cistatic u32 rk3x_i2c_func(struct i2c_adapter *adap) 116062306a36Sopenharmony_ci{ 116162306a36Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING; 116262306a36Sopenharmony_ci} 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_cistatic const struct i2c_algorithm rk3x_i2c_algorithm = { 116562306a36Sopenharmony_ci .master_xfer = rk3x_i2c_xfer, 116662306a36Sopenharmony_ci .master_xfer_atomic = rk3x_i2c_xfer_polling, 116762306a36Sopenharmony_ci .functionality = rk3x_i2c_func, 116862306a36Sopenharmony_ci}; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_cistatic const struct rk3x_i2c_soc_data rv1108_soc_data = { 117162306a36Sopenharmony_ci .grf_offset = -1, 117262306a36Sopenharmony_ci .calc_timings = rk3x_i2c_v1_calc_timings, 117362306a36Sopenharmony_ci}; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_cistatic const struct rk3x_i2c_soc_data rv1126_soc_data = { 117662306a36Sopenharmony_ci .grf_offset = 0x118, 117762306a36Sopenharmony_ci .calc_timings = rk3x_i2c_v1_calc_timings, 117862306a36Sopenharmony_ci}; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_cistatic const struct rk3x_i2c_soc_data rk3066_soc_data = { 118162306a36Sopenharmony_ci .grf_offset = 0x154, 118262306a36Sopenharmony_ci .calc_timings = rk3x_i2c_v0_calc_timings, 118362306a36Sopenharmony_ci}; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_cistatic const struct rk3x_i2c_soc_data rk3188_soc_data = { 118662306a36Sopenharmony_ci .grf_offset = 0x0a4, 118762306a36Sopenharmony_ci .calc_timings = rk3x_i2c_v0_calc_timings, 118862306a36Sopenharmony_ci}; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_cistatic const struct rk3x_i2c_soc_data rk3228_soc_data = { 119162306a36Sopenharmony_ci .grf_offset = -1, 119262306a36Sopenharmony_ci .calc_timings = rk3x_i2c_v0_calc_timings, 119362306a36Sopenharmony_ci}; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_cistatic const struct rk3x_i2c_soc_data rk3288_soc_data = { 119662306a36Sopenharmony_ci .grf_offset = -1, 119762306a36Sopenharmony_ci .calc_timings = rk3x_i2c_v0_calc_timings, 119862306a36Sopenharmony_ci}; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_cistatic const struct rk3x_i2c_soc_data rk3399_soc_data = { 120162306a36Sopenharmony_ci .grf_offset = -1, 120262306a36Sopenharmony_ci .calc_timings = rk3x_i2c_v1_calc_timings, 120362306a36Sopenharmony_ci}; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_cistatic const struct of_device_id rk3x_i2c_match[] = { 120662306a36Sopenharmony_ci { 120762306a36Sopenharmony_ci .compatible = "rockchip,rv1108-i2c", 120862306a36Sopenharmony_ci .data = &rv1108_soc_data 120962306a36Sopenharmony_ci }, 121062306a36Sopenharmony_ci { 121162306a36Sopenharmony_ci .compatible = "rockchip,rv1126-i2c", 121262306a36Sopenharmony_ci .data = &rv1126_soc_data 121362306a36Sopenharmony_ci }, 121462306a36Sopenharmony_ci { 121562306a36Sopenharmony_ci .compatible = "rockchip,rk3066-i2c", 121662306a36Sopenharmony_ci .data = &rk3066_soc_data 121762306a36Sopenharmony_ci }, 121862306a36Sopenharmony_ci { 121962306a36Sopenharmony_ci .compatible = "rockchip,rk3188-i2c", 122062306a36Sopenharmony_ci .data = &rk3188_soc_data 122162306a36Sopenharmony_ci }, 122262306a36Sopenharmony_ci { 122362306a36Sopenharmony_ci .compatible = "rockchip,rk3228-i2c", 122462306a36Sopenharmony_ci .data = &rk3228_soc_data 122562306a36Sopenharmony_ci }, 122662306a36Sopenharmony_ci { 122762306a36Sopenharmony_ci .compatible = "rockchip,rk3288-i2c", 122862306a36Sopenharmony_ci .data = &rk3288_soc_data 122962306a36Sopenharmony_ci }, 123062306a36Sopenharmony_ci { 123162306a36Sopenharmony_ci .compatible = "rockchip,rk3399-i2c", 123262306a36Sopenharmony_ci .data = &rk3399_soc_data 123362306a36Sopenharmony_ci }, 123462306a36Sopenharmony_ci {}, 123562306a36Sopenharmony_ci}; 123662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rk3x_i2c_match); 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_cistatic int rk3x_i2c_probe(struct platform_device *pdev) 123962306a36Sopenharmony_ci{ 124062306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 124162306a36Sopenharmony_ci const struct of_device_id *match; 124262306a36Sopenharmony_ci struct rk3x_i2c *i2c; 124362306a36Sopenharmony_ci int ret = 0; 124462306a36Sopenharmony_ci int bus_nr; 124562306a36Sopenharmony_ci u32 value; 124662306a36Sopenharmony_ci int irq; 124762306a36Sopenharmony_ci unsigned long clk_rate; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci i2c = devm_kzalloc(&pdev->dev, sizeof(struct rk3x_i2c), GFP_KERNEL); 125062306a36Sopenharmony_ci if (!i2c) 125162306a36Sopenharmony_ci return -ENOMEM; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci match = of_match_node(rk3x_i2c_match, np); 125462306a36Sopenharmony_ci i2c->soc_data = match->data; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci /* use common interface to get I2C timing properties */ 125762306a36Sopenharmony_ci i2c_parse_fw_timings(&pdev->dev, &i2c->t, true); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci strscpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name)); 126062306a36Sopenharmony_ci i2c->adap.owner = THIS_MODULE; 126162306a36Sopenharmony_ci i2c->adap.algo = &rk3x_i2c_algorithm; 126262306a36Sopenharmony_ci i2c->adap.retries = 3; 126362306a36Sopenharmony_ci i2c->adap.dev.of_node = np; 126462306a36Sopenharmony_ci i2c->adap.algo_data = i2c; 126562306a36Sopenharmony_ci i2c->adap.dev.parent = &pdev->dev; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci i2c->dev = &pdev->dev; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci spin_lock_init(&i2c->lock); 127062306a36Sopenharmony_ci init_waitqueue_head(&i2c->wait); 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci i2c->regs = devm_platform_ioremap_resource(pdev, 0); 127362306a36Sopenharmony_ci if (IS_ERR(i2c->regs)) 127462306a36Sopenharmony_ci return PTR_ERR(i2c->regs); 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci /* Try to set the I2C adapter number from dt */ 127762306a36Sopenharmony_ci bus_nr = of_alias_get_id(np, "i2c"); 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci /* 128062306a36Sopenharmony_ci * Switch to new interface if the SoC also offers the old one. 128162306a36Sopenharmony_ci * The control bit is located in the GRF register space. 128262306a36Sopenharmony_ci */ 128362306a36Sopenharmony_ci if (i2c->soc_data->grf_offset >= 0) { 128462306a36Sopenharmony_ci struct regmap *grf; 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); 128762306a36Sopenharmony_ci if (IS_ERR(grf)) { 128862306a36Sopenharmony_ci dev_err(&pdev->dev, 128962306a36Sopenharmony_ci "rk3x-i2c needs 'rockchip,grf' property\n"); 129062306a36Sopenharmony_ci return PTR_ERR(grf); 129162306a36Sopenharmony_ci } 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci if (bus_nr < 0) { 129462306a36Sopenharmony_ci dev_err(&pdev->dev, "rk3x-i2c needs i2cX alias"); 129562306a36Sopenharmony_ci return -EINVAL; 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci /* rv1126 i2c2 uses non-sequential write mask 20, value 4 */ 129962306a36Sopenharmony_ci if (i2c->soc_data == &rv1126_soc_data && bus_nr == 2) 130062306a36Sopenharmony_ci value = BIT(20) | BIT(4); 130162306a36Sopenharmony_ci else 130262306a36Sopenharmony_ci /* 27+i: write mask, 11+i: value */ 130362306a36Sopenharmony_ci value = BIT(27 + bus_nr) | BIT(11 + bus_nr); 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci ret = regmap_write(grf, i2c->soc_data->grf_offset, value); 130662306a36Sopenharmony_ci if (ret != 0) { 130762306a36Sopenharmony_ci dev_err(i2c->dev, "Could not write to GRF: %d\n", ret); 130862306a36Sopenharmony_ci return ret; 130962306a36Sopenharmony_ci } 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci /* IRQ setup */ 131362306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 131462306a36Sopenharmony_ci if (irq < 0) 131562306a36Sopenharmony_ci return irq; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, rk3x_i2c_irq, 131862306a36Sopenharmony_ci 0, dev_name(&pdev->dev), i2c); 131962306a36Sopenharmony_ci if (ret < 0) { 132062306a36Sopenharmony_ci dev_err(&pdev->dev, "cannot request IRQ\n"); 132162306a36Sopenharmony_ci return ret; 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci i2c->irq = irq; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci platform_set_drvdata(pdev, i2c); 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) { 132962306a36Sopenharmony_ci /* Only one clock to use for bus clock and peripheral clock */ 133062306a36Sopenharmony_ci i2c->clk = devm_clk_get(&pdev->dev, NULL); 133162306a36Sopenharmony_ci i2c->pclk = i2c->clk; 133262306a36Sopenharmony_ci } else { 133362306a36Sopenharmony_ci i2c->clk = devm_clk_get(&pdev->dev, "i2c"); 133462306a36Sopenharmony_ci i2c->pclk = devm_clk_get(&pdev->dev, "pclk"); 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci if (IS_ERR(i2c->clk)) 133862306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(i2c->clk), 133962306a36Sopenharmony_ci "Can't get bus clk\n"); 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci if (IS_ERR(i2c->pclk)) 134262306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(i2c->pclk), 134362306a36Sopenharmony_ci "Can't get periph clk\n"); 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci ret = clk_prepare(i2c->clk); 134662306a36Sopenharmony_ci if (ret < 0) { 134762306a36Sopenharmony_ci dev_err(&pdev->dev, "Can't prepare bus clk: %d\n", ret); 134862306a36Sopenharmony_ci return ret; 134962306a36Sopenharmony_ci } 135062306a36Sopenharmony_ci ret = clk_prepare(i2c->pclk); 135162306a36Sopenharmony_ci if (ret < 0) { 135262306a36Sopenharmony_ci dev_err(&pdev->dev, "Can't prepare periph clock: %d\n", ret); 135362306a36Sopenharmony_ci goto err_clk; 135462306a36Sopenharmony_ci } 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb; 135762306a36Sopenharmony_ci ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb); 135862306a36Sopenharmony_ci if (ret != 0) { 135962306a36Sopenharmony_ci dev_err(&pdev->dev, "Unable to register clock notifier\n"); 136062306a36Sopenharmony_ci goto err_pclk; 136162306a36Sopenharmony_ci } 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci ret = clk_enable(i2c->clk); 136462306a36Sopenharmony_ci if (ret < 0) { 136562306a36Sopenharmony_ci dev_err(&pdev->dev, "Can't enable bus clk: %d\n", ret); 136662306a36Sopenharmony_ci goto err_clk_notifier; 136762306a36Sopenharmony_ci } 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci clk_rate = clk_get_rate(i2c->clk); 137062306a36Sopenharmony_ci rk3x_i2c_adapt_div(i2c, clk_rate); 137162306a36Sopenharmony_ci clk_disable(i2c->clk); 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci ret = i2c_add_adapter(&i2c->adap); 137462306a36Sopenharmony_ci if (ret < 0) 137562306a36Sopenharmony_ci goto err_clk_notifier; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci return 0; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_cierr_clk_notifier: 138062306a36Sopenharmony_ci clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb); 138162306a36Sopenharmony_cierr_pclk: 138262306a36Sopenharmony_ci clk_unprepare(i2c->pclk); 138362306a36Sopenharmony_cierr_clk: 138462306a36Sopenharmony_ci clk_unprepare(i2c->clk); 138562306a36Sopenharmony_ci return ret; 138662306a36Sopenharmony_ci} 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_cistatic void rk3x_i2c_remove(struct platform_device *pdev) 138962306a36Sopenharmony_ci{ 139062306a36Sopenharmony_ci struct rk3x_i2c *i2c = platform_get_drvdata(pdev); 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci i2c_del_adapter(&i2c->adap); 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb); 139562306a36Sopenharmony_ci clk_unprepare(i2c->pclk); 139662306a36Sopenharmony_ci clk_unprepare(i2c->clk); 139762306a36Sopenharmony_ci} 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(rk3x_i2c_pm_ops, NULL, rk3x_i2c_resume); 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_cistatic struct platform_driver rk3x_i2c_driver = { 140262306a36Sopenharmony_ci .probe = rk3x_i2c_probe, 140362306a36Sopenharmony_ci .remove_new = rk3x_i2c_remove, 140462306a36Sopenharmony_ci .driver = { 140562306a36Sopenharmony_ci .name = "rk3x-i2c", 140662306a36Sopenharmony_ci .of_match_table = rk3x_i2c_match, 140762306a36Sopenharmony_ci .pm = &rk3x_i2c_pm_ops, 140862306a36Sopenharmony_ci }, 140962306a36Sopenharmony_ci}; 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_cimodule_platform_driver(rk3x_i2c_driver); 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ciMODULE_DESCRIPTION("Rockchip RK3xxx I2C Bus driver"); 141462306a36Sopenharmony_ciMODULE_AUTHOR("Max Schwarz <max.schwarz@online.de>"); 141562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1416