18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * This driver provides regmap to access to analog part of audio codec
48c2ecf20Sopenharmony_ci * found on Allwinner A23, A31s, A33, H3 and A64 Socs
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright 2016 Chen-Yu Tsai <wens@csie.org>
78c2ecf20Sopenharmony_ci * Copyright (C) 2018 Vasily Khoruzhick <anarsoul@gmail.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/io.h>
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/regmap.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "sun8i-adda-pr-regmap.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/* Analog control register access bits */
188c2ecf20Sopenharmony_ci#define ADDA_PR			0x0		/* PRCM base + 0x1c0 */
198c2ecf20Sopenharmony_ci#define ADDA_PR_RESET			BIT(28)
208c2ecf20Sopenharmony_ci#define ADDA_PR_WRITE			BIT(24)
218c2ecf20Sopenharmony_ci#define ADDA_PR_ADDR_SHIFT		16
228c2ecf20Sopenharmony_ci#define ADDA_PR_ADDR_MASK		GENMASK(4, 0)
238c2ecf20Sopenharmony_ci#define ADDA_PR_DATA_IN_SHIFT		8
248c2ecf20Sopenharmony_ci#define ADDA_PR_DATA_IN_MASK		GENMASK(7, 0)
258c2ecf20Sopenharmony_ci#define ADDA_PR_DATA_OUT_SHIFT		0
268c2ecf20Sopenharmony_ci#define ADDA_PR_DATA_OUT_MASK		GENMASK(7, 0)
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* regmap access bits */
298c2ecf20Sopenharmony_cistatic int adda_reg_read(void *context, unsigned int reg, unsigned int *val)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	void __iomem *base = (void __iomem *)context;
328c2ecf20Sopenharmony_ci	u32 tmp;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	/* De-assert reset */
358c2ecf20Sopenharmony_ci	writel(readl(base) | ADDA_PR_RESET, base);
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	/* Clear write bit */
388c2ecf20Sopenharmony_ci	writel(readl(base) & ~ADDA_PR_WRITE, base);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	/* Set register address */
418c2ecf20Sopenharmony_ci	tmp = readl(base);
428c2ecf20Sopenharmony_ci	tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
438c2ecf20Sopenharmony_ci	tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
448c2ecf20Sopenharmony_ci	writel(tmp, base);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	/* Read back value */
478c2ecf20Sopenharmony_ci	*val = readl(base) & ADDA_PR_DATA_OUT_MASK;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	return 0;
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic int adda_reg_write(void *context, unsigned int reg, unsigned int val)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	void __iomem *base = (void __iomem *)context;
558c2ecf20Sopenharmony_ci	u32 tmp;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	/* De-assert reset */
588c2ecf20Sopenharmony_ci	writel(readl(base) | ADDA_PR_RESET, base);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	/* Set register address */
618c2ecf20Sopenharmony_ci	tmp = readl(base);
628c2ecf20Sopenharmony_ci	tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
638c2ecf20Sopenharmony_ci	tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
648c2ecf20Sopenharmony_ci	writel(tmp, base);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	/* Set data to write */
678c2ecf20Sopenharmony_ci	tmp = readl(base);
688c2ecf20Sopenharmony_ci	tmp &= ~(ADDA_PR_DATA_IN_MASK << ADDA_PR_DATA_IN_SHIFT);
698c2ecf20Sopenharmony_ci	tmp |= (val & ADDA_PR_DATA_IN_MASK) << ADDA_PR_DATA_IN_SHIFT;
708c2ecf20Sopenharmony_ci	writel(tmp, base);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	/* Set write bit to signal a write */
738c2ecf20Sopenharmony_ci	writel(readl(base) | ADDA_PR_WRITE, base);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	/* Clear write bit */
768c2ecf20Sopenharmony_ci	writel(readl(base) & ~ADDA_PR_WRITE, base);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	return 0;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic const struct regmap_config adda_pr_regmap_cfg = {
828c2ecf20Sopenharmony_ci	.name		= "adda-pr",
838c2ecf20Sopenharmony_ci	.reg_bits	= 5,
848c2ecf20Sopenharmony_ci	.reg_stride	= 1,
858c2ecf20Sopenharmony_ci	.val_bits	= 8,
868c2ecf20Sopenharmony_ci	.reg_read	= adda_reg_read,
878c2ecf20Sopenharmony_ci	.reg_write	= adda_reg_write,
888c2ecf20Sopenharmony_ci	.fast_io	= true,
898c2ecf20Sopenharmony_ci	.max_register	= 31,
908c2ecf20Sopenharmony_ci};
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistruct regmap *sun8i_adda_pr_regmap_init(struct device *dev,
938c2ecf20Sopenharmony_ci					 void __iomem *base)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	return devm_regmap_init(dev, NULL, base, &adda_pr_regmap_cfg);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sun8i_adda_pr_regmap_init);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Allwinner analog audio codec regmap driver");
1008c2ecf20Sopenharmony_ciMODULE_AUTHOR("Vasily Khoruzhick <anarsoul@gmail.com>");
1018c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1028c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:sunxi-adda-pr");
103