377 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * I2C bus driver for Conexant Digicolor SoCs4 *5 * Author: Baruch Siach <baruch@tkos.co.il>6 *7 * Copyright (C) 2015 Paradox Innovation Ltd.8 */9 10#include <linux/clk.h>11#include <linux/completion.h>12#include <linux/delay.h>13#include <linux/i2c.h>14#include <linux/interrupt.h>15#include <linux/io.h>16#include <linux/kernel.h>17#include <linux/module.h>18#include <linux/of.h>19#include <linux/platform_device.h>20 21#define TIMEOUT_MS 10022 23#define II_CONTROL 0x024#define II_CONTROL_LOCAL_RESET BIT(0)25 26#define II_CLOCKTIME 0x127 28#define II_COMMAND 0x229#define II_CMD_START 130#define II_CMD_RESTART 231#define II_CMD_SEND_ACK 332#define II_CMD_GET_ACK 633#define II_CMD_GET_NOACK 734#define II_CMD_STOP 1035#define II_COMMAND_GO BIT(7)36#define II_COMMAND_COMPLETION_STATUS(r) (((r) >> 5) & 3)37#define II_CMD_STATUS_NORMAL 038#define II_CMD_STATUS_ACK_GOOD 139#define II_CMD_STATUS_ACK_BAD 240#define II_CMD_STATUS_ABORT 341 42#define II_DATA 0x343#define II_INTFLAG_CLEAR 0x844#define II_INTENABLE 0xa45 46struct dc_i2c {47 struct i2c_adapter adap;48 struct device *dev;49 void __iomem *regs;50 struct clk *clk;51 unsigned int frequency;52 53 struct i2c_msg *msg;54 unsigned int msgbuf_ptr;55 int last;56 spinlock_t lock;57 struct completion done;58 int state;59 int error;60};61 62enum {63 STATE_IDLE,64 STATE_START,65 STATE_ADDR,66 STATE_WRITE,67 STATE_READ,68 STATE_STOP,69};70 71static void dc_i2c_cmd(struct dc_i2c *i2c, u8 cmd)72{73 writeb_relaxed(cmd | II_COMMAND_GO, i2c->regs + II_COMMAND);74}75 76static u8 dc_i2c_addr_cmd(struct i2c_msg *msg)77{78 u8 addr = (msg->addr & 0x7f) << 1;79 80 if (msg->flags & I2C_M_RD)81 addr |= 1;82 83 return addr;84}85 86static void dc_i2c_data(struct dc_i2c *i2c, u8 data)87{88 writeb_relaxed(data, i2c->regs + II_DATA);89}90 91static void dc_i2c_write_byte(struct dc_i2c *i2c, u8 byte)92{93 dc_i2c_data(i2c, byte);94 dc_i2c_cmd(i2c, II_CMD_SEND_ACK);95}96 97static void dc_i2c_write_buf(struct dc_i2c *i2c)98{99 dc_i2c_write_byte(i2c, i2c->msg->buf[i2c->msgbuf_ptr++]);100}101 102static void dc_i2c_next_read(struct dc_i2c *i2c)103{104 bool last = (i2c->msgbuf_ptr + 1 == i2c->msg->len);105 106 dc_i2c_cmd(i2c, last ? II_CMD_GET_NOACK : II_CMD_GET_ACK);107}108 109static void dc_i2c_stop(struct dc_i2c *i2c)110{111 i2c->state = STATE_STOP;112 if (i2c->last)113 dc_i2c_cmd(i2c, II_CMD_STOP);114 else115 complete(&i2c->done);116}117 118static u8 dc_i2c_read_byte(struct dc_i2c *i2c)119{120 return readb_relaxed(i2c->regs + II_DATA);121}122 123static void dc_i2c_read_buf(struct dc_i2c *i2c)124{125 i2c->msg->buf[i2c->msgbuf_ptr++] = dc_i2c_read_byte(i2c);126 dc_i2c_next_read(i2c);127}128 129static void dc_i2c_set_irq(struct dc_i2c *i2c, int enable)130{131 if (enable)132 writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR);133 writeb_relaxed(!!enable, i2c->regs + II_INTENABLE);134}135 136static int dc_i2c_cmd_status(struct dc_i2c *i2c)137{138 u8 cmd = readb_relaxed(i2c->regs + II_COMMAND);139 140 return II_COMMAND_COMPLETION_STATUS(cmd);141}142 143static void dc_i2c_start_msg(struct dc_i2c *i2c, int first)144{145 struct i2c_msg *msg = i2c->msg;146 147 if (!(msg->flags & I2C_M_NOSTART)) {148 i2c->state = STATE_START;149 dc_i2c_cmd(i2c, first ? II_CMD_START : II_CMD_RESTART);150 } else if (msg->flags & I2C_M_RD) {151 i2c->state = STATE_READ;152 dc_i2c_next_read(i2c);153 } else {154 i2c->state = STATE_WRITE;155 dc_i2c_write_buf(i2c);156 }157}158 159static irqreturn_t dc_i2c_irq(int irq, void *dev_id)160{161 struct dc_i2c *i2c = dev_id;162 int cmd_status = dc_i2c_cmd_status(i2c);163 u8 addr_cmd;164 165 writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR);166 167 spin_lock(&i2c->lock);168 169 if (cmd_status == II_CMD_STATUS_ACK_BAD170 || cmd_status == II_CMD_STATUS_ABORT) {171 i2c->error = -EIO;172 complete(&i2c->done);173 goto out;174 }175 176 switch (i2c->state) {177 case STATE_START:178 addr_cmd = dc_i2c_addr_cmd(i2c->msg);179 dc_i2c_write_byte(i2c, addr_cmd);180 i2c->state = STATE_ADDR;181 break;182 case STATE_ADDR:183 if (i2c->msg->flags & I2C_M_RD) {184 dc_i2c_next_read(i2c);185 i2c->state = STATE_READ;186 break;187 }188 i2c->state = STATE_WRITE;189 fallthrough;190 case STATE_WRITE:191 if (i2c->msgbuf_ptr < i2c->msg->len)192 dc_i2c_write_buf(i2c);193 else194 dc_i2c_stop(i2c);195 break;196 case STATE_READ:197 if (i2c->msgbuf_ptr < i2c->msg->len)198 dc_i2c_read_buf(i2c);199 else200 dc_i2c_stop(i2c);201 break;202 case STATE_STOP:203 i2c->state = STATE_IDLE;204 complete(&i2c->done);205 break;206 }207 208out:209 spin_unlock(&i2c->lock);210 return IRQ_HANDLED;211}212 213static int dc_i2c_xfer_msg(struct dc_i2c *i2c, struct i2c_msg *msg, int first,214 int last)215{216 unsigned long time_left = msecs_to_jiffies(TIMEOUT_MS);217 unsigned long flags;218 219 spin_lock_irqsave(&i2c->lock, flags);220 i2c->msg = msg;221 i2c->msgbuf_ptr = 0;222 i2c->last = last;223 i2c->error = 0;224 225 reinit_completion(&i2c->done);226 dc_i2c_set_irq(i2c, 1);227 dc_i2c_start_msg(i2c, first);228 spin_unlock_irqrestore(&i2c->lock, flags);229 230 time_left = wait_for_completion_timeout(&i2c->done, time_left);231 dc_i2c_set_irq(i2c, 0);232 if (time_left == 0) {233 i2c->state = STATE_IDLE;234 return -ETIMEDOUT;235 }236 237 if (i2c->error)238 return i2c->error;239 240 return 0;241}242 243static int dc_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)244{245 struct dc_i2c *i2c = adap->algo_data;246 int i, ret;247 248 for (i = 0; i < num; i++) {249 ret = dc_i2c_xfer_msg(i2c, &msgs[i], i == 0, i == num - 1);250 if (ret)251 return ret;252 }253 254 return num;255}256 257static int dc_i2c_init_hw(struct dc_i2c *i2c)258{259 unsigned long clk_rate = clk_get_rate(i2c->clk);260 unsigned int clocktime;261 262 writeb_relaxed(II_CONTROL_LOCAL_RESET, i2c->regs + II_CONTROL);263 udelay(100);264 writeb_relaxed(0, i2c->regs + II_CONTROL);265 udelay(100);266 267 clocktime = DIV_ROUND_UP(clk_rate, 64 * i2c->frequency);268 if (clocktime < 1 || clocktime > 0xff) {269 dev_err(i2c->dev, "can't set bus speed of %u Hz\n",270 i2c->frequency);271 return -EINVAL;272 }273 writeb_relaxed(clocktime - 1, i2c->regs + II_CLOCKTIME);274 275 return 0;276}277 278static u32 dc_i2c_func(struct i2c_adapter *adap)279{280 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;281}282 283static const struct i2c_algorithm dc_i2c_algorithm = {284 .xfer = dc_i2c_xfer,285 .functionality = dc_i2c_func,286};287 288static int dc_i2c_probe(struct platform_device *pdev)289{290 struct device_node *np = pdev->dev.of_node;291 struct dc_i2c *i2c;292 int ret = 0, irq;293 294 i2c = devm_kzalloc(&pdev->dev, sizeof(struct dc_i2c), GFP_KERNEL);295 if (!i2c)296 return -ENOMEM;297 298 if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",299 &i2c->frequency))300 i2c->frequency = I2C_MAX_STANDARD_MODE_FREQ;301 302 i2c->dev = &pdev->dev;303 platform_set_drvdata(pdev, i2c);304 305 spin_lock_init(&i2c->lock);306 init_completion(&i2c->done);307 308 i2c->clk = devm_clk_get(&pdev->dev, NULL);309 if (IS_ERR(i2c->clk))310 return PTR_ERR(i2c->clk);311 312 i2c->regs = devm_platform_ioremap_resource(pdev, 0);313 if (IS_ERR(i2c->regs))314 return PTR_ERR(i2c->regs);315 316 irq = platform_get_irq(pdev, 0);317 if (irq < 0)318 return irq;319 320 ret = devm_request_irq(&pdev->dev, irq, dc_i2c_irq, 0,321 dev_name(&pdev->dev), i2c);322 if (ret < 0)323 return ret;324 325 strscpy(i2c->adap.name, "Conexant Digicolor I2C adapter",326 sizeof(i2c->adap.name));327 i2c->adap.owner = THIS_MODULE;328 i2c->adap.algo = &dc_i2c_algorithm;329 i2c->adap.dev.parent = &pdev->dev;330 i2c->adap.dev.of_node = np;331 i2c->adap.algo_data = i2c;332 333 ret = dc_i2c_init_hw(i2c);334 if (ret)335 return ret;336 337 ret = clk_prepare_enable(i2c->clk);338 if (ret < 0)339 return ret;340 341 ret = i2c_add_adapter(&i2c->adap);342 if (ret < 0) {343 clk_disable_unprepare(i2c->clk);344 return ret;345 }346 347 return 0;348}349 350static void dc_i2c_remove(struct platform_device *pdev)351{352 struct dc_i2c *i2c = platform_get_drvdata(pdev);353 354 i2c_del_adapter(&i2c->adap);355 clk_disable_unprepare(i2c->clk);356}357 358static const struct of_device_id dc_i2c_match[] = {359 { .compatible = "cnxt,cx92755-i2c" },360 { }361};362MODULE_DEVICE_TABLE(of, dc_i2c_match);363 364static struct platform_driver dc_i2c_driver = {365 .probe = dc_i2c_probe,366 .remove_new = dc_i2c_remove,367 .driver = {368 .name = "digicolor-i2c",369 .of_match_table = dc_i2c_match,370 },371};372module_platform_driver(dc_i2c_driver);373 374MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");375MODULE_DESCRIPTION("Conexant Digicolor I2C controller driver");376MODULE_LICENSE("GPL v2");377