// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Copyright (c) 2019 Amlogic, Inc. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // #include #include #include // #define I2C_DEBUG // #define I2C_PXP #define I2C_PM_RUNTIME #define FUTURE_USE 0 /* Meson I2C register map */ #define REG_CFG_RDY 0x00 #define REG_CFG_I2C 0x04 #define REG_CFG_START 0x08 #define REG_CFG_BUS 0x0c #define REG_TX_RD_ADDR 0x10 #define REG_TX_WR_ADDR 0x14 #define REG_RX_RD_ADDR 0x18 #define REG_RX_WR_ADDR 0x1c #define REG_CGF_TX 0x20 #define REG_CGF_RX 0x24 #define REG_CGF_IRQ_STATE 0x30 #define REG_CGF_IRQ_ENABLE 0x34 #define REG_SHAKE_BLK_CNT 0x38 //could check numbers of bytes send /* CFG RDY fields */ #define RDY_TEE_ONLY BIT(1) #define RDY_IF BIT(0) /* CFG I2C fields */ #define I2C_RX_THR GENMASK(23, 16) #define I2C_TX_THR GENMASK(15, 8) #define I2C_DMA BIT(4) #define I2C_HW_NEG BIT(3) #define I2C_HW_POS BIT(2) #define I2C_JOIN_RX BIT(1) #define I2C_JOIN_TX BIT(0) #define I2C_TX_THR_DIV 2 /* CFG BUS fields */ #define BUS_NO_STOP BIT(18)//after soc c5 support this bit. others invalid. #define BUS_SPEED_MODE BIT(17) #define BUS_SLAVE_MODE BIT(16) #define BUS_FILTER_MASK GENMASK(15, 12) /*SCL = clk/b_ratio if b_ratio<=8, SCL = clk/8 */ #define BUS_RATIO_MASK GENMASK(11, 0) /* CFG START fields */ #define START_STRAT BIT(31) #define START_LEN GENMASK(23, 12) #define START_LEN_SHIFT 12 #define START_10_BITS BIT(11) /*only 7bit now*/ #define START_SLAVE_ADDR GENMASK(10, 1) #define START_READ BIT(0) /* CFG TX_RX fields */ #define TX_RX_EMPTY BIT(9) #define TX_RX_FULL BIT(8) #define TX_RX_DATA GENMASK(7, 0) /* SHAKE_BLK_CNT fields */ #define BLK_CNT_MASK GENMASK(16, 4) #define BLK_CNT_SHIFTS 4 /*CGF IRQ fields */ #define RCH_ERROR BIT(0) #define WCH_ERROR BIT(1) #define NCK_ERROR BIT(2) #define RX_EMPTY BIT(3) #define TX_FULL BIT(4) #define RX_FIFO_READ BIT(5) #define TX_FIFO_WRITE BIT(6) #define PHY_DONE BIT(7) #define TRANS_ERROR (RCH_ERROR | WCH_ERROR | NCK_ERROR) #define TRANS_DONE (PHY_DONE | TRANS_ERROR) /* enable irq, critical trans done bit must be set. * tx/rx thresh bit used for continuously transfer, * set it manul when transfer. * TX_FULL RX_EMPTY not used. * NACK ERROR can not be use in gxlx4, it will cause down signal at scl after nack. */ #define ENABLE_IRQ_BIT (NCK_ERROR | RCH_ERROR | WCH_ERROR | PHY_DONE) //| RX_FIFO_READ | TX_FIFO_WRITE) /*A9 and new IRQ fields*/ #define A9_NCK_ERROR BIT(0) #define A9_RX_EMPTY BIT(1) #define A9_RX_FULL BIT(2) #define A9_TX_EMPTY BIT(3) #define A9_TX_FULL BIT(4) //#define A9_RX_FIFO_READ BIT(5) same as the old //#define A9_TX_FIFO_WRITE BIT(6) same as the old //#define A9_PHY_DONE BIT(7) same as the old #define A9_TASK_DONE BIT(8) #define A9_ALL_DONE BIT(9) #define A9_TRANS_DONE (PHY_DONE | A9_NCK_ERROR) #define A9_TRANS_ERROR (A9_NCK_ERROR) #define A9_ENABLE_IRQ_BIT (A9_NCK_ERROR | PHY_DONE) //if use thresh mode, should be set at start. #define THRESH_MODE (RX_FIFO_READ | TX_FIFO_WRITE) #define REG_FIFO_BASE 0x80 /* keep the same with I2C_TIMEOUT_MS */ #define MESON_I2C_PM_TIMEOUT 500 #define I2C_TIMEOUT_MS 500 #define MESON_I2C_PM_TIMEOUT 500 enum { STATE_IDLE, STATE_READ, STATE_WRITE, STATE_WAIT, }; struct meson_i2c_data { bool tee; u32 tee_id; u32 enable_irq_bits; u32 xfer_done_bits; u32 xfer_err_bits; }; /** * struct meson_i2c - Meson I2C device private data * * @adap: I2C adapter instance * @dev: Pointer to device structure * @regs: Base address of the device memory mapped registers * @clk: Pointer to clock structure * @msg: Pointer to the current I2C message * @state: Current state in the driver state machine * @count: Number of bytes to be sent/received in current transfer * @last: The last msg flag * @pos: Current position in the send/receive buffer * @error: Flag set when an error is received * @lock: To avoid race conditions between irq handler and xfer code * @done: Completion used to wait for transfer termination * @frequency: Operating frequency of I2C bus clock * @data: Pointer to the controller's platform data *@mode: I2C's transfer mode irq or polling */ struct meson_i2c { struct i2c_adapter adap; struct device *dev; void __iomem *regs; struct clk *clk; struct i2c_msg *msg; int state; int count; int pos; bool last; int error; int fifo_depth; spinlock_t lock; //protection for i2c controller critical section struct completion done; #ifdef CONFIG_AMLOGIC_MODIFY unsigned long clk_rate; unsigned int frequency; int retain_fastmode; int irq; bool is_runtime_sleep; #endif struct meson_i2c_data *data; int mode; }; static void meson_i2c_writel(struct meson_i2c *i2c, u32 data, int reg) { #if FUTURE_USE struct arm_smccc_res res; if (i2c->data->tee) arm_smccc_smc(SECURE_PWM_I2C, SECID_I2C, i2c->data->tee_id, reg, data, 0, 0, 0, &res); else #endif writel(data, i2c->regs + reg); } static inline void meson_i2c_dump_reg(struct meson_i2c *i2c, const char *func, int line) { #ifdef I2C_DEBUG u32 data; int i; trace_printk("%s %s, line:%d\n", dev_name(i2c->dev), func, line); for (i = 0 ; i < 8; i++) { data = readl(i2c->regs + i * 4); trace_printk("%s i2c reg%x : 0x%x\n", dev_name(i2c->dev), i, data); } for (i = 0xb ; i < 0xf; i++) { data = readl(i2c->regs + i * 4); trace_printk("%s i2c reg%x : 0x%x\n", dev_name(i2c->dev), i, data); } #endif } static void meson_i2c_set_mask(struct meson_i2c *i2c, int reg, u32 mask, u32 val) { u32 data; data = readl(i2c->regs + reg); data &= ~mask; data |= val & mask; meson_i2c_writel(i2c, data, reg); } /* * SCL = clk/b_ratio. if b_ratio<=8, SCL = clk/8 */ static void meson_i2c_set_clk_div(struct meson_i2c *i2c) { unsigned long clk_rate = i2c->clk_rate; unsigned int div; div = DIV_ROUND_UP(clk_rate, i2c->frequency); /* clock divider has 12 bits */ if (div >= (1 << 12)) dev_err(i2c->dev, "requested bus frequency too low\n"); else if (div <= 8) dev_err(i2c->dev, "requested bus frequency too high\n"); #ifdef I2C_PXP div = 0x40; #endif /* CFG_BUS reg:11 - 0 bits * BUS_SPEED_MODE for HW timming */ meson_i2c_set_mask(i2c, REG_CFG_BUS, BUS_RATIO_MASK | BUS_SPEED_MODE, div | BUS_SPEED_MODE); #ifdef I2C_DEBUG trace_printk("%s %s: clk %lu, freq %u, div %u\n", dev_name(i2c->dev), __func__, clk_rate, i2c->frequency, div); #endif } static void reset_fifo_pos(struct meson_i2c *i2c) { meson_i2c_writel(i2c, 0x00, REG_TX_RD_ADDR); meson_i2c_writel(i2c, 0x00, REG_TX_WR_ADDR); /* Must reset rx_wr_addr before rx_rd_addr for continues read. * Because reset rd will pull data to fifo, so we need reset wr early. * And then, data will be push rightly to 1st fifo position. */ meson_i2c_writel(i2c, 0x00, REG_RX_WR_ADDR); meson_i2c_writel(i2c, 0x00, REG_RX_RD_ADDR); } static int controller_is_error(struct meson_i2c *i2c) { int ret = 0; if (readl(i2c->regs + REG_CGF_IRQ_STATE) & i2c->data->xfer_err_bits) { #ifdef I2C_DEBUG trace_printk("%s i2c controller error: 0x%x\n", dev_name(i2c->dev), readl(i2c->regs + REG_CGF_IRQ_STATE)); #endif ret = -ENXIO; } return ret; } static int controller_is_done(struct meson_i2c *i2c) { return readl(i2c->regs + REG_CGF_IRQ_STATE) & i2c->data->xfer_done_bits; } static void clear_irq_status(struct meson_i2c *i2c, u32 irq_bits) { meson_i2c_writel(i2c, irq_bits, REG_CGF_IRQ_STATE); } static int wait_controller_done(struct meson_i2c *i2c) { u32 time_cnt = 0; int ret = 0; while (!controller_is_done(i2c)) { if (time_cnt > I2C_TIMEOUT_MS * 1000) return -ETIMEDOUT; udelay(1); time_cnt++; } ret = controller_is_error(i2c); return ret; } static int get_tx_count(struct meson_i2c *i2c) { int rd_val; rd_val = (readl(i2c->regs + REG_SHAKE_BLK_CNT) & BLK_CNT_MASK) >> BLK_CNT_SHIFTS; return rd_val; } static int wait_tx_done(struct meson_i2c *i2c, u32 des_count) { u32 time_cnt = 0; int ret = 0; while (get_tx_count(i2c) != des_count) { if (time_cnt > I2C_TIMEOUT_MS * 1000) return -ETIMEDOUT; udelay(1); time_cnt++; ret = controller_is_error(i2c); if (ret) return ret; } return ret; } static void meson_i2c_init(struct meson_i2c *i2c) { meson_i2c_set_mask(i2c, REG_CFG_BUS, BUS_FILTER_MASK, 1 << 12); clear_irq_status(i2c, 0xffff);//clear all irq meson_i2c_writel(i2c, i2c->data->enable_irq_bits, REG_CGF_IRQ_ENABLE); meson_i2c_set_mask(i2c, REG_CFG_BUS, BUS_FILTER_MASK | BUS_NO_STOP, 1 << 12 | BUS_NO_STOP); /* set rx thresh, when fifo has data and fifo full will generate irq for cpu read. * set tx thresh, when fifo empty will generate irq for continue transfer. * set fifo depth and should clear dma mode avoid tcon driver set DMA, * because TCON driver will OP i2c DMA in there driver. */ i2c->fifo_depth = 16; meson_i2c_set_mask(i2c, REG_CFG_I2C, I2C_DMA | I2C_RX_THR | I2C_TX_THR, i2c->fifo_depth << 16 | (i2c->fifo_depth / I2C_TX_THR_DIV) << 8); reset_fifo_pos(i2c); meson_i2c_set_clk_div(i2c); } static void meson_i2c_add_stop(struct meson_i2c *i2c) { meson_i2c_set_mask(i2c, REG_CFG_BUS, BUS_NO_STOP, 0); } static void meson_i2c_push_data_to_user(struct meson_i2c *i2c, u8 data) { u8 *buf = i2c->msg->buf + i2c->pos; i2c->count = 1; *buf = data; #ifdef I2C_DEBUG trace_printk("%s %s: data %08x\n", dev_name(i2c->dev), __func__, *buf); #endif } static void meson_i2c_put_data(struct meson_i2c *i2c, char *buf, int len) { if (!i2c->msg->len) {//this i2c module when trans 0 byte, must put at least 1. meson_i2c_writel(i2c, 0x00, REG_CGF_TX); return; } for (int i = 0; i < len; i++, buf++) { meson_i2c_writel(i2c, *buf, REG_CGF_TX); #ifdef I2C_DEBUG trace_printk("%s %s: data %08x\n", dev_name(i2c->dev), __func__, *buf); #endif } } static void meson_i2c_prepare_xfer(struct meson_i2c *i2c, bool full_fill) { bool write = !(i2c->msg->flags & I2C_M_RD); if (write) { if (i2c->mode == I2C_POLLING_MODE || full_fill) i2c->count = min(i2c->msg->len - i2c->pos, i2c->fifo_depth); else i2c->count = min(i2c->msg->len - i2c->pos, i2c->fifo_depth / I2C_TX_THR_DIV); meson_i2c_put_data(i2c, i2c->msg->buf + i2c->pos, i2c->count); } } /* three case should be check in irq: * 1.trans done * 2.RX thresh(fifo full) ------> pull data * 3.TX thresh(fifo empty) ------>push data to fifo * */ static irqreturn_t meson_i2c_irq(int irqno, void *dev_id) { struct meson_i2c *i2c = dev_id; int ret; u32 rd_len, i; u32 rd_val; spin_lock(&i2c->lock); ret = controller_is_error(i2c); if (ret) { #ifdef I2C_DEBUG trace_printk("%s IRQ controller error\n", dev_name(i2c->dev)); #endif i2c->error = ret; goto complete_irq_out; } switch (i2c->state) { case STATE_READ: meson_i2c_dump_reg(i2c, __func__, __LINE__); rd_len = min(i2c->msg->len - i2c->pos, i2c->fifo_depth); #ifdef I2C_DEBUG trace_printk("%s thresh for rx rd-len:%d\n", dev_name(i2c->dev), rd_len); #endif for (i = 0; i < rd_len; i++) { rd_val = readl(i2c->regs + REG_CGF_RX); #ifdef I2C_DEBUG trace_printk("%s thresh for rx RX reg value:0x%x\n", dev_name(i2c->dev), rd_val); #endif meson_i2c_push_data_to_user(i2c, rd_val & TX_RX_DATA); i2c->pos += i2c->count; } clear_irq_status(i2c, RX_FIFO_READ);//rx must clear thresh after read fifo break; case STATE_WRITE: #ifdef I2C_DEBUG trace_printk("%s thresh for tx\n", dev_name(i2c->dev)); #endif meson_i2c_dump_reg(i2c, __func__, __LINE__); meson_i2c_prepare_xfer(i2c, false); if ((i2c->pos + i2c->fifo_depth / I2C_TX_THR_DIV) >= i2c->msg->len) meson_i2c_set_mask(i2c, REG_CGF_IRQ_ENABLE, TX_FIFO_WRITE, 0); clear_irq_status(i2c, TX_FIFO_WRITE);//tx must clear thresh after write fifo i2c->pos += i2c->count; break; case STATE_IDLE: dev_warn(i2c->dev, "i2c irq triggered abnormally!!!, irq_state:0x%x,irq_en:0x%x\n", readl(i2c->regs + REG_CGF_IRQ_STATE), readl(i2c->regs + REG_CGF_IRQ_ENABLE)); break; default: break; } //check controller done? if (!controller_is_done(i2c)) { goto irq_trans_out; } else { #ifdef I2C_DEBUG trace_printk("%s i2c irq controller_is_done\n", dev_name(i2c->dev)); #endif if (i2c->state == STATE_READ && (i2c->msg->len - i2c->pos)) {//read not complete #ifdef I2C_DEBUG trace_printk("%s i2c irq done but read not complete\n", dev_name(i2c->dev)); #endif goto irq_trans_out; } } complete_irq_out: reset_fifo_pos(i2c); complete(&i2c->done); i2c->state = STATE_IDLE; meson_i2c_set_mask(i2c, REG_CGF_IRQ_ENABLE, RX_FIFO_READ | TX_FIFO_WRITE, 0);//disable TX/RX irq bits clear_irq_status(i2c, 0xffff);//clear all irq irq_trans_out: #ifdef I2C_DEBUG trace_printk("%s IRQ out\n", dev_name(i2c->dev)); #endif meson_i2c_dump_reg(i2c, __func__, __LINE__); spin_unlock(&i2c->lock); return IRQ_HANDLED; } static void meson_i2c_do_start(struct meson_i2c *i2c, struct i2c_msg *msg) { unsigned int reg_val; unsigned int trans_len; trans_len = msg->len; if (i2c->mode == I2C_POLLING_MODE) { //if TX and not last xfer, need add no stop if (!(msg->flags & I2C_M_RD) && !i2c->last && msg->len) trans_len = msg->len + 1; } reg_val = (msg->addr << 1) | ((msg->flags & I2C_M_RD) ? START_READ : 0) | ((trans_len) << 12) | START_STRAT; meson_i2c_set_mask(i2c, REG_CFG_START, START_STRAT | START_SLAVE_ADDR | START_READ | START_LEN, reg_val); //NACK irq will be clear validly only after start signal clear_irq_status(i2c, 0xffff);//clear all irq if (trans_len > i2c->fifo_depth) { reg_val = (msg->flags & I2C_M_RD) ? RX_FIFO_READ : TX_FIFO_WRITE; meson_i2c_set_mask(i2c, REG_CGF_IRQ_ENABLE, RX_FIFO_READ | TX_FIFO_WRITE, reg_val);//enable thresh mode } meson_i2c_dump_reg(i2c, __func__, __LINE__); } static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg, bool last) { unsigned long time_left, flags; int ret = 0; i2c->msg = msg; i2c->pos = 0; i2c->count = 0; i2c->error = 0; i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; meson_i2c_prepare_xfer(i2c, true); i2c->pos += i2c->count;//every prepare data pushed, should increase pos. reinit_completion(&i2c->done); if (last) meson_i2c_add_stop(i2c); /* Start the transfer */ meson_i2c_do_start(i2c, msg); time_left = msecs_to_jiffies(I2C_TIMEOUT_MS); time_left = wait_for_completion_timeout(&i2c->done, time_left); /* * Protect access to i2c struct and registers from interrupt * handlers triggered by a transfer terminated after the * timeout period */ spin_lock_irqsave(&i2c->lock, flags); if (!time_left) { /*to do. maybe reset i2c for stop*/ i2c->state = STATE_IDLE; ret = -ETIMEDOUT; } if (i2c->error) ret = i2c->error; spin_unlock_irqrestore(&i2c->lock, flags); return ret; } static int meson_i2c_no_stop(struct meson_i2c *i2c) { int ret = 0; int trans_cnt; u32 time_cnt = 0; //check data trans done while (true) { trans_cnt = (readl(i2c->regs + REG_SHAKE_BLK_CNT) & BLK_CNT_MASK) >> BLK_CNT_SHIFTS; if (trans_cnt >= i2c->msg->len) break; /*time out*/ if (time_cnt > I2C_TIMEOUT_MS * 1000) { ret = -ETIMEDOUT; goto no_stop_out; } udelay(1); time_cnt++; } udelay(20);//must delay controller idle pinctrl_pm_select_sleep_state(i2c->dev);//release SDA/SCL line meson_i2c_writel(i2c, i2c->msg->len << START_LEN_SHIFT, REG_CFG_START);//stop controller meson_i2c_writel(i2c, 0xaf, REG_CGF_TX);//write visual xfer //wait trans done ret = wait_controller_done(i2c); no_stop_out: reset_fifo_pos(i2c); pinctrl_pm_select_default_state(i2c->dev); return ret; } static int meson_i2c_xfer_polling_msg(struct meson_i2c *i2c, struct i2c_msg *msg, bool last) { int rd_val, time_cnt, ret = 0; i2c->msg = msg; i2c->pos = 0; i2c->count = 0; i2c->last = last; meson_i2c_do_start(i2c, msg); do { if (msg->flags & I2C_M_RD) {//for rx time_cnt = 0; do { rd_val = readl(i2c->regs + REG_CGF_RX); if (time_cnt > I2C_TIMEOUT_MS * 1000) { ret = -ETIMEDOUT; goto xfer_out; } udelay(1); time_cnt++; ret = controller_is_error(i2c); if (ret) goto xfer_out; } while (rd_val & TX_RX_EMPTY);//waiting data meson_i2c_push_data_to_user(i2c, rd_val & TX_RX_DATA); } else { //for tx meson_i2c_prepare_xfer(i2c, true); ret = wait_tx_done(i2c, i2c->pos + i2c->count); if (ret) goto xfer_out; } i2c->pos += i2c->count; } while (i2c->pos < msg->len); //if TX and not last xfer, need add no stop if (!(msg->flags & I2C_M_RD) && !i2c->last && msg->len) { ret = meson_i2c_no_stop(i2c); if (ret) goto xfer_out; } else { //wait trans done ret = wait_controller_done(i2c); if (ret) goto xfer_out; } xfer_out: clear_irq_status(i2c, 0xffff);//clear all irq reset_fifo_pos(i2c); return ret; } static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct meson_i2c *i2c = adap->algo_data; int i, ret = 0; #ifdef I2C_PM_RUNTIME ret = pm_runtime_get_sync(i2c->dev); if (ret < 0) goto out; #endif meson_i2c_init(i2c);//must init i2c in every xfer for (i = 0; i < num; i++) { if (i2c->mode == I2C_POLLING_MODE) ret = meson_i2c_xfer_polling_msg(i2c, msgs + i, i == num - 1); else ret = meson_i2c_xfer_msg(i2c, msgs + i, i == num - 1); if (ret) break; } #ifdef I2C_PM_RUNTIME out: pm_runtime_mark_last_busy(i2c->dev); pm_runtime_put_autosuspend(i2c->dev); #endif return ret ?: i; } static u32 meson_i2c_func(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } static const struct i2c_algorithm meson_i2c_algorithm = { .master_xfer = meson_i2c_xfer, .functionality = meson_i2c_func, }; static ssize_t speed_show(struct device *child, struct device_attribute *attr, char *buf) { struct meson_i2c *i2c = (struct meson_i2c *)dev_get_drvdata(child); return sprintf(buf, "%d\n", i2c->frequency); } static ssize_t speed_store(struct device *child, struct device_attribute *attr, const char *buf, size_t size) { struct meson_i2c *i2c = (struct meson_i2c *)dev_get_drvdata(child); int ret, val; ret = kstrtouint(buf, 0, &val); if (ret) return ret; i2c->frequency = val; meson_i2c_set_clk_div(i2c); return size; } static DEVICE_ATTR_RW(speed); static int meson_i2c_speed_debug(struct device *dev) { return sysfs_create_file(&dev->kobj, &dev_attr_speed.attr); } static int meson_i2c_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct meson_i2c *i2c; struct i2c_timings timings; int irq, ret; i2c = devm_kzalloc(&pdev->dev, sizeof(struct meson_i2c), GFP_KERNEL); if (!i2c) return -ENOMEM; i2c_parse_fw_timings(&pdev->dev, &timings, true); i2c->frequency = timings.bus_freq_hz; i2c->data = (struct meson_i2c_data *)of_device_get_match_data(&pdev->dev); i2c->dev = &pdev->dev; platform_set_drvdata(pdev, i2c); spin_lock_init(&i2c->lock); init_completion(&i2c->done); i2c->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(i2c->clk)) { dev_err(&pdev->dev, "can't get device clock\n"); return PTR_ERR(i2c->clk); } i2c->clk_rate = clk_get_rate(i2c->clk); if (i2c->clk_rate == 0) { dev_err(&pdev->dev, "failed to get clk rate\n"); return -EINVAL; } i2c->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(i2c->regs)) return PTR_ERR(i2c->regs); if (i2c->data->tee) { /* get i2c tee_id property */ ret = of_property_read_u32(pdev->dev.of_node, "tee_id", &i2c->data->tee_id); if (ret) { dev_err(&pdev->dev, "not config tee_id\n"); return ret; } } /* init i2c before req irq, avoid it's old states trigger irq. * and must init i2c after get clock rate, because it will set speed. */ meson_i2c_init(i2c); if (of_property_read_u32(pdev->dev.of_node, "working_mode", &i2c->mode)) { i2c->mode = I2C_IRQ_MODE; irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "can't find IRQ\n"); return irq; } ret = devm_request_irq(&pdev->dev, irq, meson_i2c_irq, 0, NULL, i2c); if (ret < 0) { dev_err(&pdev->dev, "can't request IRQ\n"); return ret; } i2c->irq = irq; #ifdef I2C_PM_RUNTIME /* Disable the interrupt so that the system can enter low-power mode */ disable_irq(i2c->irq); #endif } strscpy(i2c->adap.name, "Meson I2C V2 adapter", sizeof(i2c->adap.name)); i2c->adap.owner = THIS_MODULE; i2c->adap.algo = &meson_i2c_algorithm; i2c->adap.dev.parent = &pdev->dev; i2c->adap.dev.of_node = np; i2c->adap.algo_data = i2c; #ifdef I2C_PM_RUNTIME pm_runtime_enable(i2c->dev); pm_runtime_set_autosuspend_delay(i2c->dev, MESON_I2C_PM_TIMEOUT); pm_runtime_use_autosuspend(i2c->dev); ret = pm_runtime_get_sync(i2c->dev); if (ret < 0) { pm_runtime_put_noidle(i2c->dev); pm_runtime_disable(i2c->dev); return ret; } #endif /* speed sysfs */ ret = meson_i2c_speed_debug(&pdev->dev); if (ret) dev_err(&pdev->dev, "Creat i2c speed debug sysfs failed\n"); #ifdef I2C_PM_RUNTIME pm_runtime_mark_last_busy(i2c->dev); pm_runtime_put_autosuspend(i2c->dev); #endif ret = i2c_add_adapter(&i2c->adap); if (ret < 0) return ret; return 0; } static void meson_i2c_remove(struct platform_device *pdev) { struct meson_i2c *i2c = platform_get_drvdata(pdev); #ifdef I2C_PM_RUNTIME int ret; ret = pm_runtime_get_sync(&pdev->dev); if (ret < 0) return; #endif i2c_del_adapter(&i2c->adap); #ifdef I2C_PM_RUNTIME pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); #endif } static int meson_i2c_put(struct meson_i2c *i2c) { if (i2c->mode == I2C_IRQ_MODE) disable_irq(i2c->irq); pinctrl_pm_select_sleep_state(i2c->dev); clk_disable_unprepare(i2c->clk); return 0; } static int meson_i2c_regain(struct meson_i2c *i2c) { int ret; ret = clk_prepare_enable(i2c->clk); if (ret < 0) { dev_err(i2c->dev, "can not enable clock\n"); return ret; } pinctrl_pm_select_default_state(i2c->dev); if (i2c->mode == I2C_IRQ_MODE) enable_irq(i2c->irq); return 0; } #ifdef CONFIG_HIBERNATION static int meson_i2c_freeze(struct device *dev) { int ret; struct meson_i2c *i2c = (struct meson_i2c *)dev_get_drvdata(dev); if (i2c->is_runtime_sleep) return 0; ret = meson_i2c_put(i2c); return ret; } static int meson_i2c_thaw(struct device *dev) { return 0; } static int meson_i2c_restore(struct device *dev) { int ret; struct meson_i2c *i2c = (struct meson_i2c *)dev_get_drvdata(dev); if (i2c->is_runtime_sleep) return 0; ret = meson_i2c_regain(i2c); return ret; } #endif #ifdef CONFIG_AMLOGIC_MODIFY static int __maybe_unused meson_i2c_runtime_suspend(struct device *dev) { int ret; struct meson_i2c *i2c = (struct meson_i2c *)dev_get_drvdata(dev); ret = meson_i2c_put(i2c); i2c->is_runtime_sleep = true; return ret; } static int __maybe_unused meson_i2c_runtime_resume(struct device *dev) { int ret; struct meson_i2c *i2c = (struct meson_i2c *)dev_get_drvdata(dev); ret = meson_i2c_regain(i2c); i2c->is_runtime_sleep = false; return ret; } static const struct dev_pm_ops meson_i2c_pm_ops = { SET_RUNTIME_PM_OPS(meson_i2c_runtime_suspend, meson_i2c_runtime_resume, NULL) #ifdef CONFIG_HIBERNATION .freeze = meson_i2c_freeze, .thaw = meson_i2c_thaw, .restore = meson_i2c_restore, #endif }; #endif static struct meson_i2c_data i2c_tee_data = { .tee = true, .enable_irq_bits = ENABLE_IRQ_BIT, .xfer_done_bits = TRANS_DONE, .xfer_err_bits = TRANS_ERROR, }; static struct meson_i2c_data i2c_normal_data = { .tee = false, .enable_irq_bits = ENABLE_IRQ_BIT, .xfer_done_bits = TRANS_DONE, .xfer_err_bits = TRANS_ERROR, }; static struct meson_i2c_data i2c_normal_a9 = { .tee = false, .enable_irq_bits = A9_ENABLE_IRQ_BIT, .xfer_done_bits = A9_TRANS_DONE, .xfer_err_bits = A9_TRANS_ERROR, }; static const struct of_device_id meson_i2c_v2_match[] = { { .compatible = "amlogic,meson-i2c-v2", .data = &i2c_normal_data }, { .compatible = "amlogic,meson-tee-i2c-v2", .data = &i2c_tee_data }, { .compatible = "amlogic,meson-i2c-v2-1", .data = &i2c_normal_a9 }, {}, }; MODULE_DEVICE_TABLE(of, meson_i2c_v2_match); static struct platform_driver meson_i2c_driver = { .probe = meson_i2c_probe, .remove = meson_i2c_remove, .driver = { .name = "meson-i2c-v2", .pm = &meson_i2c_pm_ops, .of_match_table = meson_i2c_v2_match, }, }; int __init i2c_meson_v2_init(void) { return platform_driver_register(&meson_i2c_driver); } void __exit i2c_meson_v2_exit(void) { platform_driver_unregister(&meson_i2c_driver); } MODULE_DESCRIPTION("Amlogic Meson I2C V2 Bus driver"); MODULE_AUTHOR("Junyi Zhao "); MODULE_LICENSE("GPL v2");