573 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// CS35L41 ALSA HDA Property driver4//5// Copyright 2023 Cirrus Logic, Inc.6//7// Author: Stefan Binding <sbinding@opensource.cirrus.com>8 9#include <linux/acpi.h>10#include <linux/gpio/consumer.h>11#include <linux/string.h>12#include "cs35l41_hda_property.h"13#include <linux/spi/spi.h>14 15#define MAX_AMPS 416 17struct cs35l41_config {18 const char *ssid;19 int num_amps;20 enum {21 INTERNAL,22 EXTERNAL23 } boost_type;24 u8 channel[MAX_AMPS];25 int reset_gpio_index; /* -1 if no reset gpio */26 int spkid_gpio_index; /* -1 if no spkid gpio */27 int cs_gpio_index; /* -1 if no cs gpio, or cs-gpios already exists, max num amps == 2 */28 int boost_ind_nanohenry; /* Required if boost_type == Internal */29 int boost_peak_milliamp; /* Required if boost_type == Internal */30 int boost_cap_microfarad; /* Required if boost_type == Internal */31};32 33static const struct cs35l41_config cs35l41_config_table[] = {34 { "10280B27", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },35 { "10280B28", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },36 { "10280BEB", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 },37 { "10280C4D", 4, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT }, 0, 1, -1, 1000, 4500, 24 },38/*39 * Device 103C89C6 does have _DSD, however it is setup to use the wrong boost type.40 * We can override the _DSD to correct the boost type here.41 * Since this laptop has valid ACPI, we do not need to handle cs-gpios, since that already exists42 * in the ACPI. The Reset GPIO is also valid, so we can use the Reset defined in _DSD.43 */44 { "103C89C6", 2, INTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, 0, 0 }, -1, -1, -1, 1000, 4500, 24 },45 { "103C8A28", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },46 { "103C8A29", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },47 { "103C8A2A", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },48 { "103C8A2B", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },49 { "103C8A2C", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },50 { "103C8A2D", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },51 { "103C8A2E", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },52 { "103C8A30", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },53 { "103C8A31", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },54 { "103C8A6E", 4, EXTERNAL, { CS35L41_LEFT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_RIGHT }, 0, -1, -1, 0, 0, 0 },55 { "103C8BB3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },56 { "103C8BB4", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },57 { "103C8BDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },58 { "103C8BDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },59 { "103C8BDF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },60 { "103C8BE0", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },61 { "103C8BE1", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },62 { "103C8BE2", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },63 { "103C8BE3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },64 { "103C8BE5", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },65 { "103C8BE6", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },66 { "103C8BE7", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },67 { "103C8BE8", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },68 { "103C8BE9", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },69 { "103C8B3A", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },70 { "103C8C15", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },71 { "103C8C16", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },72 { "103C8C17", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },73 { "103C8C4D", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },74 { "103C8C4E", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },75 { "103C8C4F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },76 { "103C8C50", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },77 { "103C8C51", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },78 { "103C8CDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },79 { "103C8CDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 3900, 24 },80 { "104312AF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },81 { "10431433", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },82 { "10431463", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },83 { "10431473", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 1000, 4500, 24 },84 { "10431483", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 1000, 4500, 24 },85 { "10431493", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },86 { "104314D3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },87 { "104314E3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },88 { "10431503", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },89 { "10431533", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },90 { "10431573", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },91 { "10431663", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 1000, 4500, 24 },92 { "10431683", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },93 { "104316A3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },94 { "104316D3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },95 { "104316F3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },96 { "104317F3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },97 { "10431863", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },98 { "104318D3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },99 { "10431A83", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },100 { "10431B93", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },101 { "10431C9F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },102 { "10431CAF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },103 { "10431CCF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },104 { "10431CDF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },105 { "10431CEF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },106 { "10431D1F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },107 { "10431DA2", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },108 { "10431E02", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },109 { "10431E12", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },110 { "10431EE2", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },111 { "10431F12", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },112 { "10431F1F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 },113 { "10431F62", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },114 { "10433A20", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },115 { "10433A30", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },116 { "10433A40", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },117 { "10433A50", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },118 { "10433A60", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },119 { "17AA3865", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },120 { "17AA3866", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },121 { "17AA386E", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },122 { "17AA386F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },123 { "17AA3877", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },124 { "17AA3878", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },125 { "17AA38A9", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },126 { "17AA38AB", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },127 { "17AA38B4", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },128 { "17AA38B5", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },129 { "17AA38B6", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },130 { "17AA38B7", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },131 { "17AA38C7", 4, INTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT }, 0, 2, -1, 1000, 4500, 24 },132 { "17AA38C8", 4, INTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT }, 0, 2, -1, 1000, 4500, 24 },133 { "17AA38F9", 2, EXTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, 0, 0 }, 0, 2, -1, 0, 0, 0 },134 { "17AA38FA", 2, EXTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, 0, 0 }, 0, 2, -1, 0, 0, 0 },135 {}136};137 138static int cs35l41_add_gpios(struct cs35l41_hda *cs35l41, struct device *physdev, int reset_gpio,139 int spkid_gpio, int cs_gpio_index, int num_amps)140{141 struct acpi_gpio_mapping *gpio_mapping = NULL;142 struct acpi_gpio_params *reset_gpio_params = NULL;143 struct acpi_gpio_params *spkid_gpio_params = NULL;144 struct acpi_gpio_params *cs_gpio_params = NULL;145 unsigned int num_entries = 0;146 unsigned int reset_index, spkid_index, csgpio_index;147 int i;148 149 /*150 * GPIO Mapping only needs to be done once, since it would be available for subsequent amps151 */152 if (cs35l41->dacpi->driver_gpios)153 return 0;154 155 if (reset_gpio >= 0) {156 reset_index = num_entries;157 num_entries++;158 }159 160 if (spkid_gpio >= 0) {161 spkid_index = num_entries;162 num_entries++;163 }164 165 if ((cs_gpio_index >= 0) && (num_amps == 2)) {166 csgpio_index = num_entries;167 num_entries++;168 }169 170 if (!num_entries)171 return 0;172 173 /* must include termination entry */174 num_entries++;175 176 gpio_mapping = devm_kcalloc(physdev, num_entries, sizeof(struct acpi_gpio_mapping),177 GFP_KERNEL);178 179 if (!gpio_mapping)180 goto err;181 182 if (reset_gpio >= 0) {183 gpio_mapping[reset_index].name = "reset-gpios";184 reset_gpio_params = devm_kcalloc(physdev, num_amps, sizeof(struct acpi_gpio_params),185 GFP_KERNEL);186 if (!reset_gpio_params)187 goto err;188 189 for (i = 0; i < num_amps; i++)190 reset_gpio_params[i].crs_entry_index = reset_gpio;191 192 gpio_mapping[reset_index].data = reset_gpio_params;193 gpio_mapping[reset_index].size = num_amps;194 }195 196 if (spkid_gpio >= 0) {197 gpio_mapping[spkid_index].name = "spk-id-gpios";198 spkid_gpio_params = devm_kcalloc(physdev, num_amps, sizeof(struct acpi_gpio_params),199 GFP_KERNEL);200 if (!spkid_gpio_params)201 goto err;202 203 for (i = 0; i < num_amps; i++)204 spkid_gpio_params[i].crs_entry_index = spkid_gpio;205 206 gpio_mapping[spkid_index].data = spkid_gpio_params;207 gpio_mapping[spkid_index].size = num_amps;208 }209 210 if ((cs_gpio_index >= 0) && (num_amps == 2)) {211 gpio_mapping[csgpio_index].name = "cs-gpios";212 /* only one GPIO CS is supported without using _DSD, obtained using index 0 */213 cs_gpio_params = devm_kzalloc(physdev, sizeof(struct acpi_gpio_params), GFP_KERNEL);214 if (!cs_gpio_params)215 goto err;216 217 cs_gpio_params->crs_entry_index = cs_gpio_index;218 219 gpio_mapping[csgpio_index].data = cs_gpio_params;220 gpio_mapping[csgpio_index].size = 1;221 }222 223 return devm_acpi_dev_add_driver_gpios(physdev, gpio_mapping);224err:225 devm_kfree(physdev, gpio_mapping);226 devm_kfree(physdev, reset_gpio_params);227 devm_kfree(physdev, spkid_gpio_params);228 devm_kfree(physdev, cs_gpio_params);229 return -ENOMEM;230}231 232static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physdev, int id,233 const char *hid)234{235 struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;236 const struct cs35l41_config *cfg;237 struct gpio_desc *cs_gpiod;238 struct spi_device *spi;239 bool dsd_found;240 int ret;241 int i;242 243 for (cfg = cs35l41_config_table; cfg->ssid; cfg++) {244 if (!strcasecmp(cfg->ssid, cs35l41->acpi_subsystem_id))245 break;246 }247 248 if (!cfg->ssid)249 return -ENOENT;250 251 if (!cs35l41->dacpi || cs35l41->dacpi != ACPI_COMPANION(physdev)) {252 dev_err(cs35l41->dev, "ACPI Device does not match, cannot override _DSD.\n");253 return -ENODEV;254 }255 256 dev_info(cs35l41->dev, "Adding DSD properties for %s\n", cs35l41->acpi_subsystem_id);257 258 dsd_found = acpi_dev_has_props(cs35l41->dacpi);259 260 if (!dsd_found) {261 ret = cs35l41_add_gpios(cs35l41, physdev, cfg->reset_gpio_index,262 cfg->spkid_gpio_index, cfg->cs_gpio_index,263 cfg->num_amps);264 if (ret) {265 dev_err(cs35l41->dev, "Error adding GPIO mapping: %d\n", ret);266 return ret;267 }268 } else if (cfg->reset_gpio_index >= 0 || cfg->spkid_gpio_index >= 0) {269 dev_warn(cs35l41->dev, "Cannot add Reset/Speaker ID/SPI CS GPIO Mapping, "270 "_DSD already exists.\n");271 }272 273 if (cs35l41->control_bus == SPI) {274 cs35l41->index = id;275 276 /*277 * Manually set the Chip Select for the second amp <cs_gpio_index> in the node.278 * This is only supported for systems with 2 amps, since we cannot expand the279 * default number of chip selects without using cs-gpios280 * The CS GPIO must be set high prior to communicating with the first amp (which281 * uses a native chip select), to ensure the second amp does not clash with the282 * first.283 */284 if (IS_ENABLED(CONFIG_SPI) && cfg->cs_gpio_index >= 0) {285 spi = to_spi_device(cs35l41->dev);286 287 if (cfg->num_amps != 2) {288 dev_warn(cs35l41->dev,289 "Cannot update SPI CS, Number of Amps (%d) != 2\n",290 cfg->num_amps);291 } else if (dsd_found) {292 dev_warn(cs35l41->dev,293 "Cannot update SPI CS, _DSD already exists.\n");294 } else {295 /*296 * This is obtained using driver_gpios, since only one GPIO for CS297 * exists, this can be obtained using index 0.298 */299 cs_gpiod = gpiod_get_index(physdev, "cs", 0, GPIOD_OUT_LOW);300 if (IS_ERR(cs_gpiod)) {301 dev_err(cs35l41->dev,302 "Unable to get Chip Select GPIO descriptor\n");303 return PTR_ERR(cs_gpiod);304 }305 if (id == 1) {306 spi_set_csgpiod(spi, 0, cs_gpiod);307 cs35l41->cs_gpio = cs_gpiod;308 } else {309 gpiod_set_value_cansleep(cs_gpiod, true);310 gpiod_put(cs_gpiod);311 }312 spi_setup(spi);313 }314 }315 } else {316 if (cfg->num_amps > 2)317 /*318 * i2c addresses for 3/4 amps are used in order: 0x40, 0x41, 0x42, 0x43,319 * subtracting 0x40 would give zero-based index320 */321 cs35l41->index = id - 0x40;322 else323 /* i2c addr 0x40 for first amp (always), 0x41/0x42 for 2nd amp */324 cs35l41->index = id == 0x40 ? 0 : 1;325 }326 327 cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(cs35l41->dacpi), "reset",328 cs35l41->index, GPIOD_OUT_LOW,329 "cs35l41-reset");330 cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, cs35l41->index, cfg->num_amps, -1);331 332 hw_cfg->spk_pos = cfg->channel[cs35l41->index];333 334 cs35l41->channel_index = 0;335 for (i = 0; i < cs35l41->index; i++)336 if (cfg->channel[i] == hw_cfg->spk_pos)337 cs35l41->channel_index++;338 339 if (cfg->boost_type == INTERNAL) {340 hw_cfg->bst_type = CS35L41_INT_BOOST;341 hw_cfg->bst_ind = cfg->boost_ind_nanohenry;342 hw_cfg->bst_ipk = cfg->boost_peak_milliamp;343 hw_cfg->bst_cap = cfg->boost_cap_microfarad;344 hw_cfg->gpio1.func = CS35L41_NOT_USED;345 hw_cfg->gpio1.valid = true;346 } else {347 hw_cfg->bst_type = CS35L41_EXT_BOOST;348 hw_cfg->bst_ind = -1;349 hw_cfg->bst_ipk = -1;350 hw_cfg->bst_cap = -1;351 hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH;352 hw_cfg->gpio1.valid = true;353 }354 355 hw_cfg->gpio2.func = CS35L41_INTERRUPT;356 hw_cfg->gpio2.valid = true;357 hw_cfg->valid = true;358 359 return 0;360}361 362/*363 * Systems 103C8C66, 103C8C67, 103C8C68, 103C8C6A use a dual speaker id system - each speaker has364 * its own speaker id.365 */366static int hp_i2c_int_2amp_dual_spkid(struct cs35l41_hda *cs35l41, struct device *physdev, int id,367 const char *hid)368{369 struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;370 371 /* If _DSD exists for this laptop, we cannot support it through here */372 if (acpi_dev_has_props(cs35l41->dacpi))373 return -ENOENT;374 375 /* check I2C address to assign the index */376 cs35l41->index = id == 0x40 ? 0 : 1;377 cs35l41->channel_index = 0;378 cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);379 if (cs35l41->index == 0)380 cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 1);381 else382 cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2);383 hw_cfg->spk_pos = cs35l41->index;384 hw_cfg->gpio2.func = CS35L41_INTERRUPT;385 hw_cfg->gpio2.valid = true;386 hw_cfg->valid = true;387 388 hw_cfg->bst_type = CS35L41_INT_BOOST;389 hw_cfg->bst_ind = 1000;390 hw_cfg->bst_ipk = 4100;391 hw_cfg->bst_cap = 24;392 hw_cfg->gpio1.func = CS35L41_NOT_USED;393 hw_cfg->gpio1.valid = true;394 395 return 0;396}397 398/*399 * Device CLSA010(0/1) doesn't have _DSD so a gpiod_get by the label reset won't work.400 * And devices created by serial-multi-instantiate don't have their device struct401 * pointing to the correct fwnode, so acpi_dev must be used here.402 * And devm functions expect that the device requesting the resource has the correct403 * fwnode.404 */405static int lenovo_legion_no_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id,406 const char *hid)407{408 struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;409 410 /* check I2C address to assign the index */411 cs35l41->index = id == 0x40 ? 0 : 1;412 cs35l41->channel_index = 0;413 cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);414 cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2);415 hw_cfg->spk_pos = cs35l41->index;416 hw_cfg->gpio2.func = CS35L41_INTERRUPT;417 hw_cfg->gpio2.valid = true;418 hw_cfg->valid = true;419 420 if (strcmp(hid, "CLSA0100") == 0) {421 hw_cfg->bst_type = CS35L41_EXT_BOOST_NO_VSPK_SWITCH;422 } else if (strcmp(hid, "CLSA0101") == 0) {423 hw_cfg->bst_type = CS35L41_EXT_BOOST;424 hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH;425 hw_cfg->gpio1.valid = true;426 }427 428 return 0;429}430 431static int missing_speaker_id_gpio2(struct cs35l41_hda *cs35l41, struct device *physdev, int id,432 const char *hid)433{434 int ret;435 436 ret = cs35l41_add_gpios(cs35l41, physdev, -1, 2, -1, 2);437 if (ret) {438 dev_err(cs35l41->dev, "Error adding GPIO mapping: %d\n", ret);439 return ret;440 }441 442 return cs35l41_hda_parse_acpi(cs35l41, physdev, id);443}444 445struct cs35l41_prop_model {446 const char *hid;447 const char *ssid;448 int (*add_prop)(struct cs35l41_hda *cs35l41, struct device *physdev, int id,449 const char *hid);450};451 452static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {453 { "CLSA0100", NULL, lenovo_legion_no_acpi },454 { "CLSA0101", NULL, lenovo_legion_no_acpi },455 { "CSC3551", "10280B27", generic_dsd_config },456 { "CSC3551", "10280B28", generic_dsd_config },457 { "CSC3551", "10280BEB", generic_dsd_config },458 { "CSC3551", "10280C4D", generic_dsd_config },459 { "CSC3551", "103C89C6", generic_dsd_config },460 { "CSC3551", "103C8A28", generic_dsd_config },461 { "CSC3551", "103C8A29", generic_dsd_config },462 { "CSC3551", "103C8A2A", generic_dsd_config },463 { "CSC3551", "103C8A2B", generic_dsd_config },464 { "CSC3551", "103C8A2C", generic_dsd_config },465 { "CSC3551", "103C8A2D", generic_dsd_config },466 { "CSC3551", "103C8A2E", generic_dsd_config },467 { "CSC3551", "103C8A30", generic_dsd_config },468 { "CSC3551", "103C8A31", generic_dsd_config },469 { "CSC3551", "103C8A6E", generic_dsd_config },470 { "CSC3551", "103C8BB3", generic_dsd_config },471 { "CSC3551", "103C8BB4", generic_dsd_config },472 { "CSC3551", "103C8BDD", generic_dsd_config },473 { "CSC3551", "103C8BDE", generic_dsd_config },474 { "CSC3551", "103C8BDF", generic_dsd_config },475 { "CSC3551", "103C8BE0", generic_dsd_config },476 { "CSC3551", "103C8BE1", generic_dsd_config },477 { "CSC3551", "103C8BE2", generic_dsd_config },478 { "CSC3551", "103C8BE3", generic_dsd_config },479 { "CSC3551", "103C8BE5", generic_dsd_config },480 { "CSC3551", "103C8BE6", generic_dsd_config },481 { "CSC3551", "103C8BE7", generic_dsd_config },482 { "CSC3551", "103C8BE8", generic_dsd_config },483 { "CSC3551", "103C8BE9", generic_dsd_config },484 { "CSC3551", "103C8B3A", generic_dsd_config },485 { "CSC3551", "103C8C15", generic_dsd_config },486 { "CSC3551", "103C8C16", generic_dsd_config },487 { "CSC3551", "103C8C17", generic_dsd_config },488 { "CSC3551", "103C8C4D", generic_dsd_config },489 { "CSC3551", "103C8C4E", generic_dsd_config },490 { "CSC3551", "103C8C4F", generic_dsd_config },491 { "CSC3551", "103C8C50", generic_dsd_config },492 { "CSC3551", "103C8C51", generic_dsd_config },493 { "CSC3551", "103C8C66", hp_i2c_int_2amp_dual_spkid },494 { "CSC3551", "103C8C67", hp_i2c_int_2amp_dual_spkid },495 { "CSC3551", "103C8C68", hp_i2c_int_2amp_dual_spkid },496 { "CSC3551", "103C8C6A", hp_i2c_int_2amp_dual_spkid },497 { "CSC3551", "103C8CDD", generic_dsd_config },498 { "CSC3551", "103C8CDE", generic_dsd_config },499 { "CSC3551", "104312AF", generic_dsd_config },500 { "CSC3551", "10431433", generic_dsd_config },501 { "CSC3551", "10431463", generic_dsd_config },502 { "CSC3551", "10431473", generic_dsd_config },503 { "CSC3551", "10431483", generic_dsd_config },504 { "CSC3551", "10431493", generic_dsd_config },505 { "CSC3551", "104314D3", generic_dsd_config },506 { "CSC3551", "104314E3", generic_dsd_config },507 { "CSC3551", "10431503", generic_dsd_config },508 { "CSC3551", "10431533", generic_dsd_config },509 { "CSC3551", "10431573", generic_dsd_config },510 { "CSC3551", "10431663", generic_dsd_config },511 { "CSC3551", "10431683", generic_dsd_config },512 { "CSC3551", "104316A3", generic_dsd_config },513 { "CSC3551", "104316D3", generic_dsd_config },514 { "CSC3551", "104316F3", generic_dsd_config },515 { "CSC3551", "104317F3", generic_dsd_config },516 { "CSC3551", "10431863", generic_dsd_config },517 { "CSC3551", "104318D3", generic_dsd_config },518 { "CSC3551", "10431A63", missing_speaker_id_gpio2 },519 { "CSC3551", "10431A83", generic_dsd_config },520 { "CSC3551", "10431B93", generic_dsd_config },521 { "CSC3551", "10431C9F", generic_dsd_config },522 { "CSC3551", "10431CAF", generic_dsd_config },523 { "CSC3551", "10431CCF", generic_dsd_config },524 { "CSC3551", "10431CDF", generic_dsd_config },525 { "CSC3551", "10431CEF", generic_dsd_config },526 { "CSC3551", "10431D1F", generic_dsd_config },527 { "CSC3551", "10431DA2", generic_dsd_config },528 { "CSC3551", "10431E02", generic_dsd_config },529 { "CSC3551", "10431E12", generic_dsd_config },530 { "CSC3551", "10431EE2", generic_dsd_config },531 { "CSC3551", "10431F12", generic_dsd_config },532 { "CSC3551", "10431F1F", generic_dsd_config },533 { "CSC3551", "10431F62", generic_dsd_config },534 { "CSC3551", "10433A20", generic_dsd_config },535 { "CSC3551", "10433A30", generic_dsd_config },536 { "CSC3551", "10433A40", generic_dsd_config },537 { "CSC3551", "10433A50", generic_dsd_config },538 { "CSC3551", "10433A60", generic_dsd_config },539 { "CSC3551", "17AA3865", generic_dsd_config },540 { "CSC3551", "17AA3866", generic_dsd_config },541 { "CSC3551", "17AA386E", generic_dsd_config },542 { "CSC3551", "17AA386F", generic_dsd_config },543 { "CSC3551", "17AA3877", generic_dsd_config },544 { "CSC3551", "17AA3878", generic_dsd_config },545 { "CSC3551", "17AA38A9", generic_dsd_config },546 { "CSC3551", "17AA38AB", generic_dsd_config },547 { "CSC3551", "17AA38B4", generic_dsd_config },548 { "CSC3551", "17AA38B5", generic_dsd_config },549 { "CSC3551", "17AA38B6", generic_dsd_config },550 { "CSC3551", "17AA38B7", generic_dsd_config },551 { "CSC3551", "17AA38C7", generic_dsd_config },552 { "CSC3551", "17AA38C8", generic_dsd_config },553 { "CSC3551", "17AA38F9", generic_dsd_config },554 { "CSC3551", "17AA38FA", generic_dsd_config },555 {}556};557 558int cs35l41_add_dsd_properties(struct cs35l41_hda *cs35l41, struct device *physdev, int id,559 const char *hid)560{561 const struct cs35l41_prop_model *model;562 563 for (model = cs35l41_prop_model_table; model->hid; model++) {564 if (!strcmp(model->hid, hid) &&565 (!model->ssid ||566 (cs35l41->acpi_subsystem_id &&567 !strcasecmp(model->ssid, cs35l41->acpi_subsystem_id))))568 return model->add_prop(cs35l41, physdev, id, hid);569 }570 571 return -ENOENT;572}573