| 1 | // SPDX-License-Identifier: GPL-2.0-only | 
|---|
| 2 | /* | 
|---|
| 3 | * HD-audio codec core device | 
|---|
| 4 | */ | 
|---|
| 5 |  | 
|---|
| 6 | #include <linux/init.h> | 
|---|
| 7 | #include <linux/delay.h> | 
|---|
| 8 | #include <linux/device.h> | 
|---|
| 9 | #include <linux/slab.h> | 
|---|
| 10 | #include <linux/module.h> | 
|---|
| 11 | #include <linux/export.h> | 
|---|
| 12 | #include <linux/pm_runtime.h> | 
|---|
| 13 | #include <sound/hdaudio.h> | 
|---|
| 14 | #include <sound/hda_regmap.h> | 
|---|
| 15 | #include <sound/pcm.h> | 
|---|
| 16 | #include <sound/pcm_params.h> | 
|---|
| 17 | #include "local.h" | 
|---|
| 18 |  | 
|---|
| 19 | static void setup_fg_nodes(struct hdac_device *codec); | 
|---|
| 20 | static int get_codec_vendor_name(struct hdac_device *codec); | 
|---|
| 21 |  | 
|---|
| 22 | static void default_release(struct device *dev) | 
|---|
| 23 | { | 
|---|
| 24 | snd_hdac_device_exit(dev_to_hdac_dev(dev)); | 
|---|
| 25 | } | 
|---|
| 26 |  | 
|---|
| 27 | /** | 
|---|
| 28 | * snd_hdac_device_init - initialize the HD-audio codec base device | 
|---|
| 29 | * @codec: device to initialize | 
|---|
| 30 | * @bus: but to attach | 
|---|
| 31 | * @name: device name string | 
|---|
| 32 | * @addr: codec address | 
|---|
| 33 | * | 
|---|
| 34 | * Returns zero for success or a negative error code. | 
|---|
| 35 | * | 
|---|
| 36 | * This function increments the runtime PM counter and marks it active. | 
|---|
| 37 | * The caller needs to turn it off appropriately later. | 
|---|
| 38 | * | 
|---|
| 39 | * The caller needs to set the device's release op properly by itself. | 
|---|
| 40 | */ | 
|---|
| 41 | int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus, | 
|---|
| 42 | const char *name, unsigned int addr) | 
|---|
| 43 | { | 
|---|
| 44 | struct device *dev; | 
|---|
| 45 | hda_nid_t fg; | 
|---|
| 46 | int err; | 
|---|
| 47 |  | 
|---|
| 48 | dev = &codec->dev; | 
|---|
| 49 | device_initialize(dev); | 
|---|
| 50 | dev->parent = bus->dev; | 
|---|
| 51 | dev->bus = &snd_hda_bus_type; | 
|---|
| 52 | dev->release = default_release; | 
|---|
| 53 | dev->groups = hdac_dev_attr_groups; | 
|---|
| 54 | dev_set_name(dev, name: "%s", name); | 
|---|
| 55 | device_enable_async_suspend(dev); | 
|---|
| 56 |  | 
|---|
| 57 | codec->bus = bus; | 
|---|
| 58 | codec->addr = addr; | 
|---|
| 59 | codec->type = HDA_DEV_CORE; | 
|---|
| 60 | mutex_init(&codec->widget_lock); | 
|---|
| 61 | mutex_init(&codec->regmap_lock); | 
|---|
| 62 | pm_runtime_set_active(dev: &codec->dev); | 
|---|
| 63 | pm_runtime_get_noresume(dev: &codec->dev); | 
|---|
| 64 | atomic_set(v: &codec->in_pm, i: 0); | 
|---|
| 65 |  | 
|---|
| 66 | err = snd_hdac_bus_add_device(bus, codec); | 
|---|
| 67 | if (err < 0) | 
|---|
| 68 | goto error; | 
|---|
| 69 |  | 
|---|
| 70 | /* fill parameters */ | 
|---|
| 71 | codec->vendor_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, | 
|---|
| 72 | AC_PAR_VENDOR_ID); | 
|---|
| 73 | if (codec->vendor_id == -1) { | 
|---|
| 74 | /* read again, hopefully the access method was corrected | 
|---|
| 75 | * in the last read... | 
|---|
| 76 | */ | 
|---|
| 77 | codec->vendor_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, | 
|---|
| 78 | AC_PAR_VENDOR_ID); | 
|---|
| 79 | } | 
|---|
| 80 |  | 
|---|
| 81 | codec->subsystem_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, | 
|---|
| 82 | AC_PAR_SUBSYSTEM_ID); | 
|---|
| 83 | codec->revision_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, | 
|---|
| 84 | AC_PAR_REV_ID); | 
|---|
| 85 |  | 
|---|
| 86 | setup_fg_nodes(codec); | 
|---|
| 87 | if (!codec->afg && !codec->mfg) { | 
|---|
| 88 | dev_err(dev, "no AFG or MFG node found\n"); | 
|---|
| 89 | err = -ENODEV; | 
|---|
| 90 | goto error; | 
|---|
| 91 | } | 
|---|
| 92 |  | 
|---|
| 93 | fg = codec->afg ? codec->afg : codec->mfg; | 
|---|
| 94 |  | 
|---|
| 95 | err = snd_hdac_refresh_widgets(codec); | 
|---|
| 96 | if (err < 0) | 
|---|
| 97 | goto error; | 
|---|
| 98 |  | 
|---|
| 99 | codec->power_caps = snd_hdac_read_parm(codec, nid: fg, AC_PAR_POWER_STATE); | 
|---|
| 100 | /* reread ssid if not set by parameter */ | 
|---|
| 101 | if (codec->subsystem_id == -1 || codec->subsystem_id == 0) | 
|---|
| 102 | snd_hdac_read(codec, nid: fg, AC_VERB_GET_SUBSYSTEM_ID, parm: 0, | 
|---|
| 103 | res: &codec->subsystem_id); | 
|---|
| 104 |  | 
|---|
| 105 | err = get_codec_vendor_name(codec); | 
|---|
| 106 | if (err < 0) | 
|---|
| 107 | goto error; | 
|---|
| 108 |  | 
|---|
| 109 | codec->chip_name = kasprintf(GFP_KERNEL, fmt: "ID %x", | 
|---|
| 110 | codec->vendor_id & 0xffff); | 
|---|
| 111 | if (!codec->chip_name) { | 
|---|
| 112 | err = -ENOMEM; | 
|---|
| 113 | goto error; | 
|---|
| 114 | } | 
|---|
| 115 |  | 
|---|
| 116 | return 0; | 
|---|
| 117 |  | 
|---|
| 118 | error: | 
|---|
| 119 | put_device(dev: &codec->dev); | 
|---|
| 120 | return err; | 
|---|
| 121 | } | 
|---|
| 122 | EXPORT_SYMBOL_GPL(snd_hdac_device_init); | 
|---|
| 123 |  | 
|---|
| 124 | /** | 
|---|
| 125 | * snd_hdac_device_exit - clean up the HD-audio codec base device | 
|---|
| 126 | * @codec: device to clean up | 
|---|
| 127 | */ | 
|---|
| 128 | void snd_hdac_device_exit(struct hdac_device *codec) | 
|---|
| 129 | { | 
|---|
| 130 | pm_runtime_put_noidle(dev: &codec->dev); | 
|---|
| 131 | /* keep balance of runtime PM child_count in parent device */ | 
|---|
| 132 | pm_runtime_set_suspended(dev: &codec->dev); | 
|---|
| 133 | snd_hdac_bus_remove_device(bus: codec->bus, codec); | 
|---|
| 134 | kfree(objp: codec->vendor_name); | 
|---|
| 135 | kfree(objp: codec->chip_name); | 
|---|
| 136 | } | 
|---|
| 137 | EXPORT_SYMBOL_GPL(snd_hdac_device_exit); | 
|---|
| 138 |  | 
|---|
| 139 | /** | 
|---|
| 140 | * snd_hdac_device_register - register the hd-audio codec base device | 
|---|
| 141 | * @codec: the device to register | 
|---|
| 142 | */ | 
|---|
| 143 | int snd_hdac_device_register(struct hdac_device *codec) | 
|---|
| 144 | { | 
|---|
| 145 | int err; | 
|---|
| 146 |  | 
|---|
| 147 | err = device_add(dev: &codec->dev); | 
|---|
| 148 | if (err < 0) | 
|---|
| 149 | return err; | 
|---|
| 150 | scoped_guard(mutex, &codec->widget_lock) { | 
|---|
| 151 | err = hda_widget_sysfs_init(codec); | 
|---|
| 152 | } | 
|---|
| 153 | if (err < 0) { | 
|---|
| 154 | device_del(dev: &codec->dev); | 
|---|
| 155 | return err; | 
|---|
| 156 | } | 
|---|
| 157 |  | 
|---|
| 158 | return 0; | 
|---|
| 159 | } | 
|---|
| 160 | EXPORT_SYMBOL_GPL(snd_hdac_device_register); | 
|---|
| 161 |  | 
|---|
| 162 | /** | 
|---|
| 163 | * snd_hdac_device_unregister - unregister the hd-audio codec base device | 
|---|
| 164 | * @codec: the device to unregister | 
|---|
| 165 | */ | 
|---|
| 166 | void snd_hdac_device_unregister(struct hdac_device *codec) | 
|---|
| 167 | { | 
|---|
| 168 | if (device_is_registered(dev: &codec->dev)) { | 
|---|
| 169 | scoped_guard(mutex, &codec->widget_lock) { | 
|---|
| 170 | hda_widget_sysfs_exit(codec); | 
|---|
| 171 | } | 
|---|
| 172 | device_del(dev: &codec->dev); | 
|---|
| 173 | snd_hdac_bus_remove_device(bus: codec->bus, codec); | 
|---|
| 174 | } | 
|---|
| 175 | } | 
|---|
| 176 | EXPORT_SYMBOL_GPL(snd_hdac_device_unregister); | 
|---|
| 177 |  | 
|---|
| 178 | /** | 
|---|
| 179 | * snd_hdac_device_set_chip_name - set/update the codec name | 
|---|
| 180 | * @codec: the HDAC device | 
|---|
| 181 | * @name: name string to set | 
|---|
| 182 | * | 
|---|
| 183 | * Returns 0 if the name is set or updated, or a negative error code. | 
|---|
| 184 | */ | 
|---|
| 185 | int snd_hdac_device_set_chip_name(struct hdac_device *codec, const char *name) | 
|---|
| 186 | { | 
|---|
| 187 | char *newname; | 
|---|
| 188 |  | 
|---|
| 189 | if (!name) | 
|---|
| 190 | return 0; | 
|---|
| 191 | newname = kstrdup(s: name, GFP_KERNEL); | 
|---|
| 192 | if (!newname) | 
|---|
| 193 | return -ENOMEM; | 
|---|
| 194 | kfree(objp: codec->chip_name); | 
|---|
| 195 | codec->chip_name = newname; | 
|---|
| 196 | return 0; | 
|---|
| 197 | } | 
|---|
| 198 | EXPORT_SYMBOL_GPL(snd_hdac_device_set_chip_name); | 
|---|
| 199 |  | 
|---|
| 200 | /** | 
|---|
| 201 | * snd_hdac_codec_modalias - give the module alias name | 
|---|
| 202 | * @codec: HDAC device | 
|---|
| 203 | * @buf: string buffer to store | 
|---|
| 204 | * @size: string buffer size | 
|---|
| 205 | * | 
|---|
| 206 | * Returns the size of string, like snprintf(), or a negative error code. | 
|---|
| 207 | */ | 
|---|
| 208 | int snd_hdac_codec_modalias(const struct hdac_device *codec, char *buf, size_t size) | 
|---|
| 209 | { | 
|---|
| 210 | return scnprintf(buf, size, fmt: "hdaudio:v%08Xr%08Xa%02X\n", | 
|---|
| 211 | codec->vendor_id, codec->revision_id, codec->type); | 
|---|
| 212 | } | 
|---|
| 213 | EXPORT_SYMBOL_GPL(snd_hdac_codec_modalias); | 
|---|
| 214 |  | 
|---|
| 215 | /** | 
|---|
| 216 | * snd_hdac_make_cmd - compose a 32bit command word to be sent to the | 
|---|
| 217 | *	HD-audio controller | 
|---|
| 218 | * @codec: the codec object | 
|---|
| 219 | * @nid: NID to encode | 
|---|
| 220 | * @verb: verb to encode | 
|---|
| 221 | * @parm: parameter to encode | 
|---|
| 222 | * | 
|---|
| 223 | * Return an encoded command verb or -1 for error. | 
|---|
| 224 | */ | 
|---|
| 225 | static unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid, | 
|---|
| 226 | unsigned int verb, unsigned int parm) | 
|---|
| 227 | { | 
|---|
| 228 | u32 val, addr; | 
|---|
| 229 |  | 
|---|
| 230 | addr = codec->addr; | 
|---|
| 231 | if ((addr & ~0xf) || (nid & ~0x7f) || | 
|---|
| 232 | (verb & ~0xfff) || (parm & ~0xffff)) { | 
|---|
| 233 | dev_err(&codec->dev, "out of range cmd %x:%x:%x:%x\n", | 
|---|
| 234 | addr, nid, verb, parm); | 
|---|
| 235 | return -1; | 
|---|
| 236 | } | 
|---|
| 237 |  | 
|---|
| 238 | val = addr << 28; | 
|---|
| 239 | val |= (u32)nid << 20; | 
|---|
| 240 | val |= verb << 8; | 
|---|
| 241 | val |= parm; | 
|---|
| 242 | return val; | 
|---|
| 243 | } | 
|---|
| 244 |  | 
|---|
| 245 | /** | 
|---|
| 246 | * snd_hdac_exec_verb - execute an encoded verb | 
|---|
| 247 | * @codec: the codec object | 
|---|
| 248 | * @cmd: encoded verb to execute | 
|---|
| 249 | * @flags: optional flags, pass zero for default | 
|---|
| 250 | * @res: the pointer to store the result, NULL if running async | 
|---|
| 251 | * | 
|---|
| 252 | * Returns zero if successful, or a negative error code. | 
|---|
| 253 | * | 
|---|
| 254 | * This calls the exec_verb op when set in hdac_codec.  If not, | 
|---|
| 255 | * call the default snd_hdac_bus_exec_verb(). | 
|---|
| 256 | */ | 
|---|
| 257 | int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd, | 
|---|
| 258 | unsigned int flags, unsigned int *res) | 
|---|
| 259 | { | 
|---|
| 260 | if (codec->exec_verb) | 
|---|
| 261 | return codec->exec_verb(codec, cmd, flags, res); | 
|---|
| 262 | return snd_hdac_bus_exec_verb(bus: codec->bus, addr: codec->addr, cmd, res); | 
|---|
| 263 | } | 
|---|
| 264 |  | 
|---|
| 265 |  | 
|---|
| 266 | /** | 
|---|
| 267 | * snd_hdac_read - execute a verb | 
|---|
| 268 | * @codec: the codec object | 
|---|
| 269 | * @nid: NID to execute a verb | 
|---|
| 270 | * @verb: verb to execute | 
|---|
| 271 | * @parm: parameter for a verb | 
|---|
| 272 | * @res: the pointer to store the result, NULL if running async | 
|---|
| 273 | * | 
|---|
| 274 | * Returns zero if successful, or a negative error code. | 
|---|
| 275 | */ | 
|---|
| 276 | int snd_hdac_read(struct hdac_device *codec, hda_nid_t nid, | 
|---|
| 277 | unsigned int verb, unsigned int parm, unsigned int *res) | 
|---|
| 278 | { | 
|---|
| 279 | unsigned int cmd = snd_hdac_make_cmd(codec, nid, verb, parm); | 
|---|
| 280 |  | 
|---|
| 281 | return snd_hdac_exec_verb(codec, cmd, flags: 0, res); | 
|---|
| 282 | } | 
|---|
| 283 | EXPORT_SYMBOL_GPL(snd_hdac_read); | 
|---|
| 284 |  | 
|---|
| 285 | /** | 
|---|
| 286 | * _snd_hdac_read_parm - read a parmeter | 
|---|
| 287 | * @codec: the codec object | 
|---|
| 288 | * @nid: NID to read a parameter | 
|---|
| 289 | * @parm: parameter to read | 
|---|
| 290 | * @res: pointer to store the read value | 
|---|
| 291 | * | 
|---|
| 292 | * This function returns zero or an error unlike snd_hdac_read_parm(). | 
|---|
| 293 | */ | 
|---|
| 294 | int _snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm, | 
|---|
| 295 | unsigned int *res) | 
|---|
| 296 | { | 
|---|
| 297 | unsigned int cmd; | 
|---|
| 298 |  | 
|---|
| 299 | cmd = snd_hdac_regmap_encode_verb(nid, AC_VERB_PARAMETERS) | parm; | 
|---|
| 300 | return snd_hdac_regmap_read_raw(codec, reg: cmd, val: res); | 
|---|
| 301 | } | 
|---|
| 302 | EXPORT_SYMBOL_GPL(_snd_hdac_read_parm); | 
|---|
| 303 |  | 
|---|
| 304 | /** | 
|---|
| 305 | * snd_hdac_read_parm_uncached - read a codec parameter without caching | 
|---|
| 306 | * @codec: the codec object | 
|---|
| 307 | * @nid: NID to read a parameter | 
|---|
| 308 | * @parm: parameter to read | 
|---|
| 309 | * | 
|---|
| 310 | * Returns -1 for error.  If you need to distinguish the error more | 
|---|
| 311 | * strictly, use snd_hdac_read() directly. | 
|---|
| 312 | */ | 
|---|
| 313 | int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid, | 
|---|
| 314 | int parm) | 
|---|
| 315 | { | 
|---|
| 316 | unsigned int cmd, val; | 
|---|
| 317 |  | 
|---|
| 318 | cmd = snd_hdac_regmap_encode_verb(nid, AC_VERB_PARAMETERS) | parm; | 
|---|
| 319 | if (snd_hdac_regmap_read_raw_uncached(codec, reg: cmd, val: &val) < 0) | 
|---|
| 320 | return -1; | 
|---|
| 321 | return val; | 
|---|
| 322 | } | 
|---|
| 323 | EXPORT_SYMBOL_GPL(snd_hdac_read_parm_uncached); | 
|---|
| 324 |  | 
|---|
| 325 | /** | 
|---|
| 326 | * snd_hdac_override_parm - override read-only parameters | 
|---|
| 327 | * @codec: the codec object | 
|---|
| 328 | * @nid: NID for the parameter | 
|---|
| 329 | * @parm: the parameter to change | 
|---|
| 330 | * @val: the parameter value to overwrite | 
|---|
| 331 | */ | 
|---|
| 332 | int snd_hdac_override_parm(struct hdac_device *codec, hda_nid_t nid, | 
|---|
| 333 | unsigned int parm, unsigned int val) | 
|---|
| 334 | { | 
|---|
| 335 | unsigned int verb = (AC_VERB_PARAMETERS << 8) | (nid << 20) | parm; | 
|---|
| 336 | int err; | 
|---|
| 337 |  | 
|---|
| 338 | if (!codec->regmap) | 
|---|
| 339 | return -EINVAL; | 
|---|
| 340 |  | 
|---|
| 341 | codec->caps_overwriting = true; | 
|---|
| 342 | err = snd_hdac_regmap_write_raw(codec, reg: verb, val); | 
|---|
| 343 | codec->caps_overwriting = false; | 
|---|
| 344 | return err; | 
|---|
| 345 | } | 
|---|
| 346 | EXPORT_SYMBOL_GPL(snd_hdac_override_parm); | 
|---|
| 347 |  | 
|---|
| 348 | /** | 
|---|
| 349 | * snd_hdac_get_sub_nodes - get start NID and number of subtree nodes | 
|---|
| 350 | * @codec: the codec object | 
|---|
| 351 | * @nid: NID to inspect | 
|---|
| 352 | * @start_id: the pointer to store the starting NID | 
|---|
| 353 | * | 
|---|
| 354 | * Returns the number of subtree nodes or zero if not found. | 
|---|
| 355 | * This function reads parameters always without caching. | 
|---|
| 356 | */ | 
|---|
| 357 | int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid, | 
|---|
| 358 | hda_nid_t *start_id) | 
|---|
| 359 | { | 
|---|
| 360 | unsigned int parm; | 
|---|
| 361 |  | 
|---|
| 362 | parm = snd_hdac_read_parm_uncached(codec, nid, AC_PAR_NODE_COUNT); | 
|---|
| 363 | if (parm == -1) { | 
|---|
| 364 | *start_id = 0; | 
|---|
| 365 | return 0; | 
|---|
| 366 | } | 
|---|
| 367 | *start_id = (parm >> 16) & 0x7fff; | 
|---|
| 368 | return (int)(parm & 0x7fff); | 
|---|
| 369 | } | 
|---|
| 370 | EXPORT_SYMBOL_GPL(snd_hdac_get_sub_nodes); | 
|---|
| 371 |  | 
|---|
| 372 | /* | 
|---|
| 373 | * look for an AFG and MFG nodes | 
|---|
| 374 | */ | 
|---|
| 375 | static void setup_fg_nodes(struct hdac_device *codec) | 
|---|
| 376 | { | 
|---|
| 377 | int i, total_nodes, function_id; | 
|---|
| 378 | hda_nid_t nid; | 
|---|
| 379 |  | 
|---|
| 380 | total_nodes = snd_hdac_get_sub_nodes(codec, AC_NODE_ROOT, &nid); | 
|---|
| 381 | for (i = 0; i < total_nodes; i++, nid++) { | 
|---|
| 382 | function_id = snd_hdac_read_parm(codec, nid, | 
|---|
| 383 | AC_PAR_FUNCTION_TYPE); | 
|---|
| 384 | switch (function_id & 0xff) { | 
|---|
| 385 | case AC_GRP_AUDIO_FUNCTION: | 
|---|
| 386 | codec->afg = nid; | 
|---|
| 387 | codec->afg_function_id = function_id & 0xff; | 
|---|
| 388 | codec->afg_unsol = (function_id >> 8) & 1; | 
|---|
| 389 | break; | 
|---|
| 390 | case AC_GRP_MODEM_FUNCTION: | 
|---|
| 391 | codec->mfg = nid; | 
|---|
| 392 | codec->mfg_function_id = function_id & 0xff; | 
|---|
| 393 | codec->mfg_unsol = (function_id >> 8) & 1; | 
|---|
| 394 | break; | 
|---|
| 395 | default: | 
|---|
| 396 | break; | 
|---|
| 397 | } | 
|---|
| 398 | } | 
|---|
| 399 | } | 
|---|
| 400 |  | 
|---|
| 401 | /** | 
|---|
| 402 | * snd_hdac_refresh_widgets - Reset the widget start/end nodes | 
|---|
| 403 | * @codec: the codec object | 
|---|
| 404 | */ | 
|---|
| 405 | int snd_hdac_refresh_widgets(struct hdac_device *codec) | 
|---|
| 406 | { | 
|---|
| 407 | hda_nid_t start_nid; | 
|---|
| 408 | int nums, err = 0; | 
|---|
| 409 |  | 
|---|
| 410 | /* | 
|---|
| 411 | * Serialize against multiple threads trying to update the sysfs | 
|---|
| 412 | * widgets array. | 
|---|
| 413 | */ | 
|---|
| 414 | guard(mutex)(T: &codec->widget_lock); | 
|---|
| 415 | nums = snd_hdac_get_sub_nodes(codec, codec->afg, &start_nid); | 
|---|
| 416 | if (!start_nid || nums <= 0 || nums >= 0xff) { | 
|---|
| 417 | dev_err(&codec->dev, "cannot read sub nodes for FG 0x%02x\n", | 
|---|
| 418 | codec->afg); | 
|---|
| 419 | return -EINVAL; | 
|---|
| 420 | } | 
|---|
| 421 |  | 
|---|
| 422 | err = hda_widget_sysfs_reinit(codec, start_nid, num_nodes: nums); | 
|---|
| 423 | if (err < 0) | 
|---|
| 424 | return err; | 
|---|
| 425 |  | 
|---|
| 426 | codec->num_nodes = nums; | 
|---|
| 427 | codec->start_nid = start_nid; | 
|---|
| 428 | codec->end_nid = start_nid + nums; | 
|---|
| 429 | return 0; | 
|---|
| 430 | } | 
|---|
| 431 | EXPORT_SYMBOL_GPL(snd_hdac_refresh_widgets); | 
|---|
| 432 |  | 
|---|
| 433 | /* return CONNLIST_LEN parameter of the given widget */ | 
|---|
| 434 | static unsigned int get_num_conns(struct hdac_device *codec, hda_nid_t nid) | 
|---|
| 435 | { | 
|---|
| 436 | unsigned int wcaps = snd_hdac_get_wcaps(codec, nid); | 
|---|
| 437 | unsigned int parm; | 
|---|
| 438 |  | 
|---|
| 439 | if (!(wcaps & AC_WCAP_CONN_LIST) && | 
|---|
| 440 | snd_hdac_get_wcaps_type(wcaps) != AC_WID_VOL_KNB) | 
|---|
| 441 | return 0; | 
|---|
| 442 |  | 
|---|
| 443 | parm = snd_hdac_read_parm(codec, nid, AC_PAR_CONNLIST_LEN); | 
|---|
| 444 | if (parm == -1) | 
|---|
| 445 | parm = 0; | 
|---|
| 446 | return parm; | 
|---|
| 447 | } | 
|---|
| 448 |  | 
|---|
| 449 | /** | 
|---|
| 450 | * snd_hdac_get_connections - get a widget connection list | 
|---|
| 451 | * @codec: the codec object | 
|---|
| 452 | * @nid: NID | 
|---|
| 453 | * @conn_list: the array to store the results, can be NULL | 
|---|
| 454 | * @max_conns: the max size of the given array | 
|---|
| 455 | * | 
|---|
| 456 | * Returns the number of connected widgets, zero for no connection, or a | 
|---|
| 457 | * negative error code.  When the number of elements don't fit with the | 
|---|
| 458 | * given array size, it returns -ENOSPC. | 
|---|
| 459 | * | 
|---|
| 460 | * When @conn_list is NULL, it just checks the number of connections. | 
|---|
| 461 | */ | 
|---|
| 462 | int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid, | 
|---|
| 463 | hda_nid_t *conn_list, int max_conns) | 
|---|
| 464 | { | 
|---|
| 465 | unsigned int parm; | 
|---|
| 466 | int i, conn_len, conns, err; | 
|---|
| 467 | unsigned int shift, num_elems, mask; | 
|---|
| 468 | hda_nid_t prev_nid; | 
|---|
| 469 | int null_count = 0; | 
|---|
| 470 |  | 
|---|
| 471 | parm = get_num_conns(codec, nid); | 
|---|
| 472 | if (!parm) | 
|---|
| 473 | return 0; | 
|---|
| 474 |  | 
|---|
| 475 | if (parm & AC_CLIST_LONG) { | 
|---|
| 476 | /* long form */ | 
|---|
| 477 | shift = 16; | 
|---|
| 478 | num_elems = 2; | 
|---|
| 479 | } else { | 
|---|
| 480 | /* short form */ | 
|---|
| 481 | shift = 8; | 
|---|
| 482 | num_elems = 4; | 
|---|
| 483 | } | 
|---|
| 484 | conn_len = parm & AC_CLIST_LENGTH; | 
|---|
| 485 | mask = (1 << (shift-1)) - 1; | 
|---|
| 486 |  | 
|---|
| 487 | if (!conn_len) | 
|---|
| 488 | return 0; /* no connection */ | 
|---|
| 489 |  | 
|---|
| 490 | if (conn_len == 1) { | 
|---|
| 491 | /* single connection */ | 
|---|
| 492 | err = snd_hdac_read(codec, nid, AC_VERB_GET_CONNECT_LIST, 0, | 
|---|
| 493 | &parm); | 
|---|
| 494 | if (err < 0) | 
|---|
| 495 | return err; | 
|---|
| 496 | if (conn_list) | 
|---|
| 497 | conn_list[0] = parm & mask; | 
|---|
| 498 | return 1; | 
|---|
| 499 | } | 
|---|
| 500 |  | 
|---|
| 501 | /* multi connection */ | 
|---|
| 502 | conns = 0; | 
|---|
| 503 | prev_nid = 0; | 
|---|
| 504 | for (i = 0; i < conn_len; i++) { | 
|---|
| 505 | int range_val; | 
|---|
| 506 | hda_nid_t val, n; | 
|---|
| 507 |  | 
|---|
| 508 | if (i % num_elems == 0) { | 
|---|
| 509 | err = snd_hdac_read(codec, nid, | 
|---|
| 510 | AC_VERB_GET_CONNECT_LIST, i, | 
|---|
| 511 | &parm); | 
|---|
| 512 | if (err < 0) | 
|---|
| 513 | return -EIO; | 
|---|
| 514 | } | 
|---|
| 515 | range_val = !!(parm & (1 << (shift-1))); /* ranges */ | 
|---|
| 516 | val = parm & mask; | 
|---|
| 517 | if (val == 0 && null_count++) {  /* no second chance */ | 
|---|
| 518 | dev_dbg(&codec->dev, | 
|---|
| 519 | "invalid CONNECT_LIST verb %x[%i]:%x\n", | 
|---|
| 520 | nid, i, parm); | 
|---|
| 521 | return 0; | 
|---|
| 522 | } | 
|---|
| 523 | parm >>= shift; | 
|---|
| 524 | if (range_val) { | 
|---|
| 525 | /* ranges between the previous and this one */ | 
|---|
| 526 | if (!prev_nid || prev_nid >= val) { | 
|---|
| 527 | dev_warn(&codec->dev, | 
|---|
| 528 | "invalid dep_range_val %x:%x\n", | 
|---|
| 529 | prev_nid, val); | 
|---|
| 530 | continue; | 
|---|
| 531 | } | 
|---|
| 532 | for (n = prev_nid + 1; n <= val; n++) { | 
|---|
| 533 | if (conn_list) { | 
|---|
| 534 | if (conns >= max_conns) | 
|---|
| 535 | return -ENOSPC; | 
|---|
| 536 | conn_list[conns] = n; | 
|---|
| 537 | } | 
|---|
| 538 | conns++; | 
|---|
| 539 | } | 
|---|
| 540 | } else { | 
|---|
| 541 | if (conn_list) { | 
|---|
| 542 | if (conns >= max_conns) | 
|---|
| 543 | return -ENOSPC; | 
|---|
| 544 | conn_list[conns] = val; | 
|---|
| 545 | } | 
|---|
| 546 | conns++; | 
|---|
| 547 | } | 
|---|
| 548 | prev_nid = val; | 
|---|
| 549 | } | 
|---|
| 550 | return conns; | 
|---|
| 551 | } | 
|---|
| 552 | EXPORT_SYMBOL_GPL(snd_hdac_get_connections); | 
|---|
| 553 |  | 
|---|
| 554 | #ifdef CONFIG_PM | 
|---|
| 555 | /** | 
|---|
| 556 | * snd_hdac_power_up - power up the codec | 
|---|
| 557 | * @codec: the codec object | 
|---|
| 558 | * | 
|---|
| 559 | * This function calls the runtime PM helper to power up the given codec. | 
|---|
| 560 | * Unlike snd_hdac_power_up_pm(), you should call this only for the code | 
|---|
| 561 | * path that isn't included in PM path.  Otherwise it gets stuck. | 
|---|
| 562 | * | 
|---|
| 563 | * Returns zero if successful, or a negative error code. | 
|---|
| 564 | */ | 
|---|
| 565 | int snd_hdac_power_up(struct hdac_device *codec) | 
|---|
| 566 | { | 
|---|
| 567 | return pm_runtime_get_sync(dev: &codec->dev); | 
|---|
| 568 | } | 
|---|
| 569 | EXPORT_SYMBOL_GPL(snd_hdac_power_up); | 
|---|
| 570 |  | 
|---|
| 571 | /** | 
|---|
| 572 | * snd_hdac_power_down - power down the codec | 
|---|
| 573 | * @codec: the codec object | 
|---|
| 574 | * | 
|---|
| 575 | * Returns zero if successful, or a negative error code. | 
|---|
| 576 | */ | 
|---|
| 577 | int snd_hdac_power_down(struct hdac_device *codec) | 
|---|
| 578 | { | 
|---|
| 579 | struct device *dev = &codec->dev; | 
|---|
| 580 |  | 
|---|
| 581 | return pm_runtime_put_autosuspend(dev); | 
|---|
| 582 | } | 
|---|
| 583 | EXPORT_SYMBOL_GPL(snd_hdac_power_down); | 
|---|
| 584 |  | 
|---|
| 585 | /** | 
|---|
| 586 | * snd_hdac_power_up_pm - power up the codec | 
|---|
| 587 | * @codec: the codec object | 
|---|
| 588 | * | 
|---|
| 589 | * This function can be called in a recursive code path like init code | 
|---|
| 590 | * which may be called by PM suspend/resume again.  OTOH, if a power-up | 
|---|
| 591 | * call must wake up the sleeper (e.g. in a kctl callback), use | 
|---|
| 592 | * snd_hdac_power_up() instead. | 
|---|
| 593 | * | 
|---|
| 594 | * Returns zero if successful, or a negative error code. | 
|---|
| 595 | */ | 
|---|
| 596 | int snd_hdac_power_up_pm(struct hdac_device *codec) | 
|---|
| 597 | { | 
|---|
| 598 | if (!atomic_inc_not_zero(v: &codec->in_pm)) | 
|---|
| 599 | return snd_hdac_power_up(codec); | 
|---|
| 600 | return 0; | 
|---|
| 601 | } | 
|---|
| 602 | EXPORT_SYMBOL_GPL(snd_hdac_power_up_pm); | 
|---|
| 603 |  | 
|---|
| 604 | /* like snd_hdac_power_up_pm(), but only increment the pm count when | 
|---|
| 605 | * already powered up.  Returns -1 if not powered up, 1 if incremented | 
|---|
| 606 | * or 0 if unchanged.  Only used in hdac_regmap.c | 
|---|
| 607 | */ | 
|---|
| 608 | int snd_hdac_keep_power_up(struct hdac_device *codec) | 
|---|
| 609 | { | 
|---|
| 610 | if (!atomic_inc_not_zero(v: &codec->in_pm)) { | 
|---|
| 611 | int ret = pm_runtime_get_if_active(dev: &codec->dev); | 
|---|
| 612 | if (!ret) | 
|---|
| 613 | return -1; | 
|---|
| 614 | if (ret < 0) | 
|---|
| 615 | return 0; | 
|---|
| 616 | } | 
|---|
| 617 | return 1; | 
|---|
| 618 | } | 
|---|
| 619 |  | 
|---|
| 620 | /** | 
|---|
| 621 | * snd_hdac_power_down_pm - power down the codec | 
|---|
| 622 | * @codec: the codec object | 
|---|
| 623 | * | 
|---|
| 624 | * Like snd_hdac_power_up_pm(), this function is used in a recursive | 
|---|
| 625 | * code path like init code which may be called by PM suspend/resume again. | 
|---|
| 626 | * | 
|---|
| 627 | * Returns zero if successful, or a negative error code. | 
|---|
| 628 | */ | 
|---|
| 629 | int snd_hdac_power_down_pm(struct hdac_device *codec) | 
|---|
| 630 | { | 
|---|
| 631 | if (atomic_dec_if_positive(v: &codec->in_pm) < 0) | 
|---|
| 632 | return snd_hdac_power_down(codec); | 
|---|
| 633 | return 0; | 
|---|
| 634 | } | 
|---|
| 635 | EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm); | 
|---|
| 636 | #endif | 
|---|
| 637 |  | 
|---|
| 638 | /* codec vendor labels */ | 
|---|
| 639 | struct hda_vendor_id { | 
|---|
| 640 | unsigned int id; | 
|---|
| 641 | const char *name; | 
|---|
| 642 | }; | 
|---|
| 643 |  | 
|---|
| 644 | static const struct hda_vendor_id hda_vendor_ids[] = { | 
|---|
| 645 | { 0x0014, "Loongson"}, | 
|---|
| 646 | { 0x1002, "ATI"}, | 
|---|
| 647 | { 0x1013, "Cirrus Logic"}, | 
|---|
| 648 | { 0x1057, "Motorola"}, | 
|---|
| 649 | { 0x1095, "Silicon Image"}, | 
|---|
| 650 | { 0x10de, "Nvidia"}, | 
|---|
| 651 | { 0x10ec, "Realtek"}, | 
|---|
| 652 | { 0x1102, "Creative"}, | 
|---|
| 653 | { 0x1106, "VIA"}, | 
|---|
| 654 | { 0x111d, "IDT"}, | 
|---|
| 655 | { 0x11c1, "LSI"}, | 
|---|
| 656 | { 0x11d4, "Analog Devices"}, | 
|---|
| 657 | { 0x13f6, "C-Media"}, | 
|---|
| 658 | { 0x14f1, "Conexant"}, | 
|---|
| 659 | { 0x17e8, "Chrontel"}, | 
|---|
| 660 | { 0x1854, "LG"}, | 
|---|
| 661 | { 0x19e5, "Huawei"}, | 
|---|
| 662 | { 0x1aec, "Wolfson Microelectronics"}, | 
|---|
| 663 | { 0x1af4, "QEMU"}, | 
|---|
| 664 | { 0x1fa8, "Senarytech"}, | 
|---|
| 665 | { 0x434d, "C-Media"}, | 
|---|
| 666 | { 0x8086, "Intel"}, | 
|---|
| 667 | { 0x8384, "SigmaTel"}, | 
|---|
| 668 | {} /* terminator */ | 
|---|
| 669 | }; | 
|---|
| 670 |  | 
|---|
| 671 | /* store the codec vendor name */ | 
|---|
| 672 | static int get_codec_vendor_name(struct hdac_device *codec) | 
|---|
| 673 | { | 
|---|
| 674 | const struct hda_vendor_id *c; | 
|---|
| 675 | u16 vendor_id = codec->vendor_id >> 16; | 
|---|
| 676 |  | 
|---|
| 677 | for (c = hda_vendor_ids; c->id; c++) { | 
|---|
| 678 | if (c->id == vendor_id) { | 
|---|
| 679 | codec->vendor_name = kstrdup(s: c->name, GFP_KERNEL); | 
|---|
| 680 | return codec->vendor_name ? 0 : -ENOMEM; | 
|---|
| 681 | } | 
|---|
| 682 | } | 
|---|
| 683 |  | 
|---|
| 684 | codec->vendor_name = kasprintf(GFP_KERNEL, fmt: "Generic %04x", vendor_id); | 
|---|
| 685 | return codec->vendor_name ? 0 : -ENOMEM; | 
|---|
| 686 | } | 
|---|
| 687 |  | 
|---|
| 688 | /* | 
|---|
| 689 | * stream formats | 
|---|
| 690 | */ | 
|---|
| 691 | struct hda_rate_tbl { | 
|---|
| 692 | unsigned int hz; | 
|---|
| 693 | unsigned int alsa_bits; | 
|---|
| 694 | unsigned int hda_fmt; | 
|---|
| 695 | }; | 
|---|
| 696 |  | 
|---|
| 697 | /* rate = base * mult / div */ | 
|---|
| 698 | #define HDA_RATE(base, mult, div) \ | 
|---|
| 699 | (AC_FMT_BASE_##base##K | (((mult) - 1) << AC_FMT_MULT_SHIFT) | \ | 
|---|
| 700 | (((div) - 1) << AC_FMT_DIV_SHIFT)) | 
|---|
| 701 |  | 
|---|
| 702 | static const struct hda_rate_tbl rate_bits[] = { | 
|---|
| 703 | /* rate in Hz, ALSA rate bitmask, HDA format value */ | 
|---|
| 704 |  | 
|---|
| 705 | /* autodetected value used in snd_hda_query_supported_pcm */ | 
|---|
| 706 | { 8000, SNDRV_PCM_RATE_8000, HDA_RATE(48, 1, 6) }, | 
|---|
| 707 | { 11025, SNDRV_PCM_RATE_11025, HDA_RATE(44, 1, 4) }, | 
|---|
| 708 | { 16000, SNDRV_PCM_RATE_16000, HDA_RATE(48, 1, 3) }, | 
|---|
| 709 | { 22050, SNDRV_PCM_RATE_22050, HDA_RATE(44, 1, 2) }, | 
|---|
| 710 | { 32000, SNDRV_PCM_RATE_32000, HDA_RATE(48, 2, 3) }, | 
|---|
| 711 | { 44100, SNDRV_PCM_RATE_44100, HDA_RATE(44, 1, 1) }, | 
|---|
| 712 | { 48000, SNDRV_PCM_RATE_48000, HDA_RATE(48, 1, 1) }, | 
|---|
| 713 | { 88200, SNDRV_PCM_RATE_88200, HDA_RATE(44, 2, 1) }, | 
|---|
| 714 | { 96000, SNDRV_PCM_RATE_96000, HDA_RATE(48, 2, 1) }, | 
|---|
| 715 | { 176400, SNDRV_PCM_RATE_176400, HDA_RATE(44, 4, 1) }, | 
|---|
| 716 | { 192000, SNDRV_PCM_RATE_192000, HDA_RATE(48, 4, 1) }, | 
|---|
| 717 | #define AC_PAR_PCM_RATE_BITS	11 | 
|---|
| 718 | /* up to bits 10, 384kHZ isn't supported properly */ | 
|---|
| 719 |  | 
|---|
| 720 | /* not autodetected value */ | 
|---|
| 721 | { 9600, SNDRV_PCM_RATE_KNOT, HDA_RATE(48, 1, 5) }, | 
|---|
| 722 |  | 
|---|
| 723 | { 0 } /* terminator */ | 
|---|
| 724 | }; | 
|---|
| 725 |  | 
|---|
| 726 | static snd_pcm_format_t snd_hdac_format_normalize(snd_pcm_format_t format) | 
|---|
| 727 | { | 
|---|
| 728 | switch (format) { | 
|---|
| 729 | case SNDRV_PCM_FORMAT_S20_LE: | 
|---|
| 730 | case SNDRV_PCM_FORMAT_S24_LE: | 
|---|
| 731 | return SNDRV_PCM_FORMAT_S32_LE; | 
|---|
| 732 |  | 
|---|
| 733 | case SNDRV_PCM_FORMAT_U20_LE: | 
|---|
| 734 | case SNDRV_PCM_FORMAT_U24_LE: | 
|---|
| 735 | return SNDRV_PCM_FORMAT_U32_LE; | 
|---|
| 736 |  | 
|---|
| 737 | case SNDRV_PCM_FORMAT_S20_BE: | 
|---|
| 738 | case SNDRV_PCM_FORMAT_S24_BE: | 
|---|
| 739 | return SNDRV_PCM_FORMAT_S32_BE; | 
|---|
| 740 |  | 
|---|
| 741 | case SNDRV_PCM_FORMAT_U20_BE: | 
|---|
| 742 | case SNDRV_PCM_FORMAT_U24_BE: | 
|---|
| 743 | return SNDRV_PCM_FORMAT_U32_BE; | 
|---|
| 744 |  | 
|---|
| 745 | default: | 
|---|
| 746 | return format; | 
|---|
| 747 | } | 
|---|
| 748 | } | 
|---|
| 749 |  | 
|---|
| 750 | /** | 
|---|
| 751 | * snd_hdac_stream_format_bits - obtain bits per sample value. | 
|---|
| 752 | * @format:	the PCM format. | 
|---|
| 753 | * @subformat:	the PCM subformat. | 
|---|
| 754 | * @maxbits:	the maximum bits per sample. | 
|---|
| 755 | * | 
|---|
| 756 | * Return: The number of bits per sample. | 
|---|
| 757 | */ | 
|---|
| 758 | unsigned int snd_hdac_stream_format_bits(snd_pcm_format_t format, snd_pcm_subformat_t subformat, | 
|---|
| 759 | unsigned int maxbits) | 
|---|
| 760 | { | 
|---|
| 761 | struct snd_pcm_hw_params params; | 
|---|
| 762 | unsigned int bits; | 
|---|
| 763 |  | 
|---|
| 764 | memset(s: ¶ms, c: 0, n: sizeof(params)); | 
|---|
| 765 |  | 
|---|
| 766 | params_set_format(p: ¶ms, fmt: snd_hdac_format_normalize(format)); | 
|---|
| 767 | snd_mask_set(mask: hw_param_mask(params: ¶ms, SNDRV_PCM_HW_PARAM_SUBFORMAT), | 
|---|
| 768 | val: (__force unsigned int)subformat); | 
|---|
| 769 |  | 
|---|
| 770 | bits = snd_pcm_hw_params_bits(p: ¶ms); | 
|---|
| 771 | if (maxbits) | 
|---|
| 772 | return min(bits, maxbits); | 
|---|
| 773 | return bits; | 
|---|
| 774 | } | 
|---|
| 775 | EXPORT_SYMBOL_GPL(snd_hdac_stream_format_bits); | 
|---|
| 776 |  | 
|---|
| 777 | /** | 
|---|
| 778 | * snd_hdac_stream_format - convert format parameters to SDxFMT value. | 
|---|
| 779 | * @channels:	the number of channels. | 
|---|
| 780 | * @bits:	bits per sample. | 
|---|
| 781 | * @rate:	the sample rate. | 
|---|
| 782 | * | 
|---|
| 783 | * Return: The format bitset or zero if invalid. | 
|---|
| 784 | */ | 
|---|
| 785 | unsigned int snd_hdac_stream_format(unsigned int channels, unsigned int bits, unsigned int rate) | 
|---|
| 786 | { | 
|---|
| 787 | unsigned int val = 0; | 
|---|
| 788 | int i; | 
|---|
| 789 |  | 
|---|
| 790 | for (i = 0; rate_bits[i].hz; i++) { | 
|---|
| 791 | if (rate_bits[i].hz == rate) { | 
|---|
| 792 | val = rate_bits[i].hda_fmt; | 
|---|
| 793 | break; | 
|---|
| 794 | } | 
|---|
| 795 | } | 
|---|
| 796 |  | 
|---|
| 797 | if (!rate_bits[i].hz) | 
|---|
| 798 | return 0; | 
|---|
| 799 |  | 
|---|
| 800 | if (channels == 0 || channels > 16) | 
|---|
| 801 | return 0; | 
|---|
| 802 | val |= channels - 1; | 
|---|
| 803 |  | 
|---|
| 804 | switch (bits) { | 
|---|
| 805 | case 8: | 
|---|
| 806 | val |= AC_FMT_BITS_8; | 
|---|
| 807 | break; | 
|---|
| 808 | case 16: | 
|---|
| 809 | val |= AC_FMT_BITS_16; | 
|---|
| 810 | break; | 
|---|
| 811 | case 20: | 
|---|
| 812 | val |= AC_FMT_BITS_20; | 
|---|
| 813 | break; | 
|---|
| 814 | case 24: | 
|---|
| 815 | val |= AC_FMT_BITS_24; | 
|---|
| 816 | break; | 
|---|
| 817 | case 32: | 
|---|
| 818 | val |= AC_FMT_BITS_32; | 
|---|
| 819 | break; | 
|---|
| 820 | default: | 
|---|
| 821 | return 0; | 
|---|
| 822 | } | 
|---|
| 823 |  | 
|---|
| 824 | return val; | 
|---|
| 825 | } | 
|---|
| 826 | EXPORT_SYMBOL_GPL(snd_hdac_stream_format); | 
|---|
| 827 |  | 
|---|
| 828 | /** | 
|---|
| 829 | * snd_hdac_spdif_stream_format - convert format parameters to SDxFMT value. | 
|---|
| 830 | * @channels:	the number of channels. | 
|---|
| 831 | * @bits:	bits per sample. | 
|---|
| 832 | * @rate:	the sample rate. | 
|---|
| 833 | * @spdif_ctls:	HD-audio SPDIF status bits (0 if irrelevant). | 
|---|
| 834 | * | 
|---|
| 835 | * Return: The format bitset or zero if invalid. | 
|---|
| 836 | */ | 
|---|
| 837 | unsigned int snd_hdac_spdif_stream_format(unsigned int channels, unsigned int bits, | 
|---|
| 838 | unsigned int rate, unsigned short spdif_ctls) | 
|---|
| 839 | { | 
|---|
| 840 | unsigned int val = snd_hdac_stream_format(channels, bits, rate); | 
|---|
| 841 |  | 
|---|
| 842 | if (val && spdif_ctls & AC_DIG1_NONAUDIO) | 
|---|
| 843 | val |= AC_FMT_TYPE_NON_PCM; | 
|---|
| 844 |  | 
|---|
| 845 | return val; | 
|---|
| 846 | } | 
|---|
| 847 | EXPORT_SYMBOL_GPL(snd_hdac_spdif_stream_format); | 
|---|
| 848 |  | 
|---|
| 849 | static unsigned int query_pcm_param(struct hdac_device *codec, hda_nid_t nid) | 
|---|
| 850 | { | 
|---|
| 851 | unsigned int val = 0; | 
|---|
| 852 |  | 
|---|
| 853 | if (nid != codec->afg && | 
|---|
| 854 | (snd_hdac_get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) | 
|---|
| 855 | val = snd_hdac_read_parm(codec, nid, AC_PAR_PCM); | 
|---|
| 856 | if (!val || val == -1) | 
|---|
| 857 | val = snd_hdac_read_parm(codec, nid: codec->afg, AC_PAR_PCM); | 
|---|
| 858 | if (!val || val == -1) | 
|---|
| 859 | return 0; | 
|---|
| 860 | return val; | 
|---|
| 861 | } | 
|---|
| 862 |  | 
|---|
| 863 | static unsigned int query_stream_param(struct hdac_device *codec, hda_nid_t nid) | 
|---|
| 864 | { | 
|---|
| 865 | unsigned int streams = snd_hdac_read_parm(codec, nid, AC_PAR_STREAM); | 
|---|
| 866 |  | 
|---|
| 867 | if (!streams || streams == -1) | 
|---|
| 868 | streams = snd_hdac_read_parm(codec, nid: codec->afg, AC_PAR_STREAM); | 
|---|
| 869 | if (!streams || streams == -1) | 
|---|
| 870 | return 0; | 
|---|
| 871 | return streams; | 
|---|
| 872 | } | 
|---|
| 873 |  | 
|---|
| 874 | /** | 
|---|
| 875 | * snd_hdac_query_supported_pcm - query the supported PCM rates and formats | 
|---|
| 876 | * @codec: the codec object | 
|---|
| 877 | * @nid: NID to query | 
|---|
| 878 | * @ratesp: the pointer to store the detected rate bitflags | 
|---|
| 879 | * @formatsp: the pointer to store the detected formats | 
|---|
| 880 | * @subformatsp: the pointer to store the detected subformats for S32_LE format | 
|---|
| 881 | * @bpsp: the pointer to store the detected format widths | 
|---|
| 882 | * | 
|---|
| 883 | * Queries the supported PCM rates and formats.  The NULL @ratesp, @formatsp, | 
|---|
| 884 | * @subformatsp or @bpsp argument is ignored. | 
|---|
| 885 | * | 
|---|
| 886 | * Returns 0 if successful, otherwise a negative error code. | 
|---|
| 887 | */ | 
|---|
| 888 | int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid, | 
|---|
| 889 | u32 *ratesp, u64 *formatsp, u32 *subformatsp, | 
|---|
| 890 | unsigned int *bpsp) | 
|---|
| 891 | { | 
|---|
| 892 | unsigned int i, val, wcaps; | 
|---|
| 893 |  | 
|---|
| 894 | wcaps = snd_hdac_get_wcaps(codec, nid); | 
|---|
| 895 | val = query_pcm_param(codec, nid); | 
|---|
| 896 |  | 
|---|
| 897 | if (ratesp) { | 
|---|
| 898 | u32 rates = 0; | 
|---|
| 899 | for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) { | 
|---|
| 900 | if (val & (1 << i)) | 
|---|
| 901 | rates |= rate_bits[i].alsa_bits; | 
|---|
| 902 | } | 
|---|
| 903 | if (rates == 0) { | 
|---|
| 904 | dev_err(&codec->dev, | 
|---|
| 905 | "rates == 0 (nid=0x%x, val=0x%x, ovrd=%i)\n", | 
|---|
| 906 | nid, val, | 
|---|
| 907 | (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0); | 
|---|
| 908 | return -EIO; | 
|---|
| 909 | } | 
|---|
| 910 | *ratesp = rates; | 
|---|
| 911 | } | 
|---|
| 912 |  | 
|---|
| 913 | if (formatsp || subformatsp || bpsp) { | 
|---|
| 914 | unsigned int streams, bps; | 
|---|
| 915 | u32 subformats = 0; | 
|---|
| 916 | u64 formats = 0; | 
|---|
| 917 |  | 
|---|
| 918 | streams = query_stream_param(codec, nid); | 
|---|
| 919 | if (!streams) | 
|---|
| 920 | return -EIO; | 
|---|
| 921 |  | 
|---|
| 922 | bps = 0; | 
|---|
| 923 | if (streams & AC_SUPFMT_PCM) { | 
|---|
| 924 | if (val & AC_SUPPCM_BITS_8) { | 
|---|
| 925 | formats |= SNDRV_PCM_FMTBIT_U8; | 
|---|
| 926 | bps = 8; | 
|---|
| 927 | } | 
|---|
| 928 | if (val & AC_SUPPCM_BITS_16) { | 
|---|
| 929 | formats |= SNDRV_PCM_FMTBIT_S16_LE; | 
|---|
| 930 | bps = 16; | 
|---|
| 931 | } | 
|---|
| 932 | if (val & AC_SUPPCM_BITS_20) { | 
|---|
| 933 | formats |= SNDRV_PCM_FMTBIT_S32_LE; | 
|---|
| 934 | subformats |= SNDRV_PCM_SUBFMTBIT_MSBITS_20; | 
|---|
| 935 | bps = 20; | 
|---|
| 936 | } | 
|---|
| 937 | if (val & AC_SUPPCM_BITS_24) { | 
|---|
| 938 | formats |= SNDRV_PCM_FMTBIT_S32_LE; | 
|---|
| 939 | subformats |= SNDRV_PCM_SUBFMTBIT_MSBITS_24; | 
|---|
| 940 | bps = 24; | 
|---|
| 941 | } | 
|---|
| 942 | if (val & AC_SUPPCM_BITS_32) { | 
|---|
| 943 | if (wcaps & AC_WCAP_DIGITAL) { | 
|---|
| 944 | formats |= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; | 
|---|
| 945 | } else { | 
|---|
| 946 | formats |= SNDRV_PCM_FMTBIT_S32_LE; | 
|---|
| 947 | subformats |= SNDRV_PCM_SUBFMTBIT_MSBITS_MAX; | 
|---|
| 948 | bps = 32; | 
|---|
| 949 | } | 
|---|
| 950 | } | 
|---|
| 951 | } | 
|---|
| 952 | #if 0 /* FIXME: CS4206 doesn't work, which is the only codec supporting float */ | 
|---|
| 953 | if (streams & AC_SUPFMT_FLOAT32) { | 
|---|
| 954 | formats |= SNDRV_PCM_FMTBIT_FLOAT_LE; | 
|---|
| 955 | if (!bps) | 
|---|
| 956 | bps = 32; | 
|---|
| 957 | } | 
|---|
| 958 | #endif | 
|---|
| 959 | if (streams == AC_SUPFMT_AC3) { | 
|---|
| 960 | /* should be exclusive */ | 
|---|
| 961 | /* temporary hack: we have still no proper support | 
|---|
| 962 | * for the direct AC3 stream... | 
|---|
| 963 | */ | 
|---|
| 964 | formats |= SNDRV_PCM_FMTBIT_U8; | 
|---|
| 965 | bps = 8; | 
|---|
| 966 | } | 
|---|
| 967 | if (formats == 0) { | 
|---|
| 968 | dev_err(&codec->dev, | 
|---|
| 969 | "formats == 0 (nid=0x%x, val=0x%x, ovrd=%i, streams=0x%x)\n", | 
|---|
| 970 | nid, val, | 
|---|
| 971 | (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0, | 
|---|
| 972 | streams); | 
|---|
| 973 | return -EIO; | 
|---|
| 974 | } | 
|---|
| 975 | if (formatsp) | 
|---|
| 976 | *formatsp = formats; | 
|---|
| 977 | if (subformatsp) | 
|---|
| 978 | *subformatsp = subformats; | 
|---|
| 979 | if (bpsp) | 
|---|
| 980 | *bpsp = bps; | 
|---|
| 981 | } | 
|---|
| 982 |  | 
|---|
| 983 | return 0; | 
|---|
| 984 | } | 
|---|
| 985 | EXPORT_SYMBOL_GPL(snd_hdac_query_supported_pcm); | 
|---|
| 986 |  | 
|---|
| 987 | /** | 
|---|
| 988 | * snd_hdac_is_supported_format - Check the validity of the format | 
|---|
| 989 | * @codec: the codec object | 
|---|
| 990 | * @nid: NID to check | 
|---|
| 991 | * @format: the HD-audio format value to check | 
|---|
| 992 | * | 
|---|
| 993 | * Check whether the given node supports the format value. | 
|---|
| 994 | * | 
|---|
| 995 | * Returns true if supported, false if not. | 
|---|
| 996 | */ | 
|---|
| 997 | bool snd_hdac_is_supported_format(struct hdac_device *codec, hda_nid_t nid, | 
|---|
| 998 | unsigned int format) | 
|---|
| 999 | { | 
|---|
| 1000 | int i; | 
|---|
| 1001 | unsigned int val = 0, rate, stream; | 
|---|
| 1002 |  | 
|---|
| 1003 | val = query_pcm_param(codec, nid); | 
|---|
| 1004 | if (!val) | 
|---|
| 1005 | return false; | 
|---|
| 1006 |  | 
|---|
| 1007 | rate = format & 0xff00; | 
|---|
| 1008 | for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) | 
|---|
| 1009 | if (rate_bits[i].hda_fmt == rate) { | 
|---|
| 1010 | if (val & (1 << i)) | 
|---|
| 1011 | break; | 
|---|
| 1012 | return false; | 
|---|
| 1013 | } | 
|---|
| 1014 | if (i >= AC_PAR_PCM_RATE_BITS) | 
|---|
| 1015 | return false; | 
|---|
| 1016 |  | 
|---|
| 1017 | stream = query_stream_param(codec, nid); | 
|---|
| 1018 | if (!stream) | 
|---|
| 1019 | return false; | 
|---|
| 1020 |  | 
|---|
| 1021 | if (stream & AC_SUPFMT_PCM) { | 
|---|
| 1022 | switch (format & 0xf0) { | 
|---|
| 1023 | case 0x00: | 
|---|
| 1024 | if (!(val & AC_SUPPCM_BITS_8)) | 
|---|
| 1025 | return false; | 
|---|
| 1026 | break; | 
|---|
| 1027 | case 0x10: | 
|---|
| 1028 | if (!(val & AC_SUPPCM_BITS_16)) | 
|---|
| 1029 | return false; | 
|---|
| 1030 | break; | 
|---|
| 1031 | case 0x20: | 
|---|
| 1032 | if (!(val & AC_SUPPCM_BITS_20)) | 
|---|
| 1033 | return false; | 
|---|
| 1034 | break; | 
|---|
| 1035 | case 0x30: | 
|---|
| 1036 | if (!(val & AC_SUPPCM_BITS_24)) | 
|---|
| 1037 | return false; | 
|---|
| 1038 | break; | 
|---|
| 1039 | case 0x40: | 
|---|
| 1040 | if (!(val & AC_SUPPCM_BITS_32)) | 
|---|
| 1041 | return false; | 
|---|
| 1042 | break; | 
|---|
| 1043 | default: | 
|---|
| 1044 | return false; | 
|---|
| 1045 | } | 
|---|
| 1046 | } else { | 
|---|
| 1047 | /* FIXME: check for float32 and AC3? */ | 
|---|
| 1048 | } | 
|---|
| 1049 |  | 
|---|
| 1050 | return true; | 
|---|
| 1051 | } | 
|---|
| 1052 | EXPORT_SYMBOL_GPL(snd_hdac_is_supported_format); | 
|---|
| 1053 |  | 
|---|
| 1054 | static unsigned int codec_read(struct hdac_device *hdac, hda_nid_t nid, | 
|---|
| 1055 | int flags, unsigned int verb, unsigned int parm) | 
|---|
| 1056 | { | 
|---|
| 1057 | unsigned int cmd = snd_hdac_make_cmd(codec: hdac, nid, verb, parm); | 
|---|
| 1058 | unsigned int res; | 
|---|
| 1059 |  | 
|---|
| 1060 | if (snd_hdac_exec_verb(codec: hdac, cmd, flags, res: &res)) | 
|---|
| 1061 | return -1; | 
|---|
| 1062 |  | 
|---|
| 1063 | return res; | 
|---|
| 1064 | } | 
|---|
| 1065 |  | 
|---|
| 1066 | static int codec_write(struct hdac_device *hdac, hda_nid_t nid, | 
|---|
| 1067 | int flags, unsigned int verb, unsigned int parm) | 
|---|
| 1068 | { | 
|---|
| 1069 | unsigned int cmd = snd_hdac_make_cmd(codec: hdac, nid, verb, parm); | 
|---|
| 1070 |  | 
|---|
| 1071 | return snd_hdac_exec_verb(codec: hdac, cmd, flags, NULL); | 
|---|
| 1072 | } | 
|---|
| 1073 |  | 
|---|
| 1074 | /** | 
|---|
| 1075 | * snd_hdac_codec_read - send a command and get the response | 
|---|
| 1076 | * @hdac: the HDAC device | 
|---|
| 1077 | * @nid: NID to send the command | 
|---|
| 1078 | * @flags: optional bit flags | 
|---|
| 1079 | * @verb: the verb to send | 
|---|
| 1080 | * @parm: the parameter for the verb | 
|---|
| 1081 | * | 
|---|
| 1082 | * Send a single command and read the corresponding response. | 
|---|
| 1083 | * | 
|---|
| 1084 | * Returns the obtained response value, or -1 for an error. | 
|---|
| 1085 | */ | 
|---|
| 1086 | int snd_hdac_codec_read(struct hdac_device *hdac, hda_nid_t nid, | 
|---|
| 1087 | int flags, unsigned int verb, unsigned int parm) | 
|---|
| 1088 | { | 
|---|
| 1089 | return codec_read(hdac, nid, flags, verb, parm); | 
|---|
| 1090 | } | 
|---|
| 1091 | EXPORT_SYMBOL_GPL(snd_hdac_codec_read); | 
|---|
| 1092 |  | 
|---|
| 1093 | /** | 
|---|
| 1094 | * snd_hdac_codec_write - send a single command without waiting for response | 
|---|
| 1095 | * @hdac: the HDAC device | 
|---|
| 1096 | * @nid: NID to send the command | 
|---|
| 1097 | * @flags: optional bit flags | 
|---|
| 1098 | * @verb: the verb to send | 
|---|
| 1099 | * @parm: the parameter for the verb | 
|---|
| 1100 | * | 
|---|
| 1101 | * Send a single command without waiting for response. | 
|---|
| 1102 | * | 
|---|
| 1103 | * Returns 0 if successful, or a negative error code. | 
|---|
| 1104 | */ | 
|---|
| 1105 | int snd_hdac_codec_write(struct hdac_device *hdac, hda_nid_t nid, | 
|---|
| 1106 | int flags, unsigned int verb, unsigned int parm) | 
|---|
| 1107 | { | 
|---|
| 1108 | return codec_write(hdac, nid, flags, verb, parm); | 
|---|
| 1109 | } | 
|---|
| 1110 | EXPORT_SYMBOL_GPL(snd_hdac_codec_write); | 
|---|
| 1111 |  | 
|---|
| 1112 | /** | 
|---|
| 1113 | * snd_hdac_check_power_state - check whether the actual power state matches | 
|---|
| 1114 | * with the target state | 
|---|
| 1115 | * | 
|---|
| 1116 | * @hdac: the HDAC device | 
|---|
| 1117 | * @nid: NID to send the command | 
|---|
| 1118 | * @target_state: target state to check for | 
|---|
| 1119 | * | 
|---|
| 1120 | * Return true if state matches, false if not | 
|---|
| 1121 | */ | 
|---|
| 1122 | bool snd_hdac_check_power_state(struct hdac_device *hdac, | 
|---|
| 1123 | hda_nid_t nid, unsigned int target_state) | 
|---|
| 1124 | { | 
|---|
| 1125 | unsigned int state = codec_read(hdac, nid, flags: 0, | 
|---|
| 1126 | AC_VERB_GET_POWER_STATE, parm: 0); | 
|---|
| 1127 |  | 
|---|
| 1128 | if (state & AC_PWRST_ERROR) | 
|---|
| 1129 | return true; | 
|---|
| 1130 | state = (state >> 4) & 0x0f; | 
|---|
| 1131 | return (state == target_state); | 
|---|
| 1132 | } | 
|---|
| 1133 | EXPORT_SYMBOL_GPL(snd_hdac_check_power_state); | 
|---|
| 1134 | /** | 
|---|
| 1135 | * snd_hdac_sync_power_state - wait until actual power state matches | 
|---|
| 1136 | * with the target state | 
|---|
| 1137 | * | 
|---|
| 1138 | * @codec: the HDAC device | 
|---|
| 1139 | * @nid: NID to send the command | 
|---|
| 1140 | * @power_state: target power state to wait for | 
|---|
| 1141 | * | 
|---|
| 1142 | * Return power state or PS_ERROR if codec rejects GET verb. | 
|---|
| 1143 | */ | 
|---|
| 1144 | unsigned int snd_hdac_sync_power_state(struct hdac_device *codec, | 
|---|
| 1145 | hda_nid_t nid, unsigned int power_state) | 
|---|
| 1146 | { | 
|---|
| 1147 | unsigned long end_time = jiffies + msecs_to_jiffies(m: 500); | 
|---|
| 1148 | unsigned int state, actual_state, count; | 
|---|
| 1149 |  | 
|---|
| 1150 | for (count = 0; count < 500; count++) { | 
|---|
| 1151 | state = snd_hdac_codec_read(codec, nid, 0, | 
|---|
| 1152 | AC_VERB_GET_POWER_STATE, 0); | 
|---|
| 1153 | if (state & AC_PWRST_ERROR) { | 
|---|
| 1154 | msleep(msecs: 20); | 
|---|
| 1155 | break; | 
|---|
| 1156 | } | 
|---|
| 1157 | actual_state = (state >> 4) & 0x0f; | 
|---|
| 1158 | if (actual_state == power_state) | 
|---|
| 1159 | break; | 
|---|
| 1160 | if (time_after_eq(jiffies, end_time)) | 
|---|
| 1161 | break; | 
|---|
| 1162 | /* wait until the codec reachs to the target state */ | 
|---|
| 1163 | msleep(msecs: 1); | 
|---|
| 1164 | } | 
|---|
| 1165 | return state; | 
|---|
| 1166 | } | 
|---|
| 1167 | EXPORT_SYMBOL_GPL(snd_hdac_sync_power_state); | 
|---|
| 1168 |  | 
|---|