cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pistachio-internal-dac.c (7814B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Pistachio internal dac driver
      4 *
      5 * Copyright (C) 2015 Imagination Technologies Ltd.
      6 *
      7 * Author: Damien Horsley <Damien.Horsley@imgtec.com>
      8 */
      9
     10#include <linux/clk.h>
     11#include <linux/delay.h>
     12#include <linux/mfd/syscon.h>
     13#include <linux/module.h>
     14#include <linux/pm_runtime.h>
     15#include <linux/regmap.h>
     16#include <linux/regulator/consumer.h>
     17
     18#include <sound/pcm_params.h>
     19#include <sound/soc.h>
     20
     21#define PISTACHIO_INTERNAL_DAC_CTRL			0x40
     22#define PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK	0x2
     23#define PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK		0x1
     24
     25#define PISTACHIO_INTERNAL_DAC_SRST			0x44
     26#define PISTACHIO_INTERNAL_DAC_SRST_MASK		0x1
     27
     28#define PISTACHIO_INTERNAL_DAC_GTI_CTRL			0x48
     29#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_SHIFT	0
     30#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_MASK	0xFFF
     31#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK		0x1000
     32#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_SHIFT	13
     33#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_MASK	0x1FE000
     34
     35#define PISTACHIO_INTERNAL_DAC_PWR			0x1
     36#define PISTACHIO_INTERNAL_DAC_PWR_MASK			0x1
     37
     38#define PISTACHIO_INTERNAL_DAC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE |  \
     39					SNDRV_PCM_FMTBIT_S32_LE)
     40
     41/* codec private data */
     42struct pistachio_internal_dac {
     43	struct regmap *regmap;
     44	struct regulator *supply;
     45	bool mute;
     46};
     47
     48static const struct snd_kcontrol_new pistachio_internal_dac_snd_controls[] = {
     49	SOC_SINGLE("Playback Switch", PISTACHIO_INTERNAL_DAC_CTRL, 2, 1, 1)
     50};
     51
     52static const struct snd_soc_dapm_widget pistachio_internal_dac_widgets[] = {
     53	SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
     54	SND_SOC_DAPM_OUTPUT("AOUTL"),
     55	SND_SOC_DAPM_OUTPUT("AOUTR"),
     56};
     57
     58static const struct snd_soc_dapm_route pistachio_internal_dac_routes[] = {
     59	{ "AOUTL", NULL, "DAC" },
     60	{ "AOUTR", NULL, "DAC" },
     61};
     62
     63static void pistachio_internal_dac_reg_writel(struct regmap *top_regs,
     64						u32 val, u32 reg)
     65{
     66	regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
     67			PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_MASK,
     68			reg << PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_SHIFT);
     69
     70	regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
     71			PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_MASK,
     72			val << PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_SHIFT);
     73
     74	regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
     75			PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK,
     76			PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK);
     77
     78	regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL,
     79			PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK, 0);
     80}
     81
     82static void pistachio_internal_dac_pwr_off(struct pistachio_internal_dac *dac)
     83{
     84	regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL,
     85		PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK,
     86		PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK);
     87
     88	pistachio_internal_dac_reg_writel(dac->regmap, 0,
     89					PISTACHIO_INTERNAL_DAC_PWR);
     90}
     91
     92static void pistachio_internal_dac_pwr_on(struct pistachio_internal_dac *dac)
     93{
     94	regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_SRST,
     95			PISTACHIO_INTERNAL_DAC_SRST_MASK,
     96			PISTACHIO_INTERNAL_DAC_SRST_MASK);
     97
     98	regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_SRST,
     99			PISTACHIO_INTERNAL_DAC_SRST_MASK, 0);
    100
    101	pistachio_internal_dac_reg_writel(dac->regmap,
    102					PISTACHIO_INTERNAL_DAC_PWR_MASK,
    103					PISTACHIO_INTERNAL_DAC_PWR);
    104
    105	regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL,
    106			PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK, 0);
    107}
    108
    109static struct snd_soc_dai_driver pistachio_internal_dac_dais[] = {
    110	{
    111		.name = "pistachio_internal_dac",
    112		.playback = {
    113			.stream_name = "Playback",
    114			.channels_min = 2,
    115			.channels_max = 2,
    116			.rates = SNDRV_PCM_RATE_8000_48000,
    117			.formats = PISTACHIO_INTERNAL_DAC_FORMATS,
    118		}
    119	},
    120};
    121
    122static int pistachio_internal_dac_codec_probe(struct snd_soc_component *component)
    123{
    124	struct pistachio_internal_dac *dac = snd_soc_component_get_drvdata(component);
    125
    126	snd_soc_component_init_regmap(component, dac->regmap);
    127
    128	return 0;
    129}
    130
    131static const struct snd_soc_component_driver pistachio_internal_dac_driver = {
    132	.probe			= pistachio_internal_dac_codec_probe,
    133	.controls		= pistachio_internal_dac_snd_controls,
    134	.num_controls		= ARRAY_SIZE(pistachio_internal_dac_snd_controls),
    135	.dapm_widgets		= pistachio_internal_dac_widgets,
    136	.num_dapm_widgets	= ARRAY_SIZE(pistachio_internal_dac_widgets),
    137	.dapm_routes		= pistachio_internal_dac_routes,
    138	.num_dapm_routes	= ARRAY_SIZE(pistachio_internal_dac_routes),
    139	.use_pmdown_time	= 1,
    140	.endianness		= 1,
    141	.non_legacy_dai_naming	= 1,
    142};
    143
    144static int pistachio_internal_dac_probe(struct platform_device *pdev)
    145{
    146	struct pistachio_internal_dac *dac;
    147	int ret, voltage;
    148	struct device *dev = &pdev->dev;
    149	u32 reg;
    150
    151	dac = devm_kzalloc(dev, sizeof(*dac), GFP_KERNEL);
    152
    153	if (!dac)
    154		return -ENOMEM;
    155
    156	platform_set_drvdata(pdev, dac);
    157
    158	dac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
    159							    "img,cr-top");
    160	if (IS_ERR(dac->regmap))
    161		return PTR_ERR(dac->regmap);
    162
    163	dac->supply = devm_regulator_get(dev, "VDD");
    164	if (IS_ERR(dac->supply))
    165		return dev_err_probe(dev, PTR_ERR(dac->supply),
    166				     "failed to acquire supply 'VDD-supply'\n");
    167
    168	ret = regulator_enable(dac->supply);
    169	if (ret) {
    170		dev_err(dev, "failed to enable supply: %d\n", ret);
    171		return ret;
    172	}
    173
    174	voltage = regulator_get_voltage(dac->supply);
    175
    176	switch (voltage) {
    177	case 1800000:
    178		reg = 0;
    179		break;
    180	case 3300000:
    181		reg = PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK;
    182		break;
    183	default:
    184		dev_err(dev, "invalid voltage: %d\n", voltage);
    185		ret = -EINVAL;
    186		goto err_regulator;
    187	}
    188
    189	regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL,
    190			PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK, reg);
    191
    192	pistachio_internal_dac_pwr_off(dac);
    193	pistachio_internal_dac_pwr_on(dac);
    194
    195	pm_runtime_set_active(dev);
    196	pm_runtime_enable(dev);
    197	pm_runtime_idle(dev);
    198
    199	ret = devm_snd_soc_register_component(dev,
    200			&pistachio_internal_dac_driver,
    201			pistachio_internal_dac_dais,
    202			ARRAY_SIZE(pistachio_internal_dac_dais));
    203	if (ret) {
    204		dev_err(dev, "failed to register component: %d\n", ret);
    205		goto err_pwr;
    206	}
    207
    208	return 0;
    209
    210err_pwr:
    211	pm_runtime_disable(&pdev->dev);
    212	pistachio_internal_dac_pwr_off(dac);
    213err_regulator:
    214	regulator_disable(dac->supply);
    215
    216	return ret;
    217}
    218
    219static int pistachio_internal_dac_remove(struct platform_device *pdev)
    220{
    221	struct pistachio_internal_dac *dac = dev_get_drvdata(&pdev->dev);
    222
    223	pm_runtime_disable(&pdev->dev);
    224	pistachio_internal_dac_pwr_off(dac);
    225	regulator_disable(dac->supply);
    226
    227	return 0;
    228}
    229
    230#ifdef CONFIG_PM
    231static int pistachio_internal_dac_rt_resume(struct device *dev)
    232{
    233	struct pistachio_internal_dac *dac = dev_get_drvdata(dev);
    234	int ret;
    235
    236	ret = regulator_enable(dac->supply);
    237	if (ret) {
    238		dev_err(dev, "failed to enable supply: %d\n", ret);
    239		return ret;
    240	}
    241
    242	pistachio_internal_dac_pwr_on(dac);
    243
    244	return 0;
    245}
    246
    247static int pistachio_internal_dac_rt_suspend(struct device *dev)
    248{
    249	struct pistachio_internal_dac *dac = dev_get_drvdata(dev);
    250
    251	pistachio_internal_dac_pwr_off(dac);
    252
    253	regulator_disable(dac->supply);
    254
    255	return 0;
    256}
    257#endif
    258
    259static const struct dev_pm_ops pistachio_internal_dac_pm_ops = {
    260	SET_RUNTIME_PM_OPS(pistachio_internal_dac_rt_suspend,
    261			pistachio_internal_dac_rt_resume, NULL)
    262};
    263
    264static const struct of_device_id pistachio_internal_dac_of_match[] = {
    265	{ .compatible = "img,pistachio-internal-dac" },
    266	{}
    267};
    268MODULE_DEVICE_TABLE(of, pistachio_internal_dac_of_match);
    269
    270static struct platform_driver pistachio_internal_dac_plat_driver = {
    271	.driver = {
    272		.name = "img-pistachio-internal-dac",
    273		.of_match_table = pistachio_internal_dac_of_match,
    274		.pm = &pistachio_internal_dac_pm_ops
    275	},
    276	.probe = pistachio_internal_dac_probe,
    277	.remove = pistachio_internal_dac_remove
    278};
    279module_platform_driver(pistachio_internal_dac_plat_driver);
    280
    281MODULE_DESCRIPTION("Pistachio Internal DAC driver");
    282MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
    283MODULE_LICENSE("GPL v2");