2 * MFD core driver for X-Powers' AC100 Audio Codec IC
4 * The AC100 is a highly integrated audio codec and RTC subsystem designed
5 * for mobile applications. It has 3 I2S/PCM interfaces, a 2 channel DAC,
6 * a 2 channel ADC with 5 inputs and a builtin mixer. The RTC subsystem has
9 * The audio codec and RTC parts are completely separate, sharing only the
10 * host interface for access to its registers.
12 * Copyright (2016) Chen-Yu Tsai
14 * Author: Chen-Yu Tsai <wens@csie.org>
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License version 2 as
18 * published by the Free Software Foundation.
21 #include <linux/interrupt.h>
22 #include <linux/kernel.h>
23 #include <linux/mfd/core.h>
24 #include <linux/mfd/ac100.h>
25 #include <linux/module.h>
27 #include <linux/regmap.h>
28 #include <linux/sunxi-rsb.h>
30 static const struct regmap_range ac100_writeable_ranges
[] = {
31 regmap_reg_range(AC100_CHIP_AUDIO_RST
, AC100_I2S_SR_CTRL
),
32 regmap_reg_range(AC100_I2S1_CLK_CTRL
, AC100_I2S1_MXR_GAIN
),
33 regmap_reg_range(AC100_I2S2_CLK_CTRL
, AC100_I2S2_MXR_GAIN
),
34 regmap_reg_range(AC100_I2S3_CLK_CTRL
, AC100_I2S3_SIG_PATH_CTRL
),
35 regmap_reg_range(AC100_ADC_DIG_CTRL
, AC100_ADC_VOL_CTRL
),
36 regmap_reg_range(AC100_HMIC_CTRL1
, AC100_HMIC_STATUS
),
37 regmap_reg_range(AC100_DAC_DIG_CTRL
, AC100_DAC_MXR_GAIN
),
38 regmap_reg_range(AC100_ADC_APC_CTRL
, AC100_LINEOUT_CTRL
),
39 regmap_reg_range(AC100_ADC_DAP_L_CTRL
, AC100_ADC_DAP_OPT
),
40 regmap_reg_range(AC100_DAC_DAP_CTRL
, AC100_DAC_DAP_OPT
),
41 regmap_reg_range(AC100_ADC_DAP_ENA
, AC100_DAC_DAP_ENA
),
42 regmap_reg_range(AC100_SRC1_CTRL1
, AC100_SRC1_CTRL2
),
43 regmap_reg_range(AC100_SRC2_CTRL1
, AC100_SRC2_CTRL2
),
44 regmap_reg_range(AC100_CLK32K_ANALOG_CTRL
, AC100_CLKOUT_CTRL3
),
45 regmap_reg_range(AC100_RTC_RST
, AC100_RTC_UPD
),
46 regmap_reg_range(AC100_ALM_INT_ENA
, AC100_ALM_INT_STA
),
47 regmap_reg_range(AC100_ALM_SEC
, AC100_RTC_GP(15)),
50 static const struct regmap_range ac100_volatile_ranges
[] = {
51 regmap_reg_range(AC100_CHIP_AUDIO_RST
, AC100_PLL_CTRL2
),
52 regmap_reg_range(AC100_HMIC_STATUS
, AC100_HMIC_STATUS
),
53 regmap_reg_range(AC100_ADC_DAP_L_STA
, AC100_ADC_DAP_L_STA
),
54 regmap_reg_range(AC100_SRC1_CTRL1
, AC100_SRC1_CTRL1
),
55 regmap_reg_range(AC100_SRC1_CTRL3
, AC100_SRC2_CTRL1
),
56 regmap_reg_range(AC100_SRC2_CTRL3
, AC100_SRC2_CTRL4
),
57 regmap_reg_range(AC100_RTC_RST
, AC100_RTC_RST
),
58 regmap_reg_range(AC100_RTC_SEC
, AC100_ALM_INT_STA
),
59 regmap_reg_range(AC100_ALM_SEC
, AC100_ALM_UPD
),
62 static const struct regmap_access_table ac100_writeable_table
= {
63 .yes_ranges
= ac100_writeable_ranges
,
64 .n_yes_ranges
= ARRAY_SIZE(ac100_writeable_ranges
),
67 static const struct regmap_access_table ac100_volatile_table
= {
68 .yes_ranges
= ac100_volatile_ranges
,
69 .n_yes_ranges
= ARRAY_SIZE(ac100_volatile_ranges
),
72 static const struct regmap_config ac100_regmap_config
= {
75 .wr_table
= &ac100_writeable_table
,
76 .volatile_table
= &ac100_volatile_table
,
77 .max_register
= AC100_RTC_GP(15),
78 .cache_type
= REGCACHE_RBTREE
,
81 static struct mfd_cell ac100_cells
[] = {
83 .name
= "ac100-codec",
84 .of_compatible
= "x-powers,ac100-codec",
87 .of_compatible
= "x-powers,ac100-rtc",
91 static int ac100_rsb_probe(struct sunxi_rsb_device
*rdev
)
93 struct ac100_dev
*ac100
;
96 ac100
= devm_kzalloc(&rdev
->dev
, sizeof(*ac100
), GFP_KERNEL
);
100 ac100
->dev
= &rdev
->dev
;
101 sunxi_rsb_device_set_drvdata(rdev
, ac100
);
103 ac100
->regmap
= devm_regmap_init_sunxi_rsb(rdev
, &ac100_regmap_config
);
104 if (IS_ERR(ac100
->regmap
)) {
105 ret
= PTR_ERR(ac100
->regmap
);
106 dev_err(ac100
->dev
, "regmap init failed: %d\n", ret
);
110 ret
= devm_mfd_add_devices(ac100
->dev
, PLATFORM_DEVID_NONE
, ac100_cells
,
111 ARRAY_SIZE(ac100_cells
), NULL
, 0, NULL
);
113 dev_err(ac100
->dev
, "failed to add MFD devices: %d\n", ret
);
120 static const struct of_device_id ac100_of_match
[] = {
121 { .compatible
= "x-powers,ac100" },
124 MODULE_DEVICE_TABLE(of
, ac100_of_match
);
126 static struct sunxi_rsb_driver ac100_rsb_driver
= {
129 .of_match_table
= of_match_ptr(ac100_of_match
),
131 .probe
= ac100_rsb_probe
,
133 module_sunxi_rsb_driver(ac100_rsb_driver
);
135 MODULE_DESCRIPTION("Audio codec MFD core driver for AC100");
136 MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
137 MODULE_LICENSE("GPL v2");