brintos

brintos / linux-shallow public Read only

0
0
Text · 8.4 KiB · 074eade Raw
333 lines · c
1/*2 * P2WI (Push-Pull Two Wire Interface) bus driver.3 *4 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>5 *6 * This file is licensed under the terms of the GNU General Public License7 * version 2.  This program is licensed "as is" without any warranty of any8 * kind, whether express or implied.9 *10 * The P2WI controller looks like an SMBus controller which only supports byte11 * data transfers. But, it differs from standard SMBus protocol on several12 * aspects:13 * - it supports only one target device, and thus drop the address field14 * - it adds a parity bit every 8bits of data15 * - only one read access is required to read a byte (instead of a write16 *   followed by a read access in standard SMBus protocol)17 * - there's no Ack bit after each byte transfer18 *19 * This means this bus cannot be used to interface with standard SMBus20 * devices (the only known device to support this interface is the AXP22121 * PMIC).22 *23 */24#include <linux/clk.h>25#include <linux/i2c.h>26#include <linux/io.h>27#include <linux/interrupt.h>28#include <linux/module.h>29#include <linux/of.h>30#include <linux/platform_device.h>31#include <linux/reset.h>32 33 34/* P2WI registers */35#define P2WI_CTRL		0x036#define P2WI_CCR		0x437#define P2WI_INTE		0x838#define P2WI_INTS		0xc39#define P2WI_DADDR0		0x1040#define P2WI_DADDR1		0x1441#define P2WI_DLEN		0x1842#define P2WI_DATA0		0x1c43#define P2WI_DATA1		0x2044#define P2WI_LCR		0x2445#define P2WI_PMCR		0x2846 47/* CTRL fields */48#define P2WI_CTRL_START_TRANS		BIT(7)49#define P2WI_CTRL_ABORT_TRANS		BIT(6)50#define P2WI_CTRL_GLOBAL_INT_ENB	BIT(1)51#define P2WI_CTRL_SOFT_RST		BIT(0)52 53/* CLK CTRL fields */54#define P2WI_CCR_SDA_OUT_DELAY(v)	(((v) & 0x7) << 8)55#define P2WI_CCR_MAX_CLK_DIV		0xff56#define P2WI_CCR_CLK_DIV(v)		((v) & P2WI_CCR_MAX_CLK_DIV)57 58/* STATUS fields */59#define P2WI_INTS_TRANS_ERR_ID(v)	(((v) >> 8) & 0xff)60#define P2WI_INTS_LOAD_BSY		BIT(2)61#define P2WI_INTS_TRANS_ERR		BIT(1)62#define P2WI_INTS_TRANS_OVER		BIT(0)63 64/* DATA LENGTH fields*/65#define P2WI_DLEN_READ			BIT(4)66#define P2WI_DLEN_DATA_LENGTH(v)	((v - 1) & 0x7)67 68/* LINE CTRL fields*/69#define P2WI_LCR_SCL_STATE		BIT(5)70#define P2WI_LCR_SDA_STATE		BIT(4)71#define P2WI_LCR_SCL_CTL		BIT(3)72#define P2WI_LCR_SCL_CTL_EN		BIT(2)73#define P2WI_LCR_SDA_CTL		BIT(1)74#define P2WI_LCR_SDA_CTL_EN		BIT(0)75 76/* PMU MODE CTRL fields */77#define P2WI_PMCR_PMU_INIT_SEND		BIT(31)78#define P2WI_PMCR_PMU_INIT_DATA(v)	(((v) & 0xff) << 16)79#define P2WI_PMCR_PMU_MODE_REG(v)	(((v) & 0xff) << 8)80#define P2WI_PMCR_PMU_DEV_ADDR(v)	((v) & 0xff)81 82#define P2WI_MAX_FREQ			600000083 84struct p2wi {85	struct i2c_adapter adapter;86	struct completion complete;87	unsigned int status;88	void __iomem *regs;89	struct clk *clk;90	struct reset_control *rstc;91	int target_addr;92};93 94static irqreturn_t p2wi_interrupt(int irq, void *dev_id)95{96	struct p2wi *p2wi = dev_id;97	unsigned long status;98 99	status = readl(p2wi->regs + P2WI_INTS);100	p2wi->status = status;101 102	/* Clear interrupts */103	status &= (P2WI_INTS_LOAD_BSY | P2WI_INTS_TRANS_ERR |104		   P2WI_INTS_TRANS_OVER);105	writel(status, p2wi->regs + P2WI_INTS);106 107	complete(&p2wi->complete);108 109	return IRQ_HANDLED;110}111 112static u32 p2wi_functionality(struct i2c_adapter *adap)113{114	return I2C_FUNC_SMBUS_BYTE_DATA;115}116 117static int p2wi_smbus_xfer(struct i2c_adapter *adap, u16 addr,118			   unsigned short flags, char read_write,119			   u8 command, int size, union i2c_smbus_data *data)120{121	struct p2wi *p2wi = i2c_get_adapdata(adap);122	unsigned long dlen = P2WI_DLEN_DATA_LENGTH(1);123 124	if (p2wi->target_addr >= 0 && addr != p2wi->target_addr) {125		dev_err(&adap->dev, "invalid P2WI address\n");126		return -EINVAL;127	}128 129	if (!data)130		return -EINVAL;131 132	writel(command, p2wi->regs + P2WI_DADDR0);133 134	if (read_write == I2C_SMBUS_READ)135		dlen |= P2WI_DLEN_READ;136	else137		writel(data->byte, p2wi->regs + P2WI_DATA0);138 139	writel(dlen, p2wi->regs + P2WI_DLEN);140 141	if (readl(p2wi->regs + P2WI_CTRL) & P2WI_CTRL_START_TRANS) {142		dev_err(&adap->dev, "P2WI bus busy\n");143		return -EBUSY;144	}145 146	reinit_completion(&p2wi->complete);147 148	writel(P2WI_INTS_LOAD_BSY | P2WI_INTS_TRANS_ERR | P2WI_INTS_TRANS_OVER,149	       p2wi->regs + P2WI_INTE);150 151	writel(P2WI_CTRL_START_TRANS | P2WI_CTRL_GLOBAL_INT_ENB,152	       p2wi->regs + P2WI_CTRL);153 154	wait_for_completion(&p2wi->complete);155 156	if (p2wi->status & P2WI_INTS_LOAD_BSY) {157		dev_err(&adap->dev, "P2WI bus busy\n");158		return -EBUSY;159	}160 161	if (p2wi->status & P2WI_INTS_TRANS_ERR) {162		dev_err(&adap->dev, "P2WI bus xfer error\n");163		return -ENXIO;164	}165 166	if (read_write == I2C_SMBUS_READ)167		data->byte = readl(p2wi->regs + P2WI_DATA0);168 169	return 0;170}171 172static const struct i2c_algorithm p2wi_algo = {173	.smbus_xfer = p2wi_smbus_xfer,174	.functionality = p2wi_functionality,175};176 177static const struct of_device_id p2wi_of_match_table[] = {178	{ .compatible = "allwinner,sun6i-a31-p2wi" },179	{}180};181MODULE_DEVICE_TABLE(of, p2wi_of_match_table);182 183static int p2wi_probe(struct platform_device *pdev)184{185	struct device *dev = &pdev->dev;186	struct device_node *np = dev->of_node;187	struct device_node *childnp;188	unsigned long parent_clk_freq;189	u32 clk_freq = I2C_MAX_STANDARD_MODE_FREQ;190	struct p2wi *p2wi;191	u32 target_addr;192	int clk_div;193	int irq;194	int ret;195 196	of_property_read_u32(np, "clock-frequency", &clk_freq);197	if (clk_freq > P2WI_MAX_FREQ) {198		dev_err(dev,199			"required clock-frequency (%u Hz) is too high (max = 6MHz)",200			clk_freq);201		return -EINVAL;202	}203 204	if (clk_freq == 0) {205		dev_err(dev, "clock-frequency is set to 0 in DT\n");206		return -EINVAL;207	}208 209	if (of_get_child_count(np) > 1) {210		dev_err(dev, "P2WI only supports one target device\n");211		return -EINVAL;212	}213 214	p2wi = devm_kzalloc(dev, sizeof(struct p2wi), GFP_KERNEL);215	if (!p2wi)216		return -ENOMEM;217 218	p2wi->target_addr = -1;219 220	/*221	 * Authorize a p2wi node without any children to be able to use an222	 * i2c-dev from userpace.223	 * In this case the target_addr is set to -1 and won't be checked when224	 * launching a P2WI transfer.225	 */226	childnp = of_get_next_available_child(np, NULL);227	if (childnp) {228		ret = of_property_read_u32(childnp, "reg", &target_addr);229		if (ret) {230			dev_err(dev, "invalid target address on node %pOF\n",231				childnp);232			return -EINVAL;233		}234 235		p2wi->target_addr = target_addr;236	}237 238	p2wi->regs = devm_platform_ioremap_resource(pdev, 0);239	if (IS_ERR(p2wi->regs))240		return PTR_ERR(p2wi->regs);241 242	strscpy(p2wi->adapter.name, pdev->name, sizeof(p2wi->adapter.name));243	irq = platform_get_irq(pdev, 0);244	if (irq < 0)245		return irq;246 247	p2wi->clk = devm_clk_get_enabled(dev, NULL);248	if (IS_ERR(p2wi->clk)) {249		ret = PTR_ERR(p2wi->clk);250		dev_err(dev, "failed to enable clk: %d\n", ret);251		return ret;252	}253 254	parent_clk_freq = clk_get_rate(p2wi->clk);255 256	p2wi->rstc = devm_reset_control_get_exclusive(dev, NULL);257	if (IS_ERR(p2wi->rstc)) {258		dev_err(dev, "failed to retrieve reset controller: %pe\n",259			p2wi->rstc);260		return PTR_ERR(p2wi->rstc);261	}262 263	ret = reset_control_deassert(p2wi->rstc);264	if (ret) {265		dev_err(dev, "failed to deassert reset line: %d\n", ret);266		return ret;267	}268 269	init_completion(&p2wi->complete);270	p2wi->adapter.dev.parent = dev;271	p2wi->adapter.algo = &p2wi_algo;272	p2wi->adapter.owner = THIS_MODULE;273	p2wi->adapter.dev.of_node = pdev->dev.of_node;274	platform_set_drvdata(pdev, p2wi);275	i2c_set_adapdata(&p2wi->adapter, p2wi);276 277	ret = devm_request_irq(dev, irq, p2wi_interrupt, 0, pdev->name, p2wi);278	if (ret) {279		dev_err(dev, "can't register interrupt handler irq%d: %d\n",280			irq, ret);281		goto err_reset_assert;282	}283 284	writel(P2WI_CTRL_SOFT_RST, p2wi->regs + P2WI_CTRL);285 286	clk_div = parent_clk_freq / clk_freq;287	if (!clk_div) {288		dev_warn(dev,289			 "clock-frequency is too high, setting it to %lu Hz\n",290			 parent_clk_freq);291		clk_div = 1;292	} else if (clk_div > P2WI_CCR_MAX_CLK_DIV) {293		dev_warn(dev,294			 "clock-frequency is too low, setting it to %lu Hz\n",295			 parent_clk_freq / P2WI_CCR_MAX_CLK_DIV);296		clk_div = P2WI_CCR_MAX_CLK_DIV;297	}298 299	writel(P2WI_CCR_SDA_OUT_DELAY(1) | P2WI_CCR_CLK_DIV(clk_div),300	       p2wi->regs + P2WI_CCR);301 302	ret = i2c_add_adapter(&p2wi->adapter);303	if (!ret)304		return 0;305 306err_reset_assert:307	reset_control_assert(p2wi->rstc);308 309	return ret;310}311 312static void p2wi_remove(struct platform_device *dev)313{314	struct p2wi *p2wi = platform_get_drvdata(dev);315 316	reset_control_assert(p2wi->rstc);317	i2c_del_adapter(&p2wi->adapter);318}319 320static struct platform_driver p2wi_driver = {321	.probe	= p2wi_probe,322	.remove_new = p2wi_remove,323	.driver	= {324		.name = "i2c-sunxi-p2wi",325		.of_match_table = p2wi_of_match_table,326	},327};328module_platform_driver(p2wi_driver);329 330MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");331MODULE_DESCRIPTION("Allwinner P2WI driver");332MODULE_LICENSE("GPL v2");333