brintos

brintos / linux-shallow public Read only

0
0
Text · 5.8 KiB · 82a9421 Raw
242 lines · c
1// SPDX-License-Identifier: GPL-2.02//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    316 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};165 166static struct snd_soc_dai_driver soc_dai_bd = {167	.name     = "bd28623-speaker",168	.playback = {169		.stream_name  = "Playback",170		.formats      = SNDRV_PCM_FMTBIT_S32_LE |171				SNDRV_PCM_FMTBIT_S24_LE |172				SNDRV_PCM_FMTBIT_S16_LE,173		.rates        = SNDRV_PCM_RATE_48000 |174				SNDRV_PCM_RATE_44100 |175				SNDRV_PCM_RATE_32000,176		.channels_min = 2,177		.channels_max = 2,178	},179};180 181static int bd28623_probe(struct platform_device *pdev)182{183	struct bd28623_priv *bd;184	struct device *dev = &pdev->dev;185	int i, ret;186 187	bd = devm_kzalloc(&pdev->dev, sizeof(struct bd28623_priv), GFP_KERNEL);188	if (!bd)189		return -ENOMEM;190 191	for (i = 0; i < ARRAY_SIZE(bd->supplies); i++)192		bd->supplies[i].supply = bd28623_supply_names[i];193 194	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(bd->supplies),195				      bd->supplies);196	if (ret) {197		dev_err(dev, "Failed to get supplies: %d\n", ret);198		return ret;199	}200 201	bd->reset_gpio = devm_gpiod_get_optional(dev, "reset",202						 GPIOD_OUT_HIGH);203	if (IS_ERR(bd->reset_gpio)) {204		dev_err(dev, "Failed to request reset_gpio: %ld\n",205			PTR_ERR(bd->reset_gpio));206		return PTR_ERR(bd->reset_gpio);207	}208 209	bd->mute_gpio = devm_gpiod_get_optional(dev, "mute",210						GPIOD_OUT_HIGH);211	if (IS_ERR(bd->mute_gpio)) {212		dev_err(dev, "Failed to request mute_gpio: %ld\n",213			PTR_ERR(bd->mute_gpio));214		return PTR_ERR(bd->mute_gpio);215	}216 217	platform_set_drvdata(pdev, bd);218	bd->dev = dev;219 220	return devm_snd_soc_register_component(dev, &soc_codec_bd,221					       &soc_dai_bd, 1);222}223 224static const struct of_device_id bd28623_of_match[] __maybe_unused = {225	{ .compatible = "rohm,bd28623", },226	{}227};228MODULE_DEVICE_TABLE(of, bd28623_of_match);229 230static struct platform_driver bd28623_codec_driver = {231	.driver = {232		.name = "bd28623",233		.of_match_table = of_match_ptr(bd28623_of_match),234	},235	.probe  = bd28623_probe,236};237module_platform_driver(bd28623_codec_driver);238 239MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");240MODULE_DESCRIPTION("ROHM BD28623 speaker amplifier driver");241MODULE_LICENSE("GPL v2");242