xref: /openbmc/linux/sound/soc/codecs/rt5682-sdw.c (revision 724cc62f7a71e3a04112126806c62d9c639ab92c)
103f6fc6dSOder Chiou // SPDX-License-Identifier: GPL-2.0-only
203f6fc6dSOder Chiou //
303f6fc6dSOder Chiou // rt5682-sdw.c  --  RT5682 ALSA SoC audio component driver
403f6fc6dSOder Chiou //
503f6fc6dSOder Chiou // Copyright 2019 Realtek Semiconductor Corp.
603f6fc6dSOder Chiou // Author: Oder Chiou <oder_chiou@realtek.com>
703f6fc6dSOder Chiou //
803f6fc6dSOder Chiou 
903f6fc6dSOder Chiou #include <linux/module.h>
1003f6fc6dSOder Chiou #include <linux/moduleparam.h>
1103f6fc6dSOder Chiou #include <linux/init.h>
1203f6fc6dSOder Chiou #include <linux/delay.h>
1303f6fc6dSOder Chiou #include <linux/pm.h>
1403f6fc6dSOder Chiou #include <linux/acpi.h>
1503f6fc6dSOder Chiou #include <linux/gpio.h>
1603f6fc6dSOder Chiou #include <linux/of_gpio.h>
1703f6fc6dSOder Chiou #include <linux/regulator/consumer.h>
1803f6fc6dSOder Chiou #include <linux/mutex.h>
1903f6fc6dSOder Chiou #include <linux/soundwire/sdw.h>
2003f6fc6dSOder Chiou #include <linux/soundwire/sdw_type.h>
2103f6fc6dSOder Chiou #include <sound/core.h>
2203f6fc6dSOder Chiou #include <sound/pcm.h>
2303f6fc6dSOder Chiou #include <sound/pcm_params.h>
2403f6fc6dSOder Chiou #include <sound/jack.h>
2503f6fc6dSOder Chiou #include <sound/soc.h>
2603f6fc6dSOder Chiou #include <sound/soc-dapm.h>
2703f6fc6dSOder Chiou #include <sound/initval.h>
2803f6fc6dSOder Chiou #include <sound/tlv.h>
2903f6fc6dSOder Chiou 
3003f6fc6dSOder Chiou #include "rt5682.h"
3103f6fc6dSOder Chiou #include "rt5682-sdw.h"
3203f6fc6dSOder Chiou 
3303f6fc6dSOder Chiou static bool rt5682_sdw_readable_register(struct device *dev, unsigned int reg)
3403f6fc6dSOder Chiou {
3503f6fc6dSOder Chiou 	switch (reg) {
3603f6fc6dSOder Chiou 	case 0x00e0:
3703f6fc6dSOder Chiou 	case 0x00f0:
3803f6fc6dSOder Chiou 	case 0x3000:
3903f6fc6dSOder Chiou 	case 0x3001:
4003f6fc6dSOder Chiou 	case 0x3004:
4103f6fc6dSOder Chiou 	case 0x3005:
4203f6fc6dSOder Chiou 	case 0x3008:
4303f6fc6dSOder Chiou 		return true;
4403f6fc6dSOder Chiou 	default:
4503f6fc6dSOder Chiou 		return false;
4603f6fc6dSOder Chiou 	}
4703f6fc6dSOder Chiou }
4803f6fc6dSOder Chiou 
4903f6fc6dSOder Chiou const struct regmap_config rt5682_sdw_regmap = {
5003f6fc6dSOder Chiou 	.name = "sdw",
5103f6fc6dSOder Chiou 	.reg_bits = 32,
5203f6fc6dSOder Chiou 	.val_bits = 8,
5303f6fc6dSOder Chiou 	.max_register = RT5682_I2C_MODE,
5403f6fc6dSOder Chiou 	.readable_reg = rt5682_sdw_readable_register,
5503f6fc6dSOder Chiou 	.cache_type = REGCACHE_NONE,
5603f6fc6dSOder Chiou 	.use_single_read = true,
5703f6fc6dSOder Chiou 	.use_single_write = true,
5803f6fc6dSOder Chiou };
5903f6fc6dSOder Chiou 
6003f6fc6dSOder Chiou static int rt5682_update_status(struct sdw_slave *slave,
6103f6fc6dSOder Chiou 					enum sdw_slave_status status)
6203f6fc6dSOder Chiou {
6303f6fc6dSOder Chiou 	struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev);
6403f6fc6dSOder Chiou 
6503f6fc6dSOder Chiou 	/* Update the status */
6603f6fc6dSOder Chiou 	rt5682->status = status;
6703f6fc6dSOder Chiou 
6803f6fc6dSOder Chiou 	if (status == SDW_SLAVE_UNATTACHED)
6903f6fc6dSOder Chiou 		rt5682->hw_init = false;
7003f6fc6dSOder Chiou 
7103f6fc6dSOder Chiou 	/*
7203f6fc6dSOder Chiou 	 * Perform initialization only if slave status is present and
7303f6fc6dSOder Chiou 	 * hw_init flag is false
7403f6fc6dSOder Chiou 	 */
7503f6fc6dSOder Chiou 	if (rt5682->hw_init || rt5682->status != SDW_SLAVE_ATTACHED)
7603f6fc6dSOder Chiou 		return 0;
7703f6fc6dSOder Chiou 
7803f6fc6dSOder Chiou 	/* perform I/O transfers required for Slave initialization */
7903f6fc6dSOder Chiou 	return rt5682_io_init(&slave->dev, slave);
8003f6fc6dSOder Chiou }
8103f6fc6dSOder Chiou 
8203f6fc6dSOder Chiou static int rt5682_read_prop(struct sdw_slave *slave)
8303f6fc6dSOder Chiou {
8403f6fc6dSOder Chiou 	struct sdw_slave_prop *prop = &slave->prop;
8503f6fc6dSOder Chiou 	int nval, i, num_of_ports = 1;
8603f6fc6dSOder Chiou 	u32 bit;
8703f6fc6dSOder Chiou 	unsigned long addr;
8803f6fc6dSOder Chiou 	struct sdw_dpn_prop *dpn;
8903f6fc6dSOder Chiou 
9003f6fc6dSOder Chiou 	prop->paging_support = false;
9103f6fc6dSOder Chiou 
9203f6fc6dSOder Chiou 	/* first we need to allocate memory for set bits in port lists */
9303f6fc6dSOder Chiou 	prop->source_ports = 0x4;	/* BITMAP: 00000100 */
9403f6fc6dSOder Chiou 	prop->sink_ports = 0x2;		/* BITMAP: 00000010 */
9503f6fc6dSOder Chiou 
9603f6fc6dSOder Chiou 	nval = hweight32(prop->source_ports);
9703f6fc6dSOder Chiou 	num_of_ports += nval;
9803f6fc6dSOder Chiou 	prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
9903f6fc6dSOder Chiou 					  sizeof(*prop->src_dpn_prop),
10003f6fc6dSOder Chiou 					  GFP_KERNEL);
10103f6fc6dSOder Chiou 	if (!prop->src_dpn_prop)
10203f6fc6dSOder Chiou 		return -ENOMEM;
10303f6fc6dSOder Chiou 
10403f6fc6dSOder Chiou 	i = 0;
10503f6fc6dSOder Chiou 	dpn = prop->src_dpn_prop;
10603f6fc6dSOder Chiou 	addr = prop->source_ports;
10703f6fc6dSOder Chiou 	for_each_set_bit(bit, &addr, 32) {
10803f6fc6dSOder Chiou 		dpn[i].num = bit;
10903f6fc6dSOder Chiou 		dpn[i].type = SDW_DPN_FULL;
11003f6fc6dSOder Chiou 		dpn[i].simple_ch_prep_sm = true;
11103f6fc6dSOder Chiou 		dpn[i].ch_prep_timeout = 10;
11203f6fc6dSOder Chiou 		i++;
11303f6fc6dSOder Chiou 	}
11403f6fc6dSOder Chiou 
11503f6fc6dSOder Chiou 	/* do this again for sink now */
11603f6fc6dSOder Chiou 	nval = hweight32(prop->sink_ports);
11703f6fc6dSOder Chiou 	num_of_ports += nval;
11803f6fc6dSOder Chiou 	prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
11903f6fc6dSOder Chiou 					   sizeof(*prop->sink_dpn_prop),
12003f6fc6dSOder Chiou 					   GFP_KERNEL);
12103f6fc6dSOder Chiou 	if (!prop->sink_dpn_prop)
12203f6fc6dSOder Chiou 		return -ENOMEM;
12303f6fc6dSOder Chiou 
12403f6fc6dSOder Chiou 	i = 0;
12503f6fc6dSOder Chiou 	dpn = prop->sink_dpn_prop;
12603f6fc6dSOder Chiou 	addr = prop->sink_ports;
12703f6fc6dSOder Chiou 	for_each_set_bit(bit, &addr, 32) {
12803f6fc6dSOder Chiou 		dpn[i].num = bit;
12903f6fc6dSOder Chiou 		dpn[i].type = SDW_DPN_FULL;
13003f6fc6dSOder Chiou 		dpn[i].simple_ch_prep_sm = true;
13103f6fc6dSOder Chiou 		dpn[i].ch_prep_timeout = 10;
13203f6fc6dSOder Chiou 		i++;
13303f6fc6dSOder Chiou 	}
13403f6fc6dSOder Chiou 
13503f6fc6dSOder Chiou 	/* Allocate port_ready based on num_of_ports */
13603f6fc6dSOder Chiou 	slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports,
13703f6fc6dSOder Chiou 					 sizeof(*slave->port_ready),
13803f6fc6dSOder Chiou 					 GFP_KERNEL);
13903f6fc6dSOder Chiou 	if (!slave->port_ready)
14003f6fc6dSOder Chiou 		return -ENOMEM;
14103f6fc6dSOder Chiou 
14203f6fc6dSOder Chiou 	/* Initialize completion */
14303f6fc6dSOder Chiou 	for (i = 0; i < num_of_ports; i++)
14403f6fc6dSOder Chiou 		init_completion(&slave->port_ready[i]);
14503f6fc6dSOder Chiou 
14603f6fc6dSOder Chiou 	/* set the timeout values */
14703f6fc6dSOder Chiou 	prop->clk_stop_timeout = 20;
14803f6fc6dSOder Chiou 
14903f6fc6dSOder Chiou 	/* wake-up event */
15003f6fc6dSOder Chiou 	prop->wake_capable = 1;
15103f6fc6dSOder Chiou 
15203f6fc6dSOder Chiou 	return 0;
15303f6fc6dSOder Chiou }
15403f6fc6dSOder Chiou 
15503f6fc6dSOder Chiou /* Bus clock frequency */
15603f6fc6dSOder Chiou #define RT5682_CLK_FREQ_9600000HZ 9600000
15703f6fc6dSOder Chiou #define RT5682_CLK_FREQ_12000000HZ 12000000
15803f6fc6dSOder Chiou #define RT5682_CLK_FREQ_6000000HZ 6000000
15903f6fc6dSOder Chiou #define RT5682_CLK_FREQ_4800000HZ 4800000
16003f6fc6dSOder Chiou #define RT5682_CLK_FREQ_2400000HZ 2400000
16103f6fc6dSOder Chiou #define RT5682_CLK_FREQ_12288000HZ 12288000
16203f6fc6dSOder Chiou 
163a3c2e894SYueHaibing static int rt5682_clock_config(struct device *dev)
16403f6fc6dSOder Chiou {
16503f6fc6dSOder Chiou 	struct rt5682_priv *rt5682 = dev_get_drvdata(dev);
16603f6fc6dSOder Chiou 	unsigned int clk_freq, value;
16703f6fc6dSOder Chiou 
16803f6fc6dSOder Chiou 	clk_freq = (rt5682->params.curr_dr_freq >> 1);
16903f6fc6dSOder Chiou 
17003f6fc6dSOder Chiou 	switch (clk_freq) {
17103f6fc6dSOder Chiou 	case RT5682_CLK_FREQ_12000000HZ:
17203f6fc6dSOder Chiou 		value = 0x0;
17303f6fc6dSOder Chiou 		break;
17403f6fc6dSOder Chiou 	case RT5682_CLK_FREQ_6000000HZ:
17503f6fc6dSOder Chiou 		value = 0x1;
17603f6fc6dSOder Chiou 		break;
17703f6fc6dSOder Chiou 	case RT5682_CLK_FREQ_9600000HZ:
17803f6fc6dSOder Chiou 		value = 0x2;
17903f6fc6dSOder Chiou 		break;
18003f6fc6dSOder Chiou 	case RT5682_CLK_FREQ_4800000HZ:
18103f6fc6dSOder Chiou 		value = 0x3;
18203f6fc6dSOder Chiou 		break;
18303f6fc6dSOder Chiou 	case RT5682_CLK_FREQ_2400000HZ:
18403f6fc6dSOder Chiou 		value = 0x4;
18503f6fc6dSOder Chiou 		break;
18603f6fc6dSOder Chiou 	case RT5682_CLK_FREQ_12288000HZ:
18703f6fc6dSOder Chiou 		value = 0x5;
18803f6fc6dSOder Chiou 		break;
18903f6fc6dSOder Chiou 	default:
19003f6fc6dSOder Chiou 		return -EINVAL;
19103f6fc6dSOder Chiou 	}
19203f6fc6dSOder Chiou 
19303f6fc6dSOder Chiou 	regmap_write(rt5682->sdw_regmap, 0xe0, value);
19403f6fc6dSOder Chiou 	regmap_write(rt5682->sdw_regmap, 0xf0, value);
19503f6fc6dSOder Chiou 
19603f6fc6dSOder Chiou 	dev_dbg(dev, "%s complete, clk_freq=%d\n", __func__, clk_freq);
19703f6fc6dSOder Chiou 
19803f6fc6dSOder Chiou 	return 0;
19903f6fc6dSOder Chiou }
20003f6fc6dSOder Chiou 
20103f6fc6dSOder Chiou static int rt5682_bus_config(struct sdw_slave *slave,
20203f6fc6dSOder Chiou 					struct sdw_bus_params *params)
20303f6fc6dSOder Chiou {
20403f6fc6dSOder Chiou 	struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev);
20503f6fc6dSOder Chiou 	int ret;
20603f6fc6dSOder Chiou 
20703f6fc6dSOder Chiou 	memcpy(&rt5682->params, params, sizeof(*params));
20803f6fc6dSOder Chiou 
20903f6fc6dSOder Chiou 	ret = rt5682_clock_config(&slave->dev);
21003f6fc6dSOder Chiou 	if (ret < 0)
21103f6fc6dSOder Chiou 		dev_err(&slave->dev, "Invalid clk config");
21203f6fc6dSOder Chiou 
21303f6fc6dSOder Chiou 	return ret;
21403f6fc6dSOder Chiou }
21503f6fc6dSOder Chiou 
21603f6fc6dSOder Chiou static int rt5682_interrupt_callback(struct sdw_slave *slave,
21703f6fc6dSOder Chiou 					struct sdw_slave_intr_status *status)
21803f6fc6dSOder Chiou {
21903f6fc6dSOder Chiou 	struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev);
22003f6fc6dSOder Chiou 
22103f6fc6dSOder Chiou 	dev_dbg(&slave->dev,
22203f6fc6dSOder Chiou 		"%s control_port_stat=%x", __func__, status->control_port);
22303f6fc6dSOder Chiou 
22403f6fc6dSOder Chiou 	if (status->control_port & 0x4) {
22503f6fc6dSOder Chiou 		mod_delayed_work(system_power_efficient_wq,
22603f6fc6dSOder Chiou 			&rt5682->jack_detect_work, msecs_to_jiffies(250));
22703f6fc6dSOder Chiou 	}
22803f6fc6dSOder Chiou 
22903f6fc6dSOder Chiou 	return 0;
23003f6fc6dSOder Chiou }
23103f6fc6dSOder Chiou 
23203f6fc6dSOder Chiou static struct sdw_slave_ops rt5682_slave_ops = {
23303f6fc6dSOder Chiou 	.read_prop = rt5682_read_prop,
23403f6fc6dSOder Chiou 	.interrupt_callback = rt5682_interrupt_callback,
23503f6fc6dSOder Chiou 	.update_status = rt5682_update_status,
23603f6fc6dSOder Chiou 	.bus_config = rt5682_bus_config,
23703f6fc6dSOder Chiou };
23803f6fc6dSOder Chiou 
23903f6fc6dSOder Chiou static int rt5682_sdw_probe(struct sdw_slave *slave,
24003f6fc6dSOder Chiou 			   const struct sdw_device_id *id)
24103f6fc6dSOder Chiou {
24203f6fc6dSOder Chiou 	struct regmap *regmap;
24303f6fc6dSOder Chiou 
24403f6fc6dSOder Chiou 	/* Assign ops */
24503f6fc6dSOder Chiou 	slave->ops = &rt5682_slave_ops;
24603f6fc6dSOder Chiou 
24703f6fc6dSOder Chiou 	/* Regmap Initialization */
24803f6fc6dSOder Chiou 	regmap = devm_regmap_init_sdw(slave, &rt5682_sdw_regmap);
24903f6fc6dSOder Chiou 	if (IS_ERR(regmap))
25003f6fc6dSOder Chiou 		return -EINVAL;
25103f6fc6dSOder Chiou 
25203f6fc6dSOder Chiou 	rt5682_sdw_init(&slave->dev, regmap, slave);
25303f6fc6dSOder Chiou 
25403f6fc6dSOder Chiou 	return 0;
25503f6fc6dSOder Chiou }
25603f6fc6dSOder Chiou 
25703f6fc6dSOder Chiou static int rt5682_sdw_remove(struct sdw_slave *slave)
25803f6fc6dSOder Chiou {
25903f6fc6dSOder Chiou 	struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev);
26003f6fc6dSOder Chiou 
26103f6fc6dSOder Chiou 	if (rt5682 && rt5682->hw_init)
26203f6fc6dSOder Chiou 		cancel_delayed_work(&rt5682->jack_detect_work);
26303f6fc6dSOder Chiou 
26403f6fc6dSOder Chiou 	return 0;
26503f6fc6dSOder Chiou }
26603f6fc6dSOder Chiou 
26703f6fc6dSOder Chiou static const struct sdw_device_id rt5682_id[] = {
26803f6fc6dSOder Chiou 	SDW_SLAVE_ENTRY(0x025d, 0x5682, 0),
26903f6fc6dSOder Chiou 	{},
27003f6fc6dSOder Chiou };
27103f6fc6dSOder Chiou MODULE_DEVICE_TABLE(sdw, rt5682_id);
27203f6fc6dSOder Chiou 
273*724cc62fSPierre-Louis Bossart static int __maybe_unused rt5682_dev_suspend(struct device *dev)
27403f6fc6dSOder Chiou {
27503f6fc6dSOder Chiou 	struct rt5682_priv *rt5682 = dev_get_drvdata(dev);
27603f6fc6dSOder Chiou 
27703f6fc6dSOder Chiou 	if (!rt5682->hw_init)
27803f6fc6dSOder Chiou 		return 0;
27903f6fc6dSOder Chiou 
28003f6fc6dSOder Chiou 	regcache_cache_only(rt5682->regmap, true);
28103f6fc6dSOder Chiou 	regcache_mark_dirty(rt5682->regmap);
28203f6fc6dSOder Chiou 
28303f6fc6dSOder Chiou 	return 0;
28403f6fc6dSOder Chiou }
28503f6fc6dSOder Chiou 
286*724cc62fSPierre-Louis Bossart static int __maybe_unused rt5682_dev_resume(struct device *dev)
28703f6fc6dSOder Chiou {
28803f6fc6dSOder Chiou 	struct sdw_slave *slave = dev_to_sdw_dev(dev);
28903f6fc6dSOder Chiou 	struct rt5682_priv *rt5682 = dev_get_drvdata(dev);
29003f6fc6dSOder Chiou 	unsigned long time;
29103f6fc6dSOder Chiou 
29203f6fc6dSOder Chiou 	if (!rt5682->hw_init)
29303f6fc6dSOder Chiou 		return 0;
29403f6fc6dSOder Chiou 
29503f6fc6dSOder Chiou 	if (!slave->unattach_request)
29603f6fc6dSOder Chiou 		goto regmap_sync;
29703f6fc6dSOder Chiou 
29803f6fc6dSOder Chiou 	time = wait_for_completion_timeout(&slave->initialization_complete,
29903f6fc6dSOder Chiou 				msecs_to_jiffies(RT5682_PROBE_TIMEOUT));
30003f6fc6dSOder Chiou 	if (!time) {
30103f6fc6dSOder Chiou 		dev_err(&slave->dev, "Initialization not complete, timed out\n");
30203f6fc6dSOder Chiou 		return -ETIMEDOUT;
30303f6fc6dSOder Chiou 	}
30403f6fc6dSOder Chiou 
30503f6fc6dSOder Chiou regmap_sync:
30603f6fc6dSOder Chiou 	slave->unattach_request = 0;
30703f6fc6dSOder Chiou 	regcache_cache_only(rt5682->regmap, false);
30803f6fc6dSOder Chiou 	regcache_sync(rt5682->regmap);
30903f6fc6dSOder Chiou 
31003f6fc6dSOder Chiou 	return 0;
31103f6fc6dSOder Chiou }
31203f6fc6dSOder Chiou 
31303f6fc6dSOder Chiou static const struct dev_pm_ops rt5682_pm = {
31403f6fc6dSOder Chiou 	SET_SYSTEM_SLEEP_PM_OPS(rt5682_dev_suspend, rt5682_dev_resume)
31503f6fc6dSOder Chiou 	SET_RUNTIME_PM_OPS(rt5682_dev_suspend, rt5682_dev_resume, NULL)
31603f6fc6dSOder Chiou };
31703f6fc6dSOder Chiou 
31803f6fc6dSOder Chiou static struct sdw_driver rt5682_sdw_driver = {
31903f6fc6dSOder Chiou 	.driver = {
32003f6fc6dSOder Chiou 		.name = "rt5682",
32103f6fc6dSOder Chiou 		.owner = THIS_MODULE,
32203f6fc6dSOder Chiou 		.pm = &rt5682_pm,
32303f6fc6dSOder Chiou 	},
32403f6fc6dSOder Chiou 	.probe = rt5682_sdw_probe,
32503f6fc6dSOder Chiou 	.remove = rt5682_sdw_remove,
32603f6fc6dSOder Chiou 	.ops = &rt5682_slave_ops,
32703f6fc6dSOder Chiou 	.id_table = rt5682_id,
32803f6fc6dSOder Chiou };
32903f6fc6dSOder Chiou module_sdw_driver(rt5682_sdw_driver);
33003f6fc6dSOder Chiou 
33103f6fc6dSOder Chiou MODULE_DESCRIPTION("ASoC RT5682 driver SDW");
33203f6fc6dSOder Chiou MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
33303f6fc6dSOder Chiou MODULE_LICENSE("GPL v2");
334