wcd938x-sdw.c (8544B)
1// SPDX-License-Identifier: GPL-2.0 2// Copyright (c) 2021, Linaro Limited 3 4#include <linux/module.h> 5#include <linux/slab.h> 6#include <linux/platform_device.h> 7#include <linux/device.h> 8#include <linux/kernel.h> 9#include <linux/component.h> 10#include <linux/pm_runtime.h> 11#include <linux/irq.h> 12#include <linux/irqdomain.h> 13#include <linux/of.h> 14#include <linux/soundwire/sdw.h> 15#include <linux/soundwire/sdw_type.h> 16#include <linux/soundwire/sdw_registers.h> 17#include <linux/regmap.h> 18#include <sound/soc.h> 19#include <sound/soc-dapm.h> 20#include "wcd938x.h" 21 22#define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m) (0xE0 + 0x10 * (m)) 23 24static struct wcd938x_sdw_ch_info wcd938x_sdw_rx_ch_info[] = { 25 WCD_SDW_CH(WCD938X_HPH_L, WCD938X_HPH_PORT, BIT(0)), 26 WCD_SDW_CH(WCD938X_HPH_R, WCD938X_HPH_PORT, BIT(1)), 27 WCD_SDW_CH(WCD938X_CLSH, WCD938X_CLSH_PORT, BIT(0)), 28 WCD_SDW_CH(WCD938X_COMP_L, WCD938X_COMP_PORT, BIT(0)), 29 WCD_SDW_CH(WCD938X_COMP_R, WCD938X_COMP_PORT, BIT(1)), 30 WCD_SDW_CH(WCD938X_LO, WCD938X_LO_PORT, BIT(0)), 31 WCD_SDW_CH(WCD938X_DSD_L, WCD938X_DSD_PORT, BIT(0)), 32 WCD_SDW_CH(WCD938X_DSD_R, WCD938X_DSD_PORT, BIT(1)), 33}; 34 35static struct wcd938x_sdw_ch_info wcd938x_sdw_tx_ch_info[] = { 36 WCD_SDW_CH(WCD938X_ADC1, WCD938X_ADC_1_2_PORT, BIT(0)), 37 WCD_SDW_CH(WCD938X_ADC2, WCD938X_ADC_1_2_PORT, BIT(1)), 38 WCD_SDW_CH(WCD938X_ADC3, WCD938X_ADC_3_4_PORT, BIT(0)), 39 WCD_SDW_CH(WCD938X_ADC4, WCD938X_ADC_3_4_PORT, BIT(1)), 40 WCD_SDW_CH(WCD938X_DMIC0, WCD938X_DMIC_0_3_MBHC_PORT, BIT(0)), 41 WCD_SDW_CH(WCD938X_DMIC1, WCD938X_DMIC_0_3_MBHC_PORT, BIT(1)), 42 WCD_SDW_CH(WCD938X_MBHC, WCD938X_DMIC_0_3_MBHC_PORT, BIT(2)), 43 WCD_SDW_CH(WCD938X_DMIC2, WCD938X_DMIC_0_3_MBHC_PORT, BIT(2)), 44 WCD_SDW_CH(WCD938X_DMIC3, WCD938X_DMIC_0_3_MBHC_PORT, BIT(3)), 45 WCD_SDW_CH(WCD938X_DMIC4, WCD938X_DMIC_4_7_PORT, BIT(0)), 46 WCD_SDW_CH(WCD938X_DMIC5, WCD938X_DMIC_4_7_PORT, BIT(1)), 47 WCD_SDW_CH(WCD938X_DMIC6, WCD938X_DMIC_4_7_PORT, BIT(2)), 48 WCD_SDW_CH(WCD938X_DMIC7, WCD938X_DMIC_4_7_PORT, BIT(3)), 49}; 50 51static struct sdw_dpn_prop wcd938x_dpn_prop[WCD938X_MAX_SWR_PORTS] = { 52 { 53 .num = 1, 54 .type = SDW_DPN_SIMPLE, 55 .min_ch = 1, 56 .max_ch = 8, 57 .simple_ch_prep_sm = true, 58 }, { 59 .num = 2, 60 .type = SDW_DPN_SIMPLE, 61 .min_ch = 1, 62 .max_ch = 4, 63 .simple_ch_prep_sm = true, 64 }, { 65 .num = 3, 66 .type = SDW_DPN_SIMPLE, 67 .min_ch = 1, 68 .max_ch = 4, 69 .simple_ch_prep_sm = true, 70 }, { 71 .num = 4, 72 .type = SDW_DPN_SIMPLE, 73 .min_ch = 1, 74 .max_ch = 4, 75 .simple_ch_prep_sm = true, 76 }, { 77 .num = 5, 78 .type = SDW_DPN_SIMPLE, 79 .min_ch = 1, 80 .max_ch = 4, 81 .simple_ch_prep_sm = true, 82 } 83}; 84 85struct device *wcd938x_sdw_device_get(struct device_node *np) 86{ 87 return bus_find_device_by_of_node(&sdw_bus_type, np); 88 89} 90EXPORT_SYMBOL_GPL(wcd938x_sdw_device_get); 91 92int wcd938x_swr_get_current_bank(struct sdw_slave *sdev) 93{ 94 int bank; 95 96 bank = sdw_read(sdev, SDW_SCP_CTRL); 97 98 return ((bank & 0x40) ? 1 : 0); 99} 100EXPORT_SYMBOL_GPL(wcd938x_swr_get_current_bank); 101 102int wcd938x_sdw_hw_params(struct wcd938x_sdw_priv *wcd, 103 struct snd_pcm_substream *substream, 104 struct snd_pcm_hw_params *params, 105 struct snd_soc_dai *dai) 106{ 107 struct sdw_port_config port_config[WCD938X_MAX_SWR_PORTS]; 108 unsigned long ch_mask; 109 int i, j; 110 111 wcd->sconfig.ch_count = 1; 112 wcd->active_ports = 0; 113 for (i = 0; i < WCD938X_MAX_SWR_PORTS; i++) { 114 ch_mask = wcd->port_config[i].ch_mask; 115 116 if (!ch_mask) 117 continue; 118 119 for_each_set_bit(j, &ch_mask, 4) 120 wcd->sconfig.ch_count++; 121 122 port_config[wcd->active_ports] = wcd->port_config[i]; 123 wcd->active_ports++; 124 } 125 126 wcd->sconfig.bps = 1; 127 wcd->sconfig.frame_rate = params_rate(params); 128 if (wcd->is_tx) 129 wcd->sconfig.direction = SDW_DATA_DIR_TX; 130 else 131 wcd->sconfig.direction = SDW_DATA_DIR_RX; 132 133 wcd->sconfig.type = SDW_STREAM_PCM; 134 135 return sdw_stream_add_slave(wcd->sdev, &wcd->sconfig, 136 &port_config[0], wcd->active_ports, 137 wcd->sruntime); 138} 139EXPORT_SYMBOL_GPL(wcd938x_sdw_hw_params); 140 141int wcd938x_sdw_free(struct wcd938x_sdw_priv *wcd, 142 struct snd_pcm_substream *substream, 143 struct snd_soc_dai *dai) 144{ 145 sdw_stream_remove_slave(wcd->sdev, wcd->sruntime); 146 147 return 0; 148} 149EXPORT_SYMBOL_GPL(wcd938x_sdw_free); 150 151int wcd938x_sdw_set_sdw_stream(struct wcd938x_sdw_priv *wcd, 152 struct snd_soc_dai *dai, 153 void *stream, int direction) 154{ 155 wcd->sruntime = stream; 156 157 return 0; 158} 159EXPORT_SYMBOL_GPL(wcd938x_sdw_set_sdw_stream); 160 161static int wcd9380_update_status(struct sdw_slave *slave, 162 enum sdw_slave_status status) 163{ 164 return 0; 165} 166 167static int wcd9380_bus_config(struct sdw_slave *slave, 168 struct sdw_bus_params *params) 169{ 170 sdw_write(slave, SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(params->next_bank), 0x01); 171 172 return 0; 173} 174 175static int wcd9380_interrupt_callback(struct sdw_slave *slave, 176 struct sdw_slave_intr_status *status) 177{ 178 struct wcd938x_sdw_priv *wcd = dev_get_drvdata(&slave->dev); 179 struct irq_domain *slave_irq = wcd->slave_irq; 180 struct regmap *regmap = dev_get_regmap(&slave->dev, NULL); 181 u32 sts1, sts2, sts3; 182 183 do { 184 handle_nested_irq(irq_find_mapping(slave_irq, 0)); 185 regmap_read(regmap, WCD938X_DIGITAL_INTR_STATUS_0, &sts1); 186 regmap_read(regmap, WCD938X_DIGITAL_INTR_STATUS_1, &sts2); 187 regmap_read(regmap, WCD938X_DIGITAL_INTR_STATUS_2, &sts3); 188 189 } while (sts1 || sts2 || sts3); 190 191 return IRQ_HANDLED; 192} 193 194static struct sdw_slave_ops wcd9380_slave_ops = { 195 .update_status = wcd9380_update_status, 196 .interrupt_callback = wcd9380_interrupt_callback, 197 .bus_config = wcd9380_bus_config, 198}; 199 200static int wcd938x_sdw_component_bind(struct device *dev, 201 struct device *master, void *data) 202{ 203 return 0; 204} 205 206static void wcd938x_sdw_component_unbind(struct device *dev, 207 struct device *master, void *data) 208{ 209} 210 211static const struct component_ops wcd938x_sdw_component_ops = { 212 .bind = wcd938x_sdw_component_bind, 213 .unbind = wcd938x_sdw_component_unbind, 214}; 215 216static int wcd9380_probe(struct sdw_slave *pdev, 217 const struct sdw_device_id *id) 218{ 219 struct device *dev = &pdev->dev; 220 struct wcd938x_sdw_priv *wcd; 221 int ret; 222 223 wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL); 224 if (!wcd) 225 return -ENOMEM; 226 227 /** 228 * Port map index starts with 0, however the data port for this codec 229 * are from index 1 230 */ 231 if (of_property_read_bool(dev->of_node, "qcom,tx-port-mapping")) { 232 wcd->is_tx = true; 233 ret = of_property_read_u32_array(dev->of_node, "qcom,tx-port-mapping", 234 &pdev->m_port_map[1], 235 WCD938X_MAX_TX_SWR_PORTS); 236 } else { 237 ret = of_property_read_u32_array(dev->of_node, "qcom,rx-port-mapping", 238 &pdev->m_port_map[1], 239 WCD938X_MAX_SWR_PORTS); 240 } 241 242 if (ret < 0) 243 dev_info(dev, "Static Port mapping not specified\n"); 244 245 wcd->sdev = pdev; 246 dev_set_drvdata(dev, wcd); 247 248 pdev->prop.scp_int1_mask = SDW_SCP_INT1_IMPL_DEF | 249 SDW_SCP_INT1_BUS_CLASH | 250 SDW_SCP_INT1_PARITY; 251 pdev->prop.lane_control_support = true; 252 pdev->prop.simple_clk_stop_capable = true; 253 if (wcd->is_tx) { 254 pdev->prop.source_ports = GENMASK(WCD938X_MAX_SWR_PORTS, 0); 255 pdev->prop.src_dpn_prop = wcd938x_dpn_prop; 256 wcd->ch_info = &wcd938x_sdw_tx_ch_info[0]; 257 pdev->prop.wake_capable = true; 258 } else { 259 pdev->prop.sink_ports = GENMASK(WCD938X_MAX_SWR_PORTS, 0); 260 pdev->prop.sink_dpn_prop = wcd938x_dpn_prop; 261 wcd->ch_info = &wcd938x_sdw_rx_ch_info[0]; 262 } 263 264 pm_runtime_set_autosuspend_delay(dev, 3000); 265 pm_runtime_use_autosuspend(dev); 266 pm_runtime_mark_last_busy(dev); 267 pm_runtime_set_active(dev); 268 pm_runtime_enable(dev); 269 270 return component_add(dev, &wcd938x_sdw_component_ops); 271} 272 273static const struct sdw_device_id wcd9380_slave_id[] = { 274 SDW_SLAVE_ENTRY(0x0217, 0x10d, 0), 275 {}, 276}; 277MODULE_DEVICE_TABLE(sdw, wcd9380_slave_id); 278 279static int __maybe_unused wcd938x_sdw_runtime_suspend(struct device *dev) 280{ 281 struct regmap *regmap = dev_get_regmap(dev, NULL); 282 283 if (regmap) { 284 regcache_cache_only(regmap, true); 285 regcache_mark_dirty(regmap); 286 } 287 return 0; 288} 289 290static int __maybe_unused wcd938x_sdw_runtime_resume(struct device *dev) 291{ 292 struct regmap *regmap = dev_get_regmap(dev, NULL); 293 294 if (regmap) { 295 regcache_cache_only(regmap, false); 296 regcache_sync(regmap); 297 } 298 299 pm_runtime_mark_last_busy(dev); 300 301 return 0; 302} 303 304static const struct dev_pm_ops wcd938x_sdw_pm_ops = { 305 SET_RUNTIME_PM_OPS(wcd938x_sdw_runtime_suspend, wcd938x_sdw_runtime_resume, NULL) 306}; 307 308 309static struct sdw_driver wcd9380_codec_driver = { 310 .probe = wcd9380_probe, 311 .ops = &wcd9380_slave_ops, 312 .id_table = wcd9380_slave_id, 313 .driver = { 314 .name = "wcd9380-codec", 315 .pm = &wcd938x_sdw_pm_ops, 316 } 317}; 318module_sdw_driver(wcd9380_codec_driver); 319 320MODULE_DESCRIPTION("WCD938X SDW codec driver"); 321MODULE_LICENSE("GPL");