brintos

brintos / linux-shallow public Read only

0
0
Text · 7.9 KiB · 3dc5a46 Raw
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