0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/clk.h>
0011 #include <linux/delay.h>
0012 #include <linux/mfd/syscon.h>
0013 #include <linux/module.h>
0014 #include <linux/pm_runtime.h>
0015 #include <linux/regmap.h>
0016 #include <linux/regulator/consumer.h>
0017
0018 #include <sound/pcm_params.h>
0019 #include <sound/soc.h>
0020
0021 #define PISTACHIO_INTERNAL_DAC_CTRL 0x40
0022 #define PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK 0x2
0023 #define PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK 0x1
0024
0025 #define PISTACHIO_INTERNAL_DAC_SRST 0x44
0026 #define PISTACHIO_INTERNAL_DAC_SRST_MASK 0x1
0027
0028 #define PISTACHIO_INTERNAL_DAC_GTI_CTRL 0x48
0029 #define PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_SHIFT 0
0030 #define PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_MASK 0xFFF
0031 #define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK 0x1000
0032 #define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_SHIFT 13
0033 #define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_MASK 0x1FE000
0034
0035 #define PISTACHIO_INTERNAL_DAC_PWR 0x1
0036 #define PISTACHIO_INTERNAL_DAC_PWR_MASK 0x1
0037
0038 #define PISTACHIO_INTERNAL_DAC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \
0039 SNDRV_PCM_FMTBIT_S32_LE)
0040
0041
0042 struct pistachio_internal_dac {
0043 struct regmap *regmap;
0044 struct regulator *supply;
0045 bool mute;
0046 };
0047
0048 static const struct snd_kcontrol_new pistachio_internal_dac_snd_controls[] = {
0049 SOC_SINGLE("Playback Switch", PISTACHIO_INTERNAL_DAC_CTRL, 2, 1, 1)
0050 };
0051
0052 static const struct snd_soc_dapm_widget pistachio_internal_dac_widgets[] = {
0053 SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
0054 SND_SOC_DAPM_OUTPUT("AOUTL"),
0055 SND_SOC_DAPM_OUTPUT("AOUTR"),
0056 };
0057
0058 static const struct snd_soc_dapm_route pistachio_internal_dac_routes[] = {
0059 { "AOUTL", NULL, "DAC" },
0060 { "AOUTR", NULL, "DAC" },
0061 };
0062
0063 static void pistachio_internal_dac_reg_writel(struct regmap *top_regs,
0064 u32 val, u32 reg)
0065 {
0066 regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
0067 PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_MASK,
0068 reg << PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_SHIFT);
0069
0070 regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
0071 PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_MASK,
0072 val << PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_SHIFT);
0073
0074 regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
0075 PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK,
0076 PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK);
0077
0078 regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
0079 PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK, 0);
0080 }
0081
0082 static void pistachio_internal_dac_pwr_off(struct pistachio_internal_dac *dac)
0083 {
0084 regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL,
0085 PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK,
0086 PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK);
0087
0088 pistachio_internal_dac_reg_writel(dac->regmap, 0,
0089 PISTACHIO_INTERNAL_DAC_PWR);
0090 }
0091
0092 static void pistachio_internal_dac_pwr_on(struct pistachio_internal_dac *dac)
0093 {
0094 regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_SRST,
0095 PISTACHIO_INTERNAL_DAC_SRST_MASK,
0096 PISTACHIO_INTERNAL_DAC_SRST_MASK);
0097
0098 regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_SRST,
0099 PISTACHIO_INTERNAL_DAC_SRST_MASK, 0);
0100
0101 pistachio_internal_dac_reg_writel(dac->regmap,
0102 PISTACHIO_INTERNAL_DAC_PWR_MASK,
0103 PISTACHIO_INTERNAL_DAC_PWR);
0104
0105 regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL,
0106 PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK, 0);
0107 }
0108
0109 static struct snd_soc_dai_driver pistachio_internal_dac_dais[] = {
0110 {
0111 .name = "pistachio_internal_dac",
0112 .playback = {
0113 .stream_name = "Playback",
0114 .channels_min = 2,
0115 .channels_max = 2,
0116 .rates = SNDRV_PCM_RATE_8000_48000,
0117 .formats = PISTACHIO_INTERNAL_DAC_FORMATS,
0118 }
0119 },
0120 };
0121
0122 static int pistachio_internal_dac_codec_probe(struct snd_soc_component *component)
0123 {
0124 struct pistachio_internal_dac *dac = snd_soc_component_get_drvdata(component);
0125
0126 snd_soc_component_init_regmap(component, dac->regmap);
0127
0128 return 0;
0129 }
0130
0131 static const struct snd_soc_component_driver pistachio_internal_dac_driver = {
0132 .probe = pistachio_internal_dac_codec_probe,
0133 .controls = pistachio_internal_dac_snd_controls,
0134 .num_controls = ARRAY_SIZE(pistachio_internal_dac_snd_controls),
0135 .dapm_widgets = pistachio_internal_dac_widgets,
0136 .num_dapm_widgets = ARRAY_SIZE(pistachio_internal_dac_widgets),
0137 .dapm_routes = pistachio_internal_dac_routes,
0138 .num_dapm_routes = ARRAY_SIZE(pistachio_internal_dac_routes),
0139 .use_pmdown_time = 1,
0140 .endianness = 1,
0141 };
0142
0143 static int pistachio_internal_dac_probe(struct platform_device *pdev)
0144 {
0145 struct pistachio_internal_dac *dac;
0146 int ret, voltage;
0147 struct device *dev = &pdev->dev;
0148 u32 reg;
0149
0150 dac = devm_kzalloc(dev, sizeof(*dac), GFP_KERNEL);
0151
0152 if (!dac)
0153 return -ENOMEM;
0154
0155 platform_set_drvdata(pdev, dac);
0156
0157 dac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
0158 "img,cr-top");
0159 if (IS_ERR(dac->regmap))
0160 return PTR_ERR(dac->regmap);
0161
0162 dac->supply = devm_regulator_get(dev, "VDD");
0163 if (IS_ERR(dac->supply))
0164 return dev_err_probe(dev, PTR_ERR(dac->supply),
0165 "failed to acquire supply 'VDD-supply'\n");
0166
0167 ret = regulator_enable(dac->supply);
0168 if (ret) {
0169 dev_err(dev, "failed to enable supply: %d\n", ret);
0170 return ret;
0171 }
0172
0173 voltage = regulator_get_voltage(dac->supply);
0174
0175 switch (voltage) {
0176 case 1800000:
0177 reg = 0;
0178 break;
0179 case 3300000:
0180 reg = PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK;
0181 break;
0182 default:
0183 dev_err(dev, "invalid voltage: %d\n", voltage);
0184 ret = -EINVAL;
0185 goto err_regulator;
0186 }
0187
0188 regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL,
0189 PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK, reg);
0190
0191 pistachio_internal_dac_pwr_off(dac);
0192 pistachio_internal_dac_pwr_on(dac);
0193
0194 pm_runtime_set_active(dev);
0195 pm_runtime_enable(dev);
0196 pm_runtime_idle(dev);
0197
0198 ret = devm_snd_soc_register_component(dev,
0199 &pistachio_internal_dac_driver,
0200 pistachio_internal_dac_dais,
0201 ARRAY_SIZE(pistachio_internal_dac_dais));
0202 if (ret) {
0203 dev_err(dev, "failed to register component: %d\n", ret);
0204 goto err_pwr;
0205 }
0206
0207 return 0;
0208
0209 err_pwr:
0210 pm_runtime_disable(&pdev->dev);
0211 pistachio_internal_dac_pwr_off(dac);
0212 err_regulator:
0213 regulator_disable(dac->supply);
0214
0215 return ret;
0216 }
0217
0218 static int pistachio_internal_dac_remove(struct platform_device *pdev)
0219 {
0220 struct pistachio_internal_dac *dac = dev_get_drvdata(&pdev->dev);
0221
0222 pm_runtime_disable(&pdev->dev);
0223 pistachio_internal_dac_pwr_off(dac);
0224 regulator_disable(dac->supply);
0225
0226 return 0;
0227 }
0228
0229 #ifdef CONFIG_PM
0230 static int pistachio_internal_dac_rt_resume(struct device *dev)
0231 {
0232 struct pistachio_internal_dac *dac = dev_get_drvdata(dev);
0233 int ret;
0234
0235 ret = regulator_enable(dac->supply);
0236 if (ret) {
0237 dev_err(dev, "failed to enable supply: %d\n", ret);
0238 return ret;
0239 }
0240
0241 pistachio_internal_dac_pwr_on(dac);
0242
0243 return 0;
0244 }
0245
0246 static int pistachio_internal_dac_rt_suspend(struct device *dev)
0247 {
0248 struct pistachio_internal_dac *dac = dev_get_drvdata(dev);
0249
0250 pistachio_internal_dac_pwr_off(dac);
0251
0252 regulator_disable(dac->supply);
0253
0254 return 0;
0255 }
0256 #endif
0257
0258 static const struct dev_pm_ops pistachio_internal_dac_pm_ops = {
0259 SET_RUNTIME_PM_OPS(pistachio_internal_dac_rt_suspend,
0260 pistachio_internal_dac_rt_resume, NULL)
0261 };
0262
0263 static const struct of_device_id pistachio_internal_dac_of_match[] = {
0264 { .compatible = "img,pistachio-internal-dac" },
0265 {}
0266 };
0267 MODULE_DEVICE_TABLE(of, pistachio_internal_dac_of_match);
0268
0269 static struct platform_driver pistachio_internal_dac_plat_driver = {
0270 .driver = {
0271 .name = "img-pistachio-internal-dac",
0272 .of_match_table = pistachio_internal_dac_of_match,
0273 .pm = &pistachio_internal_dac_pm_ops
0274 },
0275 .probe = pistachio_internal_dac_probe,
0276 .remove = pistachio_internal_dac_remove
0277 };
0278 module_platform_driver(pistachio_internal_dac_plat_driver);
0279
0280 MODULE_DESCRIPTION("Pistachio Internal DAC driver");
0281 MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
0282 MODULE_LICENSE("GPL v2");