// SPDX-License-Identifier: GPL-2.0 /* * tas5825.c - ALSA SoC Texas Instruments TAS5825M Audio Amplifier * * Copyright (C) 2020 Aurelien Jarno * * Author: Aurelien Jarno */ #include #include #include #include #include #include #include #include "tas5825m.h" struct tas5825m_data { struct gpio_desc *pdn_gpio; }; static const struct snd_soc_dapm_widget tas5825m_widgets[] = { SND_SOC_DAPM_OUTPUT("OUT"), }; static const struct snd_soc_dapm_route tas5825m_routes[] = { { "OUT", NULL, "Playback" }, }; static struct snd_soc_component_driver soc_component_dev_tas5825m = { .dapm_widgets = tas5825m_widgets, .num_dapm_widgets = ARRAY_SIZE(tas5825m_widgets), .dapm_routes = tas5825m_routes, .num_dapm_routes = ARRAY_SIZE(tas5825m_routes), .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, .non_legacy_dai_naming = 1, }; static struct snd_soc_dai_driver tas5825m_dai = { .name = "tas5825m-amplifier", .playback = { .stream_name = "Playback", .channels_min = 2, .channels_max = 2, .rates = TAS5825M_RATES, .formats = TAS5825M_FORMATS, }, }; #ifdef CONFIG_OF static const struct of_device_id tas5825m_of_ids[] = { { .compatible = "ti,tas5825m", }, { } }; MODULE_DEVICE_TABLE(of, tas5825m_of_ids); #endif static void tas5825m_write_reg(struct i2c_client *client, uint8_t reg, uint8_t val) { uint8_t buf[2]; int ret; buf[0] = reg; buf[1] = val; ret = i2c_master_send(client, buf, sizeof(buf)); if (ret < 0) dev_err(&client->dev, "unable to write reg 0x%02x, value 0x%02x\n", reg, val); } static int tas5825m_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; struct tas5825m_data *tas5825m; int ret; tas5825m = devm_kzalloc(dev, sizeof(*tas5825m), GFP_KERNEL); if (!tas5825m) return -ENOMEM; dev_set_drvdata(dev, tas5825m); /* * Get control of the pdn pin and set it LOW to take the codec * out of the power-down mode. * Note: The actual pin polarity is taken care of in the GPIO lib * according the polarity specified in the DTS. */ tas5825m->pdn_gpio = devm_gpiod_get_optional(dev, "pdn", GPIOD_OUT_LOW); if (IS_ERR(tas5825m->pdn_gpio)) { if (PTR_ERR(tas5825m->pdn_gpio) == -EPROBE_DEFER) return -EPROBE_DEFER; dev_info(dev, "failed to get pdn GPIO: %ld\n", PTR_ERR(tas5825m->pdn_gpio)); tas5825m->pdn_gpio = NULL; } /* power-up time may be as long as 5ms */ mdelay(5); /* PAGE 0x00, BOOK 0x00 */ tas5825m_write_reg(client, 0x00, 0x00); tas5825m_write_reg(client, 0x7f, 0x00); /* Reset register and digital core */ tas5825m_write_reg(client, 0x01, 0x11); /* PAGE 0x00, BOOK 0x00 */ tas5825m_write_reg(client, 0x00, 0x00); tas5825m_write_reg(client, 0x7f, 0x00); /* Switch from deep sleep to Hi-z mode, keep mute enabled */ tas5825m_write_reg(client, 0x03, 0x12); /* Configure GPIO0, GPIO1 and GPIO2 as outputs */ tas5825m_write_reg(client, 0x60, 0x07); tas5825m_write_reg(client, 0x61, 0x02); tas5825m_write_reg(client, 0x62, 0x02); tas5825m_write_reg(client, 0x63, 0x02); /* GPIO0 = 1, GPIO1 = 0, GPIO2 = 1 */ tas5825m_write_reg(client, 0x65, 0x05); /* Configure the chip */ tas5825m_write_reg(client, 0x02, 0x40); /* # 768kHz, BTL, BD mode */ tas5825m_write_reg(client, 0x53, 0x60); /* # 175kHz bandwidth */ tas5825m_write_reg(client, 0x54, 0x04); /* Analog gain of -2.0dB for 24V */ tas5825m_write_reg(client, 0x4c, 0x30); /* Digital volume 0dB */ tas5825m_write_reg(client, 0x03, 0x02); /* Hiz, unmute */ /* Wait for the device to settle down */ mdelay(5); /* Start playing */ tas5825m_write_reg(client, 0x03, 0x03); /* Play mode */ tas5825m_write_reg(client, 0x78, 0x80); /* Clear analog fault */ ret = devm_snd_soc_register_component(dev, &soc_component_dev_tas5825m, &tas5825m_dai, 1); if (ret < 0) { dev_err(dev, "unable to register codec: %d\n", ret); return ret; } return 0; } static int tas5825m_i2c_remove(struct i2c_client *client) { struct device *dev = &client->dev; struct tas5825m_data *tas5825m = dev_get_drvdata(dev); /* put the codec in power-down */ if (tas5825m->pdn_gpio) gpiod_set_value_cansleep(tas5825m->pdn_gpio, 1); return 0; } static const struct i2c_device_id tas5825m_i2c_ids[] = { { "tas5825m", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, tas5825m_i2c_ids); static struct i2c_driver tas5825m_i2c_driver = { .driver = { .name = "tas5825m", .of_match_table = of_match_ptr(tas5825m_of_ids), }, .probe = tas5825m_i2c_probe, .remove = tas5825m_i2c_remove, .id_table = tas5825m_i2c_ids, }; module_i2c_driver(tas5825m_i2c_driver); MODULE_AUTHOR("Aurelien Jarno "); MODULE_DESCRIPTION("TAS5825M audio amplifier driver"); MODULE_LICENSE("GPL");