Lines Matching +full:primary +full:- +full:pmic
1 // SPDX-License-Identifier: GPL-2.0-only
5 * Author: Chen-Yu Tsai <wens@csie.org>
10 * - it uses addresses set at runtime to address slaves. Runtime addresses
13 * - it adds a parity bit every 8bits of data and address for read and
15 * - only one read access is required to read a byte (instead of a write
17 * - there's no Ack bit after each read access
21 * AXP809, and AXP806 PMICs, and the AC100 audio codec, all from X-Powers.
26 * https://github.com/allwinner-zh/documents/tree/master/A80
30 * This driver is based on i2c-sun6i-p2wi.c, the P2WI bus driver.
34 #include <linux/clk/clk-conf.h>
49 #include <linux/sunxi-rsb.h>
112 #define RSB_CTRL_NAME "sunxi-rsb"
140 const struct sunxi_rsb_driver *drv = to_sunxi_rsb_driver(dev->driver); in sunxi_rsb_device_probe()
144 if (!drv->probe) in sunxi_rsb_device_probe()
145 return -ENODEV; in sunxi_rsb_device_probe()
147 if (!rdev->irq) { in sunxi_rsb_device_probe()
148 int irq = -ENOENT; in sunxi_rsb_device_probe()
150 if (dev->of_node) in sunxi_rsb_device_probe()
151 irq = of_irq_get(dev->of_node, 0); in sunxi_rsb_device_probe()
153 if (irq == -EPROBE_DEFER) in sunxi_rsb_device_probe()
158 rdev->irq = irq; in sunxi_rsb_device_probe()
161 ret = of_clk_set_defaults(dev->of_node, false); in sunxi_rsb_device_probe()
165 return drv->probe(rdev); in sunxi_rsb_device_probe()
170 const struct sunxi_rsb_driver *drv = to_sunxi_rsb_driver(dev->driver); in sunxi_rsb_device_remove()
172 drv->remove(to_sunxi_rsb_device(dev)); in sunxi_rsb_device_remove()
196 * sunxi_rsb_device_create() - allocate and add an RSB device
210 return ERR_PTR(-ENOMEM); in sunxi_rsb_device_create()
212 rdev->rsb = rsb; in sunxi_rsb_device_create()
213 rdev->hwaddr = hwaddr; in sunxi_rsb_device_create()
214 rdev->rtaddr = rtaddr; in sunxi_rsb_device_create()
215 rdev->dev.bus = &sunxi_rsb_bus; in sunxi_rsb_device_create()
216 rdev->dev.parent = rsb->dev; in sunxi_rsb_device_create()
217 rdev->dev.of_node = node; in sunxi_rsb_device_create()
218 rdev->dev.release = sunxi_rsb_dev_release; in sunxi_rsb_device_create()
220 dev_set_name(&rdev->dev, "%s-%x", RSB_CTRL_NAME, hwaddr); in sunxi_rsb_device_create()
222 err = device_register(&rdev->dev); in sunxi_rsb_device_create()
224 dev_err(&rdev->dev, "Can't add %s, status %d\n", in sunxi_rsb_device_create()
225 dev_name(&rdev->dev), err); in sunxi_rsb_device_create()
229 dev_dbg(&rdev->dev, "device %s registered\n", dev_name(&rdev->dev)); in sunxi_rsb_device_create()
234 put_device(&rdev->dev); in sunxi_rsb_device_create()
245 device_unregister(&rdev->dev); in sunxi_rsb_device_unregister()
252 if (dev->bus == &sunxi_rsb_bus) in sunxi_rsb_remove_devices()
259 * sunxi_rsb_driver_register() - Register device driver with RSB core
260 * @rdrv: device driver to be associated with slave-device.
263 * It is typically called from the driver's module-init function.
267 rdrv->driver.bus = &sunxi_rsb_bus; in sunxi_rsb_driver_register()
268 return driver_register(&rdrv->driver); in sunxi_rsb_driver_register()
278 if (readl(rsb->regs + RSB_CTRL) & RSB_CTRL_START_TRANS) { in _sunxi_rsb_run_xfer()
279 dev_dbg(rsb->dev, "RSB transfer still in progress\n"); in _sunxi_rsb_run_xfer()
280 return -EBUSY; in _sunxi_rsb_run_xfer()
283 reinit_completion(&rsb->complete); in _sunxi_rsb_run_xfer()
286 writel(int_mask, rsb->regs + RSB_INTE); in _sunxi_rsb_run_xfer()
288 rsb->regs + RSB_CTRL); in _sunxi_rsb_run_xfer()
291 timeout = readl_poll_timeout_atomic(rsb->regs + RSB_INTS, in _sunxi_rsb_run_xfer()
294 writel(status, rsb->regs + RSB_INTS); in _sunxi_rsb_run_xfer()
296 timeout = !wait_for_completion_io_timeout(&rsb->complete, in _sunxi_rsb_run_xfer()
298 status = rsb->status; in _sunxi_rsb_run_xfer()
302 dev_dbg(rsb->dev, "RSB timeout\n"); in _sunxi_rsb_run_xfer()
305 writel(RSB_CTRL_ABORT_TRANS, rsb->regs + RSB_CTRL); in _sunxi_rsb_run_xfer()
308 writel(readl(rsb->regs + RSB_INTS), rsb->regs + RSB_INTS); in _sunxi_rsb_run_xfer()
310 return -ETIMEDOUT; in _sunxi_rsb_run_xfer()
314 dev_dbg(rsb->dev, "RSB busy\n"); in _sunxi_rsb_run_xfer()
315 return -EBUSY; in _sunxi_rsb_run_xfer()
320 dev_dbg(rsb->dev, "RSB slave nack\n"); in _sunxi_rsb_run_xfer()
321 return -EINVAL; in _sunxi_rsb_run_xfer()
325 dev_dbg(rsb->dev, "RSB transfer data error\n"); in _sunxi_rsb_run_xfer()
326 return -EIO; in _sunxi_rsb_run_xfer()
340 return -EINVAL; in sunxi_rsb_read()
353 dev_err(rsb->dev, "Invalid access width: %zd\n", len); in sunxi_rsb_read()
354 return -EINVAL; in sunxi_rsb_read()
357 ret = pm_runtime_resume_and_get(rsb->dev); in sunxi_rsb_read()
361 mutex_lock(&rsb->lock); in sunxi_rsb_read()
363 writel(addr, rsb->regs + RSB_ADDR); in sunxi_rsb_read()
364 writel(RSB_DAR_RTA(rtaddr), rsb->regs + RSB_DAR); in sunxi_rsb_read()
365 writel(cmd, rsb->regs + RSB_CMD); in sunxi_rsb_read()
371 *buf = readl(rsb->regs + RSB_DATA) & GENMASK(len * 8 - 1, 0); in sunxi_rsb_read()
374 mutex_unlock(&rsb->lock); in sunxi_rsb_read()
376 pm_runtime_mark_last_busy(rsb->dev); in sunxi_rsb_read()
377 pm_runtime_put_autosuspend(rsb->dev); in sunxi_rsb_read()
389 return -EINVAL; in sunxi_rsb_write()
402 dev_err(rsb->dev, "Invalid access width: %zd\n", len); in sunxi_rsb_write()
403 return -EINVAL; in sunxi_rsb_write()
406 ret = pm_runtime_resume_and_get(rsb->dev); in sunxi_rsb_write()
410 mutex_lock(&rsb->lock); in sunxi_rsb_write()
412 writel(addr, rsb->regs + RSB_ADDR); in sunxi_rsb_write()
413 writel(RSB_DAR_RTA(rtaddr), rsb->regs + RSB_DAR); in sunxi_rsb_write()
414 writel(*buf, rsb->regs + RSB_DATA); in sunxi_rsb_write()
415 writel(cmd, rsb->regs + RSB_CMD); in sunxi_rsb_write()
418 mutex_unlock(&rsb->lock); in sunxi_rsb_write()
420 pm_runtime_mark_last_busy(rsb->dev); in sunxi_rsb_write()
421 pm_runtime_put_autosuspend(rsb->dev); in sunxi_rsb_write()
436 struct sunxi_rsb_device *rdev = ctx->rdev; in regmap_sunxi_rsb_reg_read()
439 return -EINVAL; in regmap_sunxi_rsb_reg_read()
441 return sunxi_rsb_read(rdev->rsb, rdev->rtaddr, reg, val, ctx->size); in regmap_sunxi_rsb_reg_read()
448 struct sunxi_rsb_device *rdev = ctx->rdev; in regmap_sunxi_rsb_reg_write()
450 return sunxi_rsb_write(rdev->rsb, rdev->rtaddr, reg, &val, ctx->size); in regmap_sunxi_rsb_reg_write()
473 switch (config->val_bits) { in regmap_sunxi_rsb_init_ctx()
479 return ERR_PTR(-EINVAL); in regmap_sunxi_rsb_init_ctx()
484 return ERR_PTR(-ENOMEM); in regmap_sunxi_rsb_init_ctx()
486 ctx->rdev = rdev; in regmap_sunxi_rsb_init_ctx()
487 ctx->size = config->val_bits / 8; in regmap_sunxi_rsb_init_ctx()
502 return __devm_regmap_init(&rdev->dev, ®map_sunxi_rsb, ctx, config, in __devm_regmap_init_sunxi_rsb()
513 status = readl(rsb->regs + RSB_INTS); in sunxi_rsb_irq()
514 rsb->status = status; in sunxi_rsb_irq()
519 writel(status, rsb->regs + RSB_INTS); in sunxi_rsb_irq()
521 complete(&rsb->complete); in sunxi_rsb_irq()
533 RSB_DMCR_MODE_REG | RSB_DMCR_DEV_ADDR, rsb->regs + RSB_DMCR); in sunxi_rsb_init_device_mode()
535 readl_poll_timeout(rsb->regs + RSB_DMCR, reg, in sunxi_rsb_init_device_mode()
538 ret = -ETIMEDOUT; in sunxi_rsb_init_device_mode()
541 writel(readl(rsb->regs + RSB_INTS), rsb->regs + RSB_INTS); in sunxi_rsb_init_device_mode()
555 * use 0x2d for the primary PMIC, 0x3a for the secondary PMIC if
558 * The hardware does not seem to support re-setting runtime addresses.
564 { 0x3a3, 0x2d }, /* Primary PMIC: AXP223, AXP809, AXP81X, ... */
565 { 0x745, 0x3a }, /* Secondary PMIC: AXP806, ... */
582 struct device *dev = rsb->dev; in of_rsb_register_devices()
583 struct device_node *child, *np = dev->of_node; in of_rsb_register_devices()
589 return -EINVAL; in of_rsb_register_devices()
616 writel(RSB_CMD_STRA, rsb->regs + RSB_CMD); in of_rsb_register_devices()
618 rsb->regs + RSB_DAR); in of_rsb_register_devices()
652 struct device *dev = rsb->dev; in sunxi_rsb_hw_init()
657 ret = clk_prepare_enable(rsb->clk); in sunxi_rsb_hw_init()
663 ret = reset_control_deassert(rsb->rstc); in sunxi_rsb_hw_init()
670 writel(RSB_CTRL_SOFT_RST, rsb->regs + RSB_CTRL); in sunxi_rsb_hw_init()
671 readl_poll_timeout(rsb->regs + RSB_CTRL, reg, in sunxi_rsb_hw_init()
676 * Allwinner U-boot sources. in sunxi_rsb_hw_init()
681 p_clk_freq = clk_get_rate(rsb->clk); in sunxi_rsb_hw_init()
682 clk_div = p_clk_freq / rsb->clk_freq / 2; in sunxi_rsb_hw_init()
693 writel(RSB_CCR_SDA_OUT_DELAY(clk_delay) | RSB_CCR_CLK_DIV(clk_div - 1), in sunxi_rsb_hw_init()
694 rsb->regs + RSB_CCR); in sunxi_rsb_hw_init()
699 clk_disable_unprepare(rsb->clk); in sunxi_rsb_hw_init()
706 reset_control_assert(rsb->rstc); in sunxi_rsb_hw_exit()
709 if (!pm_runtime_status_suspended(rsb->dev)) in sunxi_rsb_hw_exit()
710 clk_disable_unprepare(rsb->clk); in sunxi_rsb_hw_exit()
717 clk_disable_unprepare(rsb->clk); in sunxi_rsb_runtime_suspend()
726 return clk_prepare_enable(rsb->clk); in sunxi_rsb_runtime_resume()
747 struct device *dev = &pdev->dev; in sunxi_rsb_probe()
748 struct device_node *np = dev->of_node; in sunxi_rsb_probe()
753 of_property_read_u32(np, "clock-frequency", &clk_freq); in sunxi_rsb_probe()
755 return dev_err_probe(dev, -EINVAL, in sunxi_rsb_probe()
756 "clock-frequency (%u Hz) is too high (max = 20MHz)\n", in sunxi_rsb_probe()
761 return -ENOMEM; in sunxi_rsb_probe()
763 rsb->dev = dev; in sunxi_rsb_probe()
764 rsb->clk_freq = clk_freq; in sunxi_rsb_probe()
766 rsb->regs = devm_platform_ioremap_resource(pdev, 0); in sunxi_rsb_probe()
767 if (IS_ERR(rsb->regs)) in sunxi_rsb_probe()
768 return PTR_ERR(rsb->regs); in sunxi_rsb_probe()
774 rsb->clk = devm_clk_get(dev, NULL); in sunxi_rsb_probe()
775 if (IS_ERR(rsb->clk)) in sunxi_rsb_probe()
776 return dev_err_probe(dev, PTR_ERR(rsb->clk), in sunxi_rsb_probe()
779 rsb->rstc = devm_reset_control_get(dev, NULL); in sunxi_rsb_probe()
780 if (IS_ERR(rsb->rstc)) in sunxi_rsb_probe()
781 return dev_err_probe(dev, PTR_ERR(rsb->rstc), in sunxi_rsb_probe()
784 init_completion(&rsb->complete); in sunxi_rsb_probe()
785 mutex_init(&rsb->lock); in sunxi_rsb_probe()
816 device_for_each_child(rsb->dev, NULL, sunxi_rsb_remove_devices); in sunxi_rsb_remove()
817 pm_runtime_disable(&pdev->dev); in sunxi_rsb_remove()
828 { .compatible = "allwinner,sun8i-a23-rsb" },
870 MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");