175a6faf6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 239503622SDamien.Horsley /* 339503622SDamien.Horsley * Pistachio internal dac driver 439503622SDamien.Horsley * 539503622SDamien.Horsley * Copyright (C) 2015 Imagination Technologies Ltd. 639503622SDamien.Horsley * 739503622SDamien.Horsley * Author: Damien Horsley <Damien.Horsley@imgtec.com> 839503622SDamien.Horsley */ 939503622SDamien.Horsley 1039503622SDamien.Horsley #include <linux/clk.h> 1139503622SDamien.Horsley #include <linux/delay.h> 1239503622SDamien.Horsley #include <linux/mfd/syscon.h> 1339503622SDamien.Horsley #include <linux/module.h> 1439503622SDamien.Horsley #include <linux/pm_runtime.h> 1539503622SDamien.Horsley #include <linux/regmap.h> 1639503622SDamien.Horsley #include <linux/regulator/consumer.h> 1739503622SDamien.Horsley 1839503622SDamien.Horsley #include <sound/pcm_params.h> 1939503622SDamien.Horsley #include <sound/soc.h> 2039503622SDamien.Horsley 2139503622SDamien.Horsley #define PISTACHIO_INTERNAL_DAC_CTRL 0x40 2239503622SDamien.Horsley #define PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK 0x2 2339503622SDamien.Horsley #define PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK 0x1 2439503622SDamien.Horsley 2539503622SDamien.Horsley #define PISTACHIO_INTERNAL_DAC_SRST 0x44 2639503622SDamien.Horsley #define PISTACHIO_INTERNAL_DAC_SRST_MASK 0x1 2739503622SDamien.Horsley 2839503622SDamien.Horsley #define PISTACHIO_INTERNAL_DAC_GTI_CTRL 0x48 2939503622SDamien.Horsley #define PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_SHIFT 0 3039503622SDamien.Horsley #define PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_MASK 0xFFF 3139503622SDamien.Horsley #define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK 0x1000 3239503622SDamien.Horsley #define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_SHIFT 13 3339503622SDamien.Horsley #define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_MASK 0x1FE000 3439503622SDamien.Horsley 3539503622SDamien.Horsley #define PISTACHIO_INTERNAL_DAC_PWR 0x1 3639503622SDamien.Horsley #define PISTACHIO_INTERNAL_DAC_PWR_MASK 0x1 3739503622SDamien.Horsley 3839503622SDamien.Horsley #define PISTACHIO_INTERNAL_DAC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \ 3939503622SDamien.Horsley SNDRV_PCM_FMTBIT_S32_LE) 4039503622SDamien.Horsley 4139503622SDamien.Horsley /* codec private data */ 4239503622SDamien.Horsley struct pistachio_internal_dac { 4339503622SDamien.Horsley struct regmap *regmap; 4439503622SDamien.Horsley struct regulator *supply; 4539503622SDamien.Horsley bool mute; 4639503622SDamien.Horsley }; 4739503622SDamien.Horsley 4839503622SDamien.Horsley static const struct snd_kcontrol_new pistachio_internal_dac_snd_controls[] = { 4939503622SDamien.Horsley SOC_SINGLE("Playback Switch", PISTACHIO_INTERNAL_DAC_CTRL, 2, 1, 1) 5039503622SDamien.Horsley }; 5139503622SDamien.Horsley 5239503622SDamien.Horsley static const struct snd_soc_dapm_widget pistachio_internal_dac_widgets[] = { 5339503622SDamien.Horsley SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), 5439503622SDamien.Horsley SND_SOC_DAPM_OUTPUT("AOUTL"), 5539503622SDamien.Horsley SND_SOC_DAPM_OUTPUT("AOUTR"), 5639503622SDamien.Horsley }; 5739503622SDamien.Horsley 5839503622SDamien.Horsley static const struct snd_soc_dapm_route pistachio_internal_dac_routes[] = { 5939503622SDamien.Horsley { "AOUTL", NULL, "DAC" }, 6039503622SDamien.Horsley { "AOUTR", NULL, "DAC" }, 6139503622SDamien.Horsley }; 6239503622SDamien.Horsley 6339503622SDamien.Horsley static void pistachio_internal_dac_reg_writel(struct regmap *top_regs, 6439503622SDamien.Horsley u32 val, u32 reg) 6539503622SDamien.Horsley { 6639503622SDamien.Horsley regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL, 6739503622SDamien.Horsley PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_MASK, 6839503622SDamien.Horsley reg << PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_SHIFT); 6939503622SDamien.Horsley 7039503622SDamien.Horsley regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL, 7139503622SDamien.Horsley PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_MASK, 7239503622SDamien.Horsley val << PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_SHIFT); 7339503622SDamien.Horsley 7439503622SDamien.Horsley regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL, 7539503622SDamien.Horsley PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK, 7639503622SDamien.Horsley PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK); 7739503622SDamien.Horsley 7839503622SDamien.Horsley regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL, 7939503622SDamien.Horsley PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK, 0); 8039503622SDamien.Horsley } 8139503622SDamien.Horsley 8239503622SDamien.Horsley static void pistachio_internal_dac_pwr_off(struct pistachio_internal_dac *dac) 8339503622SDamien.Horsley { 8439503622SDamien.Horsley regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL, 8539503622SDamien.Horsley PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK, 8639503622SDamien.Horsley PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK); 8739503622SDamien.Horsley 8839503622SDamien.Horsley pistachio_internal_dac_reg_writel(dac->regmap, 0, 8939503622SDamien.Horsley PISTACHIO_INTERNAL_DAC_PWR); 9039503622SDamien.Horsley } 9139503622SDamien.Horsley 9239503622SDamien.Horsley static void pistachio_internal_dac_pwr_on(struct pistachio_internal_dac *dac) 9339503622SDamien.Horsley { 9439503622SDamien.Horsley regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_SRST, 9539503622SDamien.Horsley PISTACHIO_INTERNAL_DAC_SRST_MASK, 9639503622SDamien.Horsley PISTACHIO_INTERNAL_DAC_SRST_MASK); 9739503622SDamien.Horsley 9839503622SDamien.Horsley regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_SRST, 9939503622SDamien.Horsley PISTACHIO_INTERNAL_DAC_SRST_MASK, 0); 10039503622SDamien.Horsley 10139503622SDamien.Horsley pistachio_internal_dac_reg_writel(dac->regmap, 10239503622SDamien.Horsley PISTACHIO_INTERNAL_DAC_PWR_MASK, 10339503622SDamien.Horsley PISTACHIO_INTERNAL_DAC_PWR); 10439503622SDamien.Horsley 10539503622SDamien.Horsley regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL, 10639503622SDamien.Horsley PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK, 0); 10739503622SDamien.Horsley } 10839503622SDamien.Horsley 10939503622SDamien.Horsley static struct snd_soc_dai_driver pistachio_internal_dac_dais[] = { 11039503622SDamien.Horsley { 11139503622SDamien.Horsley .name = "pistachio_internal_dac", 11239503622SDamien.Horsley .playback = { 11339503622SDamien.Horsley .stream_name = "Playback", 11439503622SDamien.Horsley .channels_min = 2, 11539503622SDamien.Horsley .channels_max = 2, 11639503622SDamien.Horsley .rates = SNDRV_PCM_RATE_8000_48000, 11739503622SDamien.Horsley .formats = PISTACHIO_INTERNAL_DAC_FORMATS, 11839503622SDamien.Horsley } 11939503622SDamien.Horsley }, 12039503622SDamien.Horsley }; 12139503622SDamien.Horsley 1228dc906d3SKuninori Morimoto static int pistachio_internal_dac_codec_probe(struct snd_soc_component *component) 12339503622SDamien.Horsley { 1248dc906d3SKuninori Morimoto struct pistachio_internal_dac *dac = snd_soc_component_get_drvdata(component); 12539503622SDamien.Horsley 1268dc906d3SKuninori Morimoto snd_soc_component_init_regmap(component, dac->regmap); 12739503622SDamien.Horsley 12839503622SDamien.Horsley return 0; 12939503622SDamien.Horsley } 13039503622SDamien.Horsley 1318dc906d3SKuninori Morimoto static const struct snd_soc_component_driver pistachio_internal_dac_driver = { 13239503622SDamien.Horsley .probe = pistachio_internal_dac_codec_probe, 13339503622SDamien.Horsley .controls = pistachio_internal_dac_snd_controls, 13439503622SDamien.Horsley .num_controls = ARRAY_SIZE(pistachio_internal_dac_snd_controls), 13539503622SDamien.Horsley .dapm_widgets = pistachio_internal_dac_widgets, 13639503622SDamien.Horsley .num_dapm_widgets = ARRAY_SIZE(pistachio_internal_dac_widgets), 13739503622SDamien.Horsley .dapm_routes = pistachio_internal_dac_routes, 13839503622SDamien.Horsley .num_dapm_routes = ARRAY_SIZE(pistachio_internal_dac_routes), 1398dc906d3SKuninori Morimoto .use_pmdown_time = 1, 1408dc906d3SKuninori Morimoto .endianness = 1, 14139503622SDamien.Horsley }; 14239503622SDamien.Horsley 14339503622SDamien.Horsley static int pistachio_internal_dac_probe(struct platform_device *pdev) 14439503622SDamien.Horsley { 14539503622SDamien.Horsley struct pistachio_internal_dac *dac; 14639503622SDamien.Horsley int ret, voltage; 14739503622SDamien.Horsley struct device *dev = &pdev->dev; 14839503622SDamien.Horsley u32 reg; 14939503622SDamien.Horsley 15039503622SDamien.Horsley dac = devm_kzalloc(dev, sizeof(*dac), GFP_KERNEL); 15139503622SDamien.Horsley 15239503622SDamien.Horsley if (!dac) 15339503622SDamien.Horsley return -ENOMEM; 15439503622SDamien.Horsley 15539503622SDamien.Horsley platform_set_drvdata(pdev, dac); 15639503622SDamien.Horsley 15739503622SDamien.Horsley dac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, 15839503622SDamien.Horsley "img,cr-top"); 15939503622SDamien.Horsley if (IS_ERR(dac->regmap)) 16039503622SDamien.Horsley return PTR_ERR(dac->regmap); 16139503622SDamien.Horsley 16239503622SDamien.Horsley dac->supply = devm_regulator_get(dev, "VDD"); 163ef12f373SKuninori Morimoto if (IS_ERR(dac->supply)) 164ef12f373SKuninori Morimoto return dev_err_probe(dev, PTR_ERR(dac->supply), 165ef12f373SKuninori Morimoto "failed to acquire supply 'VDD-supply'\n"); 16639503622SDamien.Horsley 16739503622SDamien.Horsley ret = regulator_enable(dac->supply); 16839503622SDamien.Horsley if (ret) { 16939503622SDamien.Horsley dev_err(dev, "failed to enable supply: %d\n", ret); 17039503622SDamien.Horsley return ret; 17139503622SDamien.Horsley } 17239503622SDamien.Horsley 17339503622SDamien.Horsley voltage = regulator_get_voltage(dac->supply); 17439503622SDamien.Horsley 17539503622SDamien.Horsley switch (voltage) { 17639503622SDamien.Horsley case 1800000: 17739503622SDamien.Horsley reg = 0; 17839503622SDamien.Horsley break; 17939503622SDamien.Horsley case 3300000: 18039503622SDamien.Horsley reg = PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK; 18139503622SDamien.Horsley break; 18239503622SDamien.Horsley default: 18339503622SDamien.Horsley dev_err(dev, "invalid voltage: %d\n", voltage); 18439503622SDamien.Horsley ret = -EINVAL; 18539503622SDamien.Horsley goto err_regulator; 18639503622SDamien.Horsley } 18739503622SDamien.Horsley 18839503622SDamien.Horsley regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL, 18939503622SDamien.Horsley PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK, reg); 19039503622SDamien.Horsley 19139503622SDamien.Horsley pistachio_internal_dac_pwr_off(dac); 19239503622SDamien.Horsley pistachio_internal_dac_pwr_on(dac); 19339503622SDamien.Horsley 19439503622SDamien.Horsley pm_runtime_set_active(dev); 19539503622SDamien.Horsley pm_runtime_enable(dev); 19639503622SDamien.Horsley pm_runtime_idle(dev); 19739503622SDamien.Horsley 1988dc906d3SKuninori Morimoto ret = devm_snd_soc_register_component(dev, 1998dc906d3SKuninori Morimoto &pistachio_internal_dac_driver, 20039503622SDamien.Horsley pistachio_internal_dac_dais, 20139503622SDamien.Horsley ARRAY_SIZE(pistachio_internal_dac_dais)); 20239503622SDamien.Horsley if (ret) { 2038dc906d3SKuninori Morimoto dev_err(dev, "failed to register component: %d\n", ret); 20439503622SDamien.Horsley goto err_pwr; 20539503622SDamien.Horsley } 20639503622SDamien.Horsley 20739503622SDamien.Horsley return 0; 20839503622SDamien.Horsley 20939503622SDamien.Horsley err_pwr: 21039503622SDamien.Horsley pm_runtime_disable(&pdev->dev); 21139503622SDamien.Horsley pistachio_internal_dac_pwr_off(dac); 21239503622SDamien.Horsley err_regulator: 21339503622SDamien.Horsley regulator_disable(dac->supply); 21439503622SDamien.Horsley 21539503622SDamien.Horsley return ret; 21639503622SDamien.Horsley } 21739503622SDamien.Horsley 218*ab443489SUwe Kleine-König static void pistachio_internal_dac_remove(struct platform_device *pdev) 21939503622SDamien.Horsley { 22039503622SDamien.Horsley struct pistachio_internal_dac *dac = dev_get_drvdata(&pdev->dev); 22139503622SDamien.Horsley 22239503622SDamien.Horsley pm_runtime_disable(&pdev->dev); 22339503622SDamien.Horsley pistachio_internal_dac_pwr_off(dac); 22439503622SDamien.Horsley regulator_disable(dac->supply); 22539503622SDamien.Horsley } 22639503622SDamien.Horsley 22739503622SDamien.Horsley #ifdef CONFIG_PM 22839503622SDamien.Horsley static int pistachio_internal_dac_rt_resume(struct device *dev) 22939503622SDamien.Horsley { 23039503622SDamien.Horsley struct pistachio_internal_dac *dac = dev_get_drvdata(dev); 23139503622SDamien.Horsley int ret; 23239503622SDamien.Horsley 23339503622SDamien.Horsley ret = regulator_enable(dac->supply); 23439503622SDamien.Horsley if (ret) { 23539503622SDamien.Horsley dev_err(dev, "failed to enable supply: %d\n", ret); 23639503622SDamien.Horsley return ret; 23739503622SDamien.Horsley } 23839503622SDamien.Horsley 23939503622SDamien.Horsley pistachio_internal_dac_pwr_on(dac); 24039503622SDamien.Horsley 24139503622SDamien.Horsley return 0; 24239503622SDamien.Horsley } 24339503622SDamien.Horsley 24439503622SDamien.Horsley static int pistachio_internal_dac_rt_suspend(struct device *dev) 24539503622SDamien.Horsley { 24639503622SDamien.Horsley struct pistachio_internal_dac *dac = dev_get_drvdata(dev); 24739503622SDamien.Horsley 24839503622SDamien.Horsley pistachio_internal_dac_pwr_off(dac); 24939503622SDamien.Horsley 25039503622SDamien.Horsley regulator_disable(dac->supply); 25139503622SDamien.Horsley 25239503622SDamien.Horsley return 0; 25339503622SDamien.Horsley } 25439503622SDamien.Horsley #endif 25539503622SDamien.Horsley 25639503622SDamien.Horsley static const struct dev_pm_ops pistachio_internal_dac_pm_ops = { 25739503622SDamien.Horsley SET_RUNTIME_PM_OPS(pistachio_internal_dac_rt_suspend, 25839503622SDamien.Horsley pistachio_internal_dac_rt_resume, NULL) 25939503622SDamien.Horsley }; 26039503622SDamien.Horsley 26139503622SDamien.Horsley static const struct of_device_id pistachio_internal_dac_of_match[] = { 26239503622SDamien.Horsley { .compatible = "img,pistachio-internal-dac" }, 26339503622SDamien.Horsley {} 26439503622SDamien.Horsley }; 26539503622SDamien.Horsley MODULE_DEVICE_TABLE(of, pistachio_internal_dac_of_match); 26639503622SDamien.Horsley 26739503622SDamien.Horsley static struct platform_driver pistachio_internal_dac_plat_driver = { 26839503622SDamien.Horsley .driver = { 26939503622SDamien.Horsley .name = "img-pistachio-internal-dac", 27039503622SDamien.Horsley .of_match_table = pistachio_internal_dac_of_match, 27139503622SDamien.Horsley .pm = &pistachio_internal_dac_pm_ops 27239503622SDamien.Horsley }, 27339503622SDamien.Horsley .probe = pistachio_internal_dac_probe, 274*ab443489SUwe Kleine-König .remove_new = pistachio_internal_dac_remove 27539503622SDamien.Horsley }; 27639503622SDamien.Horsley module_platform_driver(pistachio_internal_dac_plat_driver); 27739503622SDamien.Horsley 27839503622SDamien.Horsley MODULE_DESCRIPTION("Pistachio Internal DAC driver"); 27939503622SDamien.Horsley MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>"); 28039503622SDamien.Horsley MODULE_LICENSE("GPL v2"); 281