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