155b407f6SVasily Khoruzhick // SPDX-License-Identifier: GPL-2.0+
255b407f6SVasily Khoruzhick /*
355b407f6SVasily Khoruzhick  * This driver provides regmap to access to analog part of audio codec
455b407f6SVasily Khoruzhick  * found on Allwinner A23, A31s, A33, H3 and A64 Socs
555b407f6SVasily Khoruzhick  *
655b407f6SVasily Khoruzhick  * Copyright 2016 Chen-Yu Tsai <wens@csie.org>
755b407f6SVasily Khoruzhick  * Copyright (C) 2018 Vasily Khoruzhick <anarsoul@gmail.com>
855b407f6SVasily Khoruzhick  */
955b407f6SVasily Khoruzhick 
1055b407f6SVasily Khoruzhick #include <linux/io.h>
1155b407f6SVasily Khoruzhick #include <linux/kernel.h>
1255b407f6SVasily Khoruzhick #include <linux/module.h>
1355b407f6SVasily Khoruzhick #include <linux/regmap.h>
1455b407f6SVasily Khoruzhick 
1555b407f6SVasily Khoruzhick #include "sun8i-adda-pr-regmap.h"
1655b407f6SVasily Khoruzhick 
1755b407f6SVasily Khoruzhick /* Analog control register access bits */
1855b407f6SVasily Khoruzhick #define ADDA_PR			0x0		/* PRCM base + 0x1c0 */
1955b407f6SVasily Khoruzhick #define ADDA_PR_RESET			BIT(28)
2055b407f6SVasily Khoruzhick #define ADDA_PR_WRITE			BIT(24)
2155b407f6SVasily Khoruzhick #define ADDA_PR_ADDR_SHIFT		16
2255b407f6SVasily Khoruzhick #define ADDA_PR_ADDR_MASK		GENMASK(4, 0)
2355b407f6SVasily Khoruzhick #define ADDA_PR_DATA_IN_SHIFT		8
2455b407f6SVasily Khoruzhick #define ADDA_PR_DATA_IN_MASK		GENMASK(7, 0)
2555b407f6SVasily Khoruzhick #define ADDA_PR_DATA_OUT_SHIFT		0
2655b407f6SVasily Khoruzhick #define ADDA_PR_DATA_OUT_MASK		GENMASK(7, 0)
2755b407f6SVasily Khoruzhick 
2855b407f6SVasily Khoruzhick /* regmap access bits */
adda_reg_read(void * context,unsigned int reg,unsigned int * val)2955b407f6SVasily Khoruzhick static int adda_reg_read(void *context, unsigned int reg, unsigned int *val)
3055b407f6SVasily Khoruzhick {
3155b407f6SVasily Khoruzhick 	void __iomem *base = (void __iomem *)context;
3255b407f6SVasily Khoruzhick 	u32 tmp;
3355b407f6SVasily Khoruzhick 
3455b407f6SVasily Khoruzhick 	/* De-assert reset */
3555b407f6SVasily Khoruzhick 	writel(readl(base) | ADDA_PR_RESET, base);
3655b407f6SVasily Khoruzhick 
3755b407f6SVasily Khoruzhick 	/* Clear write bit */
3855b407f6SVasily Khoruzhick 	writel(readl(base) & ~ADDA_PR_WRITE, base);
3955b407f6SVasily Khoruzhick 
4055b407f6SVasily Khoruzhick 	/* Set register address */
4155b407f6SVasily Khoruzhick 	tmp = readl(base);
4255b407f6SVasily Khoruzhick 	tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
4355b407f6SVasily Khoruzhick 	tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
4455b407f6SVasily Khoruzhick 	writel(tmp, base);
4555b407f6SVasily Khoruzhick 
4655b407f6SVasily Khoruzhick 	/* Read back value */
4755b407f6SVasily Khoruzhick 	*val = readl(base) & ADDA_PR_DATA_OUT_MASK;
4855b407f6SVasily Khoruzhick 
4955b407f6SVasily Khoruzhick 	return 0;
5055b407f6SVasily Khoruzhick }
5155b407f6SVasily Khoruzhick 
adda_reg_write(void * context,unsigned int reg,unsigned int val)5255b407f6SVasily Khoruzhick static int adda_reg_write(void *context, unsigned int reg, unsigned int val)
5355b407f6SVasily Khoruzhick {
5455b407f6SVasily Khoruzhick 	void __iomem *base = (void __iomem *)context;
5555b407f6SVasily Khoruzhick 	u32 tmp;
5655b407f6SVasily Khoruzhick 
5755b407f6SVasily Khoruzhick 	/* De-assert reset */
5855b407f6SVasily Khoruzhick 	writel(readl(base) | ADDA_PR_RESET, base);
5955b407f6SVasily Khoruzhick 
6055b407f6SVasily Khoruzhick 	/* Set register address */
6155b407f6SVasily Khoruzhick 	tmp = readl(base);
6255b407f6SVasily Khoruzhick 	tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
6355b407f6SVasily Khoruzhick 	tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
6455b407f6SVasily Khoruzhick 	writel(tmp, base);
6555b407f6SVasily Khoruzhick 
6655b407f6SVasily Khoruzhick 	/* Set data to write */
6755b407f6SVasily Khoruzhick 	tmp = readl(base);
6855b407f6SVasily Khoruzhick 	tmp &= ~(ADDA_PR_DATA_IN_MASK << ADDA_PR_DATA_IN_SHIFT);
6955b407f6SVasily Khoruzhick 	tmp |= (val & ADDA_PR_DATA_IN_MASK) << ADDA_PR_DATA_IN_SHIFT;
7055b407f6SVasily Khoruzhick 	writel(tmp, base);
7155b407f6SVasily Khoruzhick 
7255b407f6SVasily Khoruzhick 	/* Set write bit to signal a write */
7355b407f6SVasily Khoruzhick 	writel(readl(base) | ADDA_PR_WRITE, base);
7455b407f6SVasily Khoruzhick 
7555b407f6SVasily Khoruzhick 	/* Clear write bit */
7655b407f6SVasily Khoruzhick 	writel(readl(base) & ~ADDA_PR_WRITE, base);
7755b407f6SVasily Khoruzhick 
7855b407f6SVasily Khoruzhick 	return 0;
7955b407f6SVasily Khoruzhick }
8055b407f6SVasily Khoruzhick 
8155b407f6SVasily Khoruzhick static const struct regmap_config adda_pr_regmap_cfg = {
8255b407f6SVasily Khoruzhick 	.name		= "adda-pr",
8355b407f6SVasily Khoruzhick 	.reg_bits	= 5,
8455b407f6SVasily Khoruzhick 	.reg_stride	= 1,
8555b407f6SVasily Khoruzhick 	.val_bits	= 8,
8655b407f6SVasily Khoruzhick 	.reg_read	= adda_reg_read,
8755b407f6SVasily Khoruzhick 	.reg_write	= adda_reg_write,
8855b407f6SVasily Khoruzhick 	.fast_io	= true,
8955b407f6SVasily Khoruzhick 	.max_register	= 31,
9055b407f6SVasily Khoruzhick };
9155b407f6SVasily Khoruzhick 
sun8i_adda_pr_regmap_init(struct device * dev,void __iomem * base)9255b407f6SVasily Khoruzhick struct regmap *sun8i_adda_pr_regmap_init(struct device *dev,
9355b407f6SVasily Khoruzhick 					 void __iomem *base)
9455b407f6SVasily Khoruzhick {
9555b407f6SVasily Khoruzhick 	return devm_regmap_init(dev, NULL, base, &adda_pr_regmap_cfg);
9655b407f6SVasily Khoruzhick }
9755b407f6SVasily Khoruzhick EXPORT_SYMBOL_GPL(sun8i_adda_pr_regmap_init);
9855b407f6SVasily Khoruzhick 
9955b407f6SVasily Khoruzhick MODULE_DESCRIPTION("Allwinner analog audio codec regmap driver");
10055b407f6SVasily Khoruzhick MODULE_AUTHOR("Vasily Khoruzhick <anarsoul@gmail.com>");
10155b407f6SVasily Khoruzhick MODULE_LICENSE("GPL");
10255b407f6SVasily Khoruzhick MODULE_ALIAS("platform:sunxi-adda-pr");
103