1 // SPDX-License-Identifier: GPL-2.0-only
3 * MFD core driver for X-Powers' AC100 Audio Codec IC
5 * The AC100 is a highly integrated audio codec and RTC subsystem designed
6 * for mobile applications. It has 3 I2S/PCM interfaces, a 2 channel DAC,
7 * a 2 channel ADC with 5 inputs and a builtin mixer. The RTC subsystem has
10 * The audio codec and RTC parts are completely separate, sharing only the
11 * host interface for access to its registers.
13 * Copyright (2016) Chen-Yu Tsai
15 * Author: Chen-Yu Tsai <wens@csie.org>
18 #include <linux/interrupt.h>
19 #include <linux/kernel.h>
20 #include <linux/mfd/core.h>
21 #include <linux/mfd/ac100.h>
22 #include <linux/module.h>
24 #include <linux/regmap.h>
25 #include <linux/sunxi-rsb.h>
27 static const struct regmap_range ac100_writeable_ranges
[] = {
28 regmap_reg_range(AC100_CHIP_AUDIO_RST
, AC100_I2S_SR_CTRL
),
29 regmap_reg_range(AC100_I2S1_CLK_CTRL
, AC100_I2S1_MXR_GAIN
),
30 regmap_reg_range(AC100_I2S2_CLK_CTRL
, AC100_I2S2_MXR_GAIN
),
31 regmap_reg_range(AC100_I2S3_CLK_CTRL
, AC100_I2S3_SIG_PATH_CTRL
),
32 regmap_reg_range(AC100_ADC_DIG_CTRL
, AC100_ADC_VOL_CTRL
),
33 regmap_reg_range(AC100_HMIC_CTRL1
, AC100_HMIC_STATUS
),
34 regmap_reg_range(AC100_DAC_DIG_CTRL
, AC100_DAC_MXR_GAIN
),
35 regmap_reg_range(AC100_ADC_APC_CTRL
, AC100_LINEOUT_CTRL
),
36 regmap_reg_range(AC100_ADC_DAP_L_CTRL
, AC100_ADC_DAP_OPT
),
37 regmap_reg_range(AC100_DAC_DAP_CTRL
, AC100_DAC_DAP_OPT
),
38 regmap_reg_range(AC100_ADC_DAP_ENA
, AC100_DAC_DAP_ENA
),
39 regmap_reg_range(AC100_SRC1_CTRL1
, AC100_SRC1_CTRL2
),
40 regmap_reg_range(AC100_SRC2_CTRL1
, AC100_SRC2_CTRL2
),
41 regmap_reg_range(AC100_CLK32K_ANALOG_CTRL
, AC100_CLKOUT_CTRL3
),
42 regmap_reg_range(AC100_RTC_RST
, AC100_RTC_UPD
),
43 regmap_reg_range(AC100_ALM_INT_ENA
, AC100_ALM_INT_STA
),
44 regmap_reg_range(AC100_ALM_SEC
, AC100_RTC_GP(15)),
47 static const struct regmap_range ac100_volatile_ranges
[] = {
48 regmap_reg_range(AC100_CHIP_AUDIO_RST
, AC100_PLL_CTRL2
),
49 regmap_reg_range(AC100_HMIC_STATUS
, AC100_HMIC_STATUS
),
50 regmap_reg_range(AC100_ADC_DAP_L_STA
, AC100_ADC_DAP_L_STA
),
51 regmap_reg_range(AC100_SRC1_CTRL1
, AC100_SRC1_CTRL1
),
52 regmap_reg_range(AC100_SRC1_CTRL3
, AC100_SRC2_CTRL1
),
53 regmap_reg_range(AC100_SRC2_CTRL3
, AC100_SRC2_CTRL4
),
54 regmap_reg_range(AC100_RTC_RST
, AC100_RTC_RST
),
55 regmap_reg_range(AC100_RTC_SEC
, AC100_ALM_INT_STA
),
56 regmap_reg_range(AC100_ALM_SEC
, AC100_ALM_UPD
),
59 static const struct regmap_access_table ac100_writeable_table
= {
60 .yes_ranges
= ac100_writeable_ranges
,
61 .n_yes_ranges
= ARRAY_SIZE(ac100_writeable_ranges
),
64 static const struct regmap_access_table ac100_volatile_table
= {
65 .yes_ranges
= ac100_volatile_ranges
,
66 .n_yes_ranges
= ARRAY_SIZE(ac100_volatile_ranges
),
69 static const struct regmap_config ac100_regmap_config
= {
72 .wr_table
= &ac100_writeable_table
,
73 .volatile_table
= &ac100_volatile_table
,
74 .max_register
= AC100_RTC_GP(15),
75 .cache_type
= REGCACHE_RBTREE
,
78 static struct mfd_cell ac100_cells
[] = {
80 .name
= "ac100-codec",
81 .of_compatible
= "x-powers,ac100-codec",
84 .of_compatible
= "x-powers,ac100-rtc",
88 static int ac100_rsb_probe(struct sunxi_rsb_device
*rdev
)
90 struct ac100_dev
*ac100
;
93 ac100
= devm_kzalloc(&rdev
->dev
, sizeof(*ac100
), GFP_KERNEL
);
97 ac100
->dev
= &rdev
->dev
;
98 sunxi_rsb_device_set_drvdata(rdev
, ac100
);
100 ac100
->regmap
= devm_regmap_init_sunxi_rsb(rdev
, &ac100_regmap_config
);
101 if (IS_ERR(ac100
->regmap
)) {
102 ret
= PTR_ERR(ac100
->regmap
);
103 dev_err(ac100
->dev
, "regmap init failed: %d\n", ret
);
107 ret
= devm_mfd_add_devices(ac100
->dev
, PLATFORM_DEVID_NONE
, ac100_cells
,
108 ARRAY_SIZE(ac100_cells
), NULL
, 0, NULL
);
110 dev_err(ac100
->dev
, "failed to add MFD devices: %d\n", ret
);
117 static const struct of_device_id ac100_of_match
[] = {
118 { .compatible
= "x-powers,ac100" },
121 MODULE_DEVICE_TABLE(of
, ac100_of_match
);
123 static struct sunxi_rsb_driver ac100_rsb_driver
= {
126 .of_match_table
= of_match_ptr(ac100_of_match
),
128 .probe
= ac100_rsb_probe
,
130 module_sunxi_rsb_driver(ac100_rsb_driver
);
132 MODULE_DESCRIPTION("Audio codec MFD core driver for AC100");
133 MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
134 MODULE_LICENSE("GPL v2");