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