1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * This driver provides regmap to access to analog part of audio codec 4 * found on Allwinner A23, A31s, A33, H3 and A64 Socs 5 * 6 * Copyright 2016 Chen-Yu Tsai <wens@csie.org> 7 * Copyright (C) 2018 Vasily Khoruzhick <anarsoul@gmail.com> 8 */ 9 10 #include <linux/io.h> 11 #include <linux/kernel.h> 12 #include <linux/module.h> 13 #include <linux/regmap.h> 14 15 #include "sun8i-adda-pr-regmap.h" 16 17 /* Analog control register access bits */ 18 #define ADDA_PR 0x0 /* PRCM base + 0x1c0 */ 19 #define ADDA_PR_RESET BIT(28) 20 #define ADDA_PR_WRITE BIT(24) 21 #define ADDA_PR_ADDR_SHIFT 16 22 #define ADDA_PR_ADDR_MASK GENMASK(4, 0) 23 #define ADDA_PR_DATA_IN_SHIFT 8 24 #define ADDA_PR_DATA_IN_MASK GENMASK(7, 0) 25 #define ADDA_PR_DATA_OUT_SHIFT 0 26 #define ADDA_PR_DATA_OUT_MASK GENMASK(7, 0) 27 28 /* regmap access bits */ 29 static int adda_reg_read(void *context, unsigned int reg, unsigned int *val) 30 { 31 void __iomem *base = (void __iomem *)context; 32 u32 tmp; 33 34 /* De-assert reset */ 35 writel(readl(base) | ADDA_PR_RESET, base); 36 37 /* Clear write bit */ 38 writel(readl(base) & ~ADDA_PR_WRITE, base); 39 40 /* Set register address */ 41 tmp = readl(base); 42 tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT); 43 tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT; 44 writel(tmp, base); 45 46 /* Read back value */ 47 *val = readl(base) & ADDA_PR_DATA_OUT_MASK; 48 49 return 0; 50 } 51 52 static int adda_reg_write(void *context, unsigned int reg, unsigned int val) 53 { 54 void __iomem *base = (void __iomem *)context; 55 u32 tmp; 56 57 /* De-assert reset */ 58 writel(readl(base) | ADDA_PR_RESET, base); 59 60 /* Set register address */ 61 tmp = readl(base); 62 tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT); 63 tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT; 64 writel(tmp, base); 65 66 /* Set data to write */ 67 tmp = readl(base); 68 tmp &= ~(ADDA_PR_DATA_IN_MASK << ADDA_PR_DATA_IN_SHIFT); 69 tmp |= (val & ADDA_PR_DATA_IN_MASK) << ADDA_PR_DATA_IN_SHIFT; 70 writel(tmp, base); 71 72 /* Set write bit to signal a write */ 73 writel(readl(base) | ADDA_PR_WRITE, base); 74 75 /* Clear write bit */ 76 writel(readl(base) & ~ADDA_PR_WRITE, base); 77 78 return 0; 79 } 80 81 static const struct regmap_config adda_pr_regmap_cfg = { 82 .name = "adda-pr", 83 .reg_bits = 5, 84 .reg_stride = 1, 85 .val_bits = 8, 86 .reg_read = adda_reg_read, 87 .reg_write = adda_reg_write, 88 .fast_io = true, 89 .max_register = 31, 90 }; 91 92 struct regmap *sun8i_adda_pr_regmap_init(struct device *dev, 93 void __iomem *base) 94 { 95 return devm_regmap_init(dev, NULL, base, &adda_pr_regmap_cfg); 96 } 97 EXPORT_SYMBOL_GPL(sun8i_adda_pr_regmap_init); 98 99 MODULE_DESCRIPTION("Allwinner analog audio codec regmap driver"); 100 MODULE_AUTHOR("Vasily Khoruzhick <anarsoul@gmail.com>"); 101 MODULE_LICENSE("GPL"); 102 MODULE_ALIAS("platform:sunxi-adda-pr"); 103