Lines Matching +full:sun8i +full:- +full:a23 +full:- +full:rsb
2 * RSB (Reduced Serial Bus) driver.
4 * Author: Chen-Yu Tsai <wens@csie.org>
10 * The RSB controller looks like an SMBus controller which only supports
13 * - it uses addresses set at runtime to address slaves. Runtime addresses
16 * - it adds a parity bit every 8bits of data and address for read and
18 * - only one read access is required to read a byte (instead of a write
20 * - there's no Ack bit after each read access
24 * AXP809, and AXP806 PMICs, and the AC100 audio codec, all from X-Powers.
27 * RSB section of Allwinner's A80 user manual, which can be found at
29 * https://github.com/allwinner-zh/documents/tree/master/A80
33 * This driver is based on i2c-sun6i-p2wi.c, the P2WI bus driver.
38 #include <linux/clk/clk-conf.h>
51 #include <linux/sunxi-rsb.h>
54 /* RSB registers */
63 #define RSB_CMD 0x2c /* RSB Command */
114 #define RSB_CTRL_NAME "sunxi-rsb"
141 const struct sunxi_rsb_driver *drv = to_sunxi_rsb_driver(dev->driver); in sunxi_rsb_device_probe()
145 if (!drv->probe) in sunxi_rsb_device_probe()
146 return -ENODEV; in sunxi_rsb_device_probe()
148 if (!rdev->irq) { in sunxi_rsb_device_probe()
149 int irq = -ENOENT; in sunxi_rsb_device_probe()
151 if (dev->of_node) in sunxi_rsb_device_probe()
152 irq = of_irq_get(dev->of_node, 0); in sunxi_rsb_device_probe()
154 if (irq == -EPROBE_DEFER) in sunxi_rsb_device_probe()
159 rdev->irq = irq; in sunxi_rsb_device_probe()
162 ret = of_clk_set_defaults(dev->of_node, false); in sunxi_rsb_device_probe()
166 return drv->probe(rdev); in sunxi_rsb_device_probe()
171 const struct sunxi_rsb_driver *drv = to_sunxi_rsb_driver(dev->driver); in sunxi_rsb_device_remove()
173 return drv->remove(to_sunxi_rsb_device(dev)); in sunxi_rsb_device_remove()
192 * sunxi_rsb_device_create() - allocate and add an RSB device
193 * @rsb: RSB controller
194 * @node: RSB slave device node
195 * @hwaddr: RSB slave hardware address
196 * @rtaddr: RSB slave runtime address
198 static struct sunxi_rsb_device *sunxi_rsb_device_create(struct sunxi_rsb *rsb, in sunxi_rsb_device_create() argument
206 return ERR_PTR(-ENOMEM); in sunxi_rsb_device_create()
208 rdev->rsb = rsb; in sunxi_rsb_device_create()
209 rdev->hwaddr = hwaddr; in sunxi_rsb_device_create()
210 rdev->rtaddr = rtaddr; in sunxi_rsb_device_create()
211 rdev->dev.bus = &sunxi_rsb_bus; in sunxi_rsb_device_create()
212 rdev->dev.parent = rsb->dev; in sunxi_rsb_device_create()
213 rdev->dev.of_node = node; in sunxi_rsb_device_create()
214 rdev->dev.release = sunxi_rsb_dev_release; in sunxi_rsb_device_create()
216 dev_set_name(&rdev->dev, "%s-%x", RSB_CTRL_NAME, hwaddr); in sunxi_rsb_device_create()
218 err = device_register(&rdev->dev); in sunxi_rsb_device_create()
220 dev_err(&rdev->dev, "Can't add %s, status %d\n", in sunxi_rsb_device_create()
221 dev_name(&rdev->dev), err); in sunxi_rsb_device_create()
225 dev_dbg(&rdev->dev, "device %s registered\n", dev_name(&rdev->dev)); in sunxi_rsb_device_create()
228 put_device(&rdev->dev); in sunxi_rsb_device_create()
234 * sunxi_rsb_device_unregister(): unregister an RSB device
239 device_unregister(&rdev->dev); in sunxi_rsb_device_unregister()
246 if (dev->bus == &sunxi_rsb_bus) in sunxi_rsb_remove_devices()
253 * sunxi_rsb_driver_register() - Register device driver with RSB core
254 * @rdrv: device driver to be associated with slave-device.
256 * This API will register the client driver with the RSB framework.
257 * It is typically called from the driver's module-init function.
261 rdrv->driver.bus = &sunxi_rsb_bus; in sunxi_rsb_driver_register()
262 return driver_register(&rdrv->driver); in sunxi_rsb_driver_register()
267 static int _sunxi_rsb_run_xfer(struct sunxi_rsb *rsb) in _sunxi_rsb_run_xfer() argument
269 if (readl(rsb->regs + RSB_CTRL) & RSB_CTRL_START_TRANS) { in _sunxi_rsb_run_xfer()
270 dev_dbg(rsb->dev, "RSB transfer still in progress\n"); in _sunxi_rsb_run_xfer()
271 return -EBUSY; in _sunxi_rsb_run_xfer()
274 reinit_completion(&rsb->complete); in _sunxi_rsb_run_xfer()
277 rsb->regs + RSB_INTE); in _sunxi_rsb_run_xfer()
279 rsb->regs + RSB_CTRL); in _sunxi_rsb_run_xfer()
281 if (!wait_for_completion_io_timeout(&rsb->complete, in _sunxi_rsb_run_xfer()
283 dev_dbg(rsb->dev, "RSB timeout\n"); in _sunxi_rsb_run_xfer()
286 writel(RSB_CTRL_ABORT_TRANS, rsb->regs + RSB_CTRL); in _sunxi_rsb_run_xfer()
289 writel(readl(rsb->regs + RSB_INTS), rsb->regs + RSB_INTS); in _sunxi_rsb_run_xfer()
291 return -ETIMEDOUT; in _sunxi_rsb_run_xfer()
294 if (rsb->status & RSB_INTS_LOAD_BSY) { in _sunxi_rsb_run_xfer()
295 dev_dbg(rsb->dev, "RSB busy\n"); in _sunxi_rsb_run_xfer()
296 return -EBUSY; in _sunxi_rsb_run_xfer()
299 if (rsb->status & RSB_INTS_TRANS_ERR) { in _sunxi_rsb_run_xfer()
300 if (rsb->status & RSB_INTS_TRANS_ERR_ACK) { in _sunxi_rsb_run_xfer()
301 dev_dbg(rsb->dev, "RSB slave nack\n"); in _sunxi_rsb_run_xfer()
302 return -EINVAL; in _sunxi_rsb_run_xfer()
305 if (rsb->status & RSB_INTS_TRANS_ERR_DATA) { in _sunxi_rsb_run_xfer()
306 dev_dbg(rsb->dev, "RSB transfer data error\n"); in _sunxi_rsb_run_xfer()
307 return -EIO; in _sunxi_rsb_run_xfer()
314 static int sunxi_rsb_read(struct sunxi_rsb *rsb, u8 rtaddr, u8 addr, in sunxi_rsb_read() argument
321 return -EINVAL; in sunxi_rsb_read()
334 dev_err(rsb->dev, "Invalid access width: %zd\n", len); in sunxi_rsb_read()
335 return -EINVAL; in sunxi_rsb_read()
338 mutex_lock(&rsb->lock); in sunxi_rsb_read()
340 writel(addr, rsb->regs + RSB_ADDR); in sunxi_rsb_read()
341 writel(RSB_DAR_RTA(rtaddr), rsb->regs + RSB_DAR); in sunxi_rsb_read()
342 writel(cmd, rsb->regs + RSB_CMD); in sunxi_rsb_read()
344 ret = _sunxi_rsb_run_xfer(rsb); in sunxi_rsb_read()
348 *buf = readl(rsb->regs + RSB_DATA) & GENMASK(len * 8 - 1, 0); in sunxi_rsb_read()
351 mutex_unlock(&rsb->lock); in sunxi_rsb_read()
356 static int sunxi_rsb_write(struct sunxi_rsb *rsb, u8 rtaddr, u8 addr, in sunxi_rsb_write() argument
363 return -EINVAL; in sunxi_rsb_write()
376 dev_err(rsb->dev, "Invalid access width: %zd\n", len); in sunxi_rsb_write()
377 return -EINVAL; in sunxi_rsb_write()
380 mutex_lock(&rsb->lock); in sunxi_rsb_write()
382 writel(addr, rsb->regs + RSB_ADDR); in sunxi_rsb_write()
383 writel(RSB_DAR_RTA(rtaddr), rsb->regs + RSB_DAR); in sunxi_rsb_write()
384 writel(*buf, rsb->regs + RSB_DATA); in sunxi_rsb_write()
385 writel(cmd, rsb->regs + RSB_CMD); in sunxi_rsb_write()
386 ret = _sunxi_rsb_run_xfer(rsb); in sunxi_rsb_write()
388 mutex_unlock(&rsb->lock); in sunxi_rsb_write()
393 /* RSB regmap functions */
403 struct sunxi_rsb_device *rdev = ctx->rdev; in regmap_sunxi_rsb_reg_read()
406 return -EINVAL; in regmap_sunxi_rsb_reg_read()
408 return sunxi_rsb_read(rdev->rsb, rdev->rtaddr, reg, val, ctx->size); in regmap_sunxi_rsb_reg_read()
415 struct sunxi_rsb_device *rdev = ctx->rdev; in regmap_sunxi_rsb_reg_write()
417 return sunxi_rsb_write(rdev->rsb, rdev->rtaddr, reg, &val, ctx->size); in regmap_sunxi_rsb_reg_write()
440 switch (config->val_bits) { in regmap_sunxi_rsb_init_ctx()
446 return ERR_PTR(-EINVAL); in regmap_sunxi_rsb_init_ctx()
451 return ERR_PTR(-ENOMEM); in regmap_sunxi_rsb_init_ctx()
453 ctx->rdev = rdev; in regmap_sunxi_rsb_init_ctx()
454 ctx->size = config->val_bits / 8; in regmap_sunxi_rsb_init_ctx()
469 return __devm_regmap_init(&rdev->dev, ®map_sunxi_rsb, ctx, config, in __devm_regmap_init_sunxi_rsb()
474 /* RSB controller driver functions */
477 struct sunxi_rsb *rsb = dev_id; in sunxi_rsb_irq() local
480 status = readl(rsb->regs + RSB_INTS); in sunxi_rsb_irq()
481 rsb->status = status; in sunxi_rsb_irq()
486 writel(status, rsb->regs + RSB_INTS); in sunxi_rsb_irq()
488 complete(&rsb->complete); in sunxi_rsb_irq()
493 static int sunxi_rsb_init_device_mode(struct sunxi_rsb *rsb) in sunxi_rsb_init_device_mode() argument
500 RSB_DMCR_MODE_REG | RSB_DMCR_DEV_ADDR, rsb->regs + RSB_DMCR); in sunxi_rsb_init_device_mode()
502 readl_poll_timeout(rsb->regs + RSB_DMCR, reg, in sunxi_rsb_init_device_mode()
505 ret = -ETIMEDOUT; in sunxi_rsb_init_device_mode()
508 writel(readl(rsb->regs + RSB_INTS), rsb->regs + RSB_INTS); in sunxi_rsb_init_device_mode()
520 * No designs with 2 RSB slave devices sharing identical hardware
525 * The hardware does not seem to support re-setting runtime addresses.
547 static int of_rsb_register_devices(struct sunxi_rsb *rsb) in of_rsb_register_devices() argument
549 struct device *dev = rsb->dev; in of_rsb_register_devices()
550 struct device_node *child, *np = dev->of_node; in of_rsb_register_devices()
556 return -EINVAL; in of_rsb_register_devices()
583 writel(RSB_CMD_STRA, rsb->regs + RSB_CMD); in of_rsb_register_devices()
585 rsb->regs + RSB_DAR); in of_rsb_register_devices()
588 ret = _sunxi_rsb_run_xfer(rsb); in of_rsb_register_devices()
608 rdev = sunxi_rsb_device_create(rsb, child, hwaddr, rtaddr); in of_rsb_register_devices()
618 { .compatible = "allwinner,sun8i-a23-rsb" },
625 struct device *dev = &pdev->dev; in sunxi_rsb_probe()
626 struct device_node *np = dev->of_node; in sunxi_rsb_probe()
628 struct sunxi_rsb *rsb; in sunxi_rsb_probe() local
634 of_property_read_u32(np, "clock-frequency", &clk_freq); in sunxi_rsb_probe()
637 "clock-frequency (%u Hz) is too high (max = 20MHz)\n", in sunxi_rsb_probe()
639 return -EINVAL; in sunxi_rsb_probe()
642 rsb = devm_kzalloc(dev, sizeof(*rsb), GFP_KERNEL); in sunxi_rsb_probe()
643 if (!rsb) in sunxi_rsb_probe()
644 return -ENOMEM; in sunxi_rsb_probe()
646 rsb->dev = dev; in sunxi_rsb_probe()
647 platform_set_drvdata(pdev, rsb); in sunxi_rsb_probe()
649 rsb->regs = devm_ioremap_resource(dev, r); in sunxi_rsb_probe()
650 if (IS_ERR(rsb->regs)) in sunxi_rsb_probe()
651 return PTR_ERR(rsb->regs); in sunxi_rsb_probe()
657 rsb->clk = devm_clk_get(dev, NULL); in sunxi_rsb_probe()
658 if (IS_ERR(rsb->clk)) { in sunxi_rsb_probe()
659 ret = PTR_ERR(rsb->clk); in sunxi_rsb_probe()
664 ret = clk_prepare_enable(rsb->clk); in sunxi_rsb_probe()
670 p_clk_freq = clk_get_rate(rsb->clk); in sunxi_rsb_probe()
672 rsb->rstc = devm_reset_control_get(dev, NULL); in sunxi_rsb_probe()
673 if (IS_ERR(rsb->rstc)) { in sunxi_rsb_probe()
674 ret = PTR_ERR(rsb->rstc); in sunxi_rsb_probe()
679 ret = reset_control_deassert(rsb->rstc); in sunxi_rsb_probe()
685 init_completion(&rsb->complete); in sunxi_rsb_probe()
686 mutex_init(&rsb->lock); in sunxi_rsb_probe()
689 writel(RSB_CTRL_SOFT_RST, rsb->regs + RSB_CTRL); in sunxi_rsb_probe()
690 readl_poll_timeout(rsb->regs + RSB_CTRL, reg, in sunxi_rsb_probe()
695 * Allwinner U-boot sources. in sunxi_rsb_probe()
710 dev_info(dev, "RSB running at %lu Hz\n", p_clk_freq / clk_div / 2); in sunxi_rsb_probe()
711 writel(RSB_CCR_SDA_OUT_DELAY(clk_delay) | RSB_CCR_CLK_DIV(clk_div - 1), in sunxi_rsb_probe()
712 rsb->regs + RSB_CCR); in sunxi_rsb_probe()
714 ret = devm_request_irq(dev, irq, sunxi_rsb_irq, 0, RSB_CTRL_NAME, rsb); in sunxi_rsb_probe()
721 /* initialize all devices on the bus into RSB mode */ in sunxi_rsb_probe()
722 ret = sunxi_rsb_init_device_mode(rsb); in sunxi_rsb_probe()
726 of_rsb_register_devices(rsb); in sunxi_rsb_probe()
731 reset_control_assert(rsb->rstc); in sunxi_rsb_probe()
734 clk_disable_unprepare(rsb->clk); in sunxi_rsb_probe()
741 struct sunxi_rsb *rsb = platform_get_drvdata(pdev); in sunxi_rsb_remove() local
743 device_for_each_child(rsb->dev, NULL, sunxi_rsb_remove_devices); in sunxi_rsb_remove()
744 reset_control_assert(rsb->rstc); in sunxi_rsb_remove()
745 clk_disable_unprepare(rsb->clk); in sunxi_rsb_remove()
780 MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");