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

bd28623.c (6012B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// ROHM BD28623MUV class D speaker amplifier codec driver.
      4//
      5// Copyright (c) 2018 Socionext Inc.
      6
      7#include <linux/delay.h>
      8#include <linux/gpio/consumer.h>
      9#include <linux/module.h>
     10#include <linux/of.h>
     11#include <linux/regulator/consumer.h>
     12#include <sound/pcm.h>
     13#include <sound/soc.h>
     14
     15#define BD28623_NUM_SUPPLIES    3
     16
     17static const char *const bd28623_supply_names[BD28623_NUM_SUPPLIES] = {
     18	"VCCA",
     19	"VCCP1",
     20	"VCCP2",
     21};
     22
     23struct bd28623_priv {
     24	struct device *dev;
     25	struct regulator_bulk_data supplies[BD28623_NUM_SUPPLIES];
     26	struct gpio_desc *reset_gpio;
     27	struct gpio_desc *mute_gpio;
     28
     29	int switch_spk;
     30};
     31
     32static const struct snd_soc_dapm_widget bd28623_widgets[] = {
     33	SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
     34	SND_SOC_DAPM_OUTPUT("OUT1P"),
     35	SND_SOC_DAPM_OUTPUT("OUT1N"),
     36	SND_SOC_DAPM_OUTPUT("OUT2P"),
     37	SND_SOC_DAPM_OUTPUT("OUT2N"),
     38};
     39
     40static const struct snd_soc_dapm_route bd28623_routes[] = {
     41	{ "OUT1P", NULL, "DAC" },
     42	{ "OUT1N", NULL, "DAC" },
     43	{ "OUT2P", NULL, "DAC" },
     44	{ "OUT2N", NULL, "DAC" },
     45};
     46
     47static int bd28623_power_on(struct bd28623_priv *bd)
     48{
     49	int ret;
     50
     51	ret = regulator_bulk_enable(ARRAY_SIZE(bd->supplies), bd->supplies);
     52	if (ret) {
     53		dev_err(bd->dev, "Failed to enable supplies: %d\n", ret);
     54		return ret;
     55	}
     56
     57	gpiod_set_value_cansleep(bd->reset_gpio, 0);
     58	usleep_range(300000, 400000);
     59
     60	return 0;
     61}
     62
     63static void bd28623_power_off(struct bd28623_priv *bd)
     64{
     65	gpiod_set_value_cansleep(bd->reset_gpio, 1);
     66
     67	regulator_bulk_disable(ARRAY_SIZE(bd->supplies), bd->supplies);
     68}
     69
     70static int bd28623_get_switch_spk(struct snd_kcontrol *kcontrol,
     71				  struct snd_ctl_elem_value *ucontrol)
     72{
     73	struct snd_soc_component *component =
     74		snd_soc_kcontrol_component(kcontrol);
     75	struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
     76
     77	ucontrol->value.integer.value[0] = bd->switch_spk;
     78
     79	return 0;
     80}
     81
     82static int bd28623_set_switch_spk(struct snd_kcontrol *kcontrol,
     83				  struct snd_ctl_elem_value *ucontrol)
     84{
     85	struct snd_soc_component *component =
     86		snd_soc_kcontrol_component(kcontrol);
     87	struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
     88
     89	if (bd->switch_spk == ucontrol->value.integer.value[0])
     90		return 0;
     91
     92	bd->switch_spk = ucontrol->value.integer.value[0];
     93
     94	gpiod_set_value_cansleep(bd->mute_gpio, bd->switch_spk ? 0 : 1);
     95
     96	return 0;
     97}
     98
     99static const struct snd_kcontrol_new bd28623_controls[] = {
    100	SOC_SINGLE_BOOL_EXT("Speaker Switch", 0,
    101			    bd28623_get_switch_spk, bd28623_set_switch_spk),
    102};
    103
    104static int bd28623_codec_probe(struct snd_soc_component *component)
    105{
    106	struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
    107	int ret;
    108
    109	bd->switch_spk = 1;
    110
    111	ret = bd28623_power_on(bd);
    112	if (ret)
    113		return ret;
    114
    115	gpiod_set_value_cansleep(bd->mute_gpio, bd->switch_spk ? 0 : 1);
    116
    117	return 0;
    118}
    119
    120static void bd28623_codec_remove(struct snd_soc_component *component)
    121{
    122	struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
    123
    124	bd28623_power_off(bd);
    125}
    126
    127static int bd28623_codec_suspend(struct snd_soc_component *component)
    128{
    129	struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
    130
    131	bd28623_power_off(bd);
    132
    133	return 0;
    134}
    135
    136static int bd28623_codec_resume(struct snd_soc_component *component)
    137{
    138	struct bd28623_priv *bd = snd_soc_component_get_drvdata(component);
    139	int ret;
    140
    141	ret = bd28623_power_on(bd);
    142	if (ret)
    143		return ret;
    144
    145	gpiod_set_value_cansleep(bd->mute_gpio, bd->switch_spk ? 0 : 1);
    146
    147	return 0;
    148}
    149
    150static const struct snd_soc_component_driver soc_codec_bd = {
    151	.probe			= bd28623_codec_probe,
    152	.remove			= bd28623_codec_remove,
    153	.suspend		= bd28623_codec_suspend,
    154	.resume			= bd28623_codec_resume,
    155	.dapm_widgets		= bd28623_widgets,
    156	.num_dapm_widgets	= ARRAY_SIZE(bd28623_widgets),
    157	.dapm_routes		= bd28623_routes,
    158	.num_dapm_routes	= ARRAY_SIZE(bd28623_routes),
    159	.controls		= bd28623_controls,
    160	.num_controls		= ARRAY_SIZE(bd28623_controls),
    161	.idle_bias_on		= 1,
    162	.use_pmdown_time	= 1,
    163	.endianness		= 1,
    164	.non_legacy_dai_naming	= 1,
    165};
    166
    167static struct snd_soc_dai_driver soc_dai_bd = {
    168	.name     = "bd28623-speaker",
    169	.playback = {
    170		.stream_name  = "Playback",
    171		.formats      = SNDRV_PCM_FMTBIT_S32_LE |
    172				SNDRV_PCM_FMTBIT_S24_LE |
    173				SNDRV_PCM_FMTBIT_S16_LE,
    174		.rates        = SNDRV_PCM_RATE_48000 |
    175				SNDRV_PCM_RATE_44100 |
    176				SNDRV_PCM_RATE_32000,
    177		.channels_min = 2,
    178		.channels_max = 2,
    179	},
    180};
    181
    182static int bd28623_probe(struct platform_device *pdev)
    183{
    184	struct bd28623_priv *bd;
    185	struct device *dev = &pdev->dev;
    186	int i, ret;
    187
    188	bd = devm_kzalloc(&pdev->dev, sizeof(struct bd28623_priv), GFP_KERNEL);
    189	if (!bd)
    190		return -ENOMEM;
    191
    192	for (i = 0; i < ARRAY_SIZE(bd->supplies); i++)
    193		bd->supplies[i].supply = bd28623_supply_names[i];
    194
    195	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(bd->supplies),
    196				      bd->supplies);
    197	if (ret) {
    198		dev_err(dev, "Failed to get supplies: %d\n", ret);
    199		return ret;
    200	}
    201
    202	bd->reset_gpio = devm_gpiod_get_optional(dev, "reset",
    203						 GPIOD_OUT_HIGH);
    204	if (IS_ERR(bd->reset_gpio)) {
    205		dev_err(dev, "Failed to request reset_gpio: %ld\n",
    206			PTR_ERR(bd->reset_gpio));
    207		return PTR_ERR(bd->reset_gpio);
    208	}
    209
    210	bd->mute_gpio = devm_gpiod_get_optional(dev, "mute",
    211						GPIOD_OUT_HIGH);
    212	if (IS_ERR(bd->mute_gpio)) {
    213		dev_err(dev, "Failed to request mute_gpio: %ld\n",
    214			PTR_ERR(bd->mute_gpio));
    215		return PTR_ERR(bd->mute_gpio);
    216	}
    217
    218	platform_set_drvdata(pdev, bd);
    219	bd->dev = dev;
    220
    221	return devm_snd_soc_register_component(dev, &soc_codec_bd,
    222					       &soc_dai_bd, 1);
    223}
    224
    225static const struct of_device_id bd28623_of_match[] __maybe_unused = {
    226	{ .compatible = "rohm,bd28623", },
    227	{}
    228};
    229MODULE_DEVICE_TABLE(of, bd28623_of_match);
    230
    231static struct platform_driver bd28623_codec_driver = {
    232	.driver = {
    233		.name = "bd28623",
    234		.of_match_table = of_match_ptr(bd28623_of_match),
    235	},
    236	.probe  = bd28623_probe,
    237};
    238module_platform_driver(bd28623_codec_driver);
    239
    240MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
    241MODULE_DESCRIPTION("ROHM BD28623 speaker amplifier driver");
    242MODULE_LICENSE("GPL v2");