18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// soc-ac97.c -- ALSA SoC Audio Layer AC97 support 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright 2005 Wolfson Microelectronics PLC. 68c2ecf20Sopenharmony_ci// Copyright 2005 Openedhand Ltd. 78c2ecf20Sopenharmony_ci// Copyright (C) 2010 Slimlogic Ltd. 88c2ecf20Sopenharmony_ci// Copyright (C) 2010 Texas Instruments Inc. 98c2ecf20Sopenharmony_ci// 108c2ecf20Sopenharmony_ci// Author: Liam Girdwood <lrg@slimlogic.co.uk> 118c2ecf20Sopenharmony_ci// with code, comments and ideas from :- 128c2ecf20Sopenharmony_ci// Richard Purdie <richard@openedhand.com> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/ctype.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/export.h> 178c2ecf20Sopenharmony_ci#include <linux/gpio.h> 188c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 198c2ecf20Sopenharmony_ci#include <linux/init.h> 208c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 218c2ecf20Sopenharmony_ci#include <linux/of.h> 228c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h> 238c2ecf20Sopenharmony_ci#include <linux/slab.h> 248c2ecf20Sopenharmony_ci#include <sound/ac97_codec.h> 258c2ecf20Sopenharmony_ci#include <sound/soc.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct snd_ac97_reset_cfg { 288c2ecf20Sopenharmony_ci struct pinctrl *pctl; 298c2ecf20Sopenharmony_ci struct pinctrl_state *pstate_reset; 308c2ecf20Sopenharmony_ci struct pinctrl_state *pstate_warm_reset; 318c2ecf20Sopenharmony_ci struct pinctrl_state *pstate_run; 328c2ecf20Sopenharmony_ci int gpio_sdata; 338c2ecf20Sopenharmony_ci int gpio_sync; 348c2ecf20Sopenharmony_ci int gpio_reset; 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistruct snd_ac97_gpio_priv { 388c2ecf20Sopenharmony_ci#ifdef CONFIG_GPIOLIB 398c2ecf20Sopenharmony_ci struct gpio_chip gpio_chip; 408c2ecf20Sopenharmony_ci#endif 418c2ecf20Sopenharmony_ci unsigned int gpios_set; 428c2ecf20Sopenharmony_ci struct snd_soc_component *component; 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic struct snd_ac97_bus soc_ac97_bus = { 468c2ecf20Sopenharmony_ci .ops = NULL, /* Gets initialized in snd_soc_set_ac97_ops() */ 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic void soc_ac97_device_release(struct device *dev) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci kfree(to_ac97_t(dev)); 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#ifdef CONFIG_GPIOLIB 558c2ecf20Sopenharmony_cistatic inline struct snd_soc_component *gpio_to_component(struct gpio_chip *chip) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci struct snd_ac97_gpio_priv *gpio_priv = gpiochip_get_data(chip); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return gpio_priv->component; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int snd_soc_ac97_gpio_request(struct gpio_chip *chip, unsigned offset) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci if (offset >= AC97_NUM_GPIOS) 658c2ecf20Sopenharmony_ci return -EINVAL; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci return 0; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic int snd_soc_ac97_gpio_direction_in(struct gpio_chip *chip, 718c2ecf20Sopenharmony_ci unsigned offset) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct snd_soc_component *component = gpio_to_component(chip); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci dev_dbg(component->dev, "set gpio %d to output\n", offset); 768c2ecf20Sopenharmony_ci return snd_soc_component_update_bits(component, AC97_GPIO_CFG, 778c2ecf20Sopenharmony_ci 1 << offset, 1 << offset); 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic int snd_soc_ac97_gpio_get(struct gpio_chip *chip, unsigned offset) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci struct snd_soc_component *component = gpio_to_component(chip); 838c2ecf20Sopenharmony_ci int ret; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci ret = snd_soc_component_read(component, AC97_GPIO_STATUS); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci dev_dbg(component->dev, "get gpio %d : %d\n", offset, 888c2ecf20Sopenharmony_ci ret & (1 << offset)); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci return !!(ret & (1 << offset)); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic void snd_soc_ac97_gpio_set(struct gpio_chip *chip, unsigned offset, 948c2ecf20Sopenharmony_ci int value) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci struct snd_ac97_gpio_priv *gpio_priv = gpiochip_get_data(chip); 978c2ecf20Sopenharmony_ci struct snd_soc_component *component = gpio_to_component(chip); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci gpio_priv->gpios_set &= ~(1 << offset); 1008c2ecf20Sopenharmony_ci gpio_priv->gpios_set |= (!!value) << offset; 1018c2ecf20Sopenharmony_ci snd_soc_component_write(component, AC97_GPIO_STATUS, 1028c2ecf20Sopenharmony_ci gpio_priv->gpios_set); 1038c2ecf20Sopenharmony_ci dev_dbg(component->dev, "set gpio %d to %d\n", offset, !!value); 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic int snd_soc_ac97_gpio_direction_out(struct gpio_chip *chip, 1078c2ecf20Sopenharmony_ci unsigned offset, int value) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci struct snd_soc_component *component = gpio_to_component(chip); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci dev_dbg(component->dev, "set gpio %d to output\n", offset); 1128c2ecf20Sopenharmony_ci snd_soc_ac97_gpio_set(chip, offset, value); 1138c2ecf20Sopenharmony_ci return snd_soc_component_update_bits(component, AC97_GPIO_CFG, 1148c2ecf20Sopenharmony_ci 1 << offset, 0); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic const struct gpio_chip snd_soc_ac97_gpio_chip = { 1188c2ecf20Sopenharmony_ci .label = "snd_soc_ac97", 1198c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1208c2ecf20Sopenharmony_ci .request = snd_soc_ac97_gpio_request, 1218c2ecf20Sopenharmony_ci .direction_input = snd_soc_ac97_gpio_direction_in, 1228c2ecf20Sopenharmony_ci .get = snd_soc_ac97_gpio_get, 1238c2ecf20Sopenharmony_ci .direction_output = snd_soc_ac97_gpio_direction_out, 1248c2ecf20Sopenharmony_ci .set = snd_soc_ac97_gpio_set, 1258c2ecf20Sopenharmony_ci .can_sleep = 1, 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic int snd_soc_ac97_init_gpio(struct snd_ac97 *ac97, 1298c2ecf20Sopenharmony_ci struct snd_soc_component *component) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct snd_ac97_gpio_priv *gpio_priv; 1328c2ecf20Sopenharmony_ci int ret; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci gpio_priv = devm_kzalloc(component->dev, sizeof(*gpio_priv), GFP_KERNEL); 1358c2ecf20Sopenharmony_ci if (!gpio_priv) 1368c2ecf20Sopenharmony_ci return -ENOMEM; 1378c2ecf20Sopenharmony_ci ac97->gpio_priv = gpio_priv; 1388c2ecf20Sopenharmony_ci gpio_priv->component = component; 1398c2ecf20Sopenharmony_ci gpio_priv->gpio_chip = snd_soc_ac97_gpio_chip; 1408c2ecf20Sopenharmony_ci gpio_priv->gpio_chip.ngpio = AC97_NUM_GPIOS; 1418c2ecf20Sopenharmony_ci gpio_priv->gpio_chip.parent = component->dev; 1428c2ecf20Sopenharmony_ci gpio_priv->gpio_chip.base = -1; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci ret = gpiochip_add_data(&gpio_priv->gpio_chip, gpio_priv); 1458c2ecf20Sopenharmony_ci if (ret != 0) 1468c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to add GPIOs: %d\n", ret); 1478c2ecf20Sopenharmony_ci return ret; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic void snd_soc_ac97_free_gpio(struct snd_ac97 *ac97) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci gpiochip_remove(&ac97->gpio_priv->gpio_chip); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci#else 1558c2ecf20Sopenharmony_cistatic int snd_soc_ac97_init_gpio(struct snd_ac97 *ac97, 1568c2ecf20Sopenharmony_ci struct snd_soc_component *component) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci return 0; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic void snd_soc_ac97_free_gpio(struct snd_ac97 *ac97) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci#endif 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci/** 1678c2ecf20Sopenharmony_ci * snd_soc_alloc_ac97_component() - Allocate new a AC'97 device 1688c2ecf20Sopenharmony_ci * @component: The COMPONENT for which to create the AC'97 device 1698c2ecf20Sopenharmony_ci * 1708c2ecf20Sopenharmony_ci * Allocated a new snd_ac97 device and intializes it, but does not yet register 1718c2ecf20Sopenharmony_ci * it. The caller is responsible to either call device_add(&ac97->dev) to 1728c2ecf20Sopenharmony_ci * register the device, or to call put_device(&ac97->dev) to free the device. 1738c2ecf20Sopenharmony_ci * 1748c2ecf20Sopenharmony_ci * Returns: A snd_ac97 device or a PTR_ERR in case of an error. 1758c2ecf20Sopenharmony_ci */ 1768c2ecf20Sopenharmony_cistruct snd_ac97 *snd_soc_alloc_ac97_component(struct snd_soc_component *component) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci struct snd_ac97 *ac97; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); 1818c2ecf20Sopenharmony_ci if (ac97 == NULL) 1828c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci ac97->bus = &soc_ac97_bus; 1858c2ecf20Sopenharmony_ci ac97->num = 0; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci ac97->dev.bus = &ac97_bus_type; 1888c2ecf20Sopenharmony_ci ac97->dev.parent = component->card->dev; 1898c2ecf20Sopenharmony_ci ac97->dev.release = soc_ac97_device_release; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci dev_set_name(&ac97->dev, "%d-%d:%s", 1928c2ecf20Sopenharmony_ci component->card->snd_card->number, 0, 1938c2ecf20Sopenharmony_ci component->name); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci device_initialize(&ac97->dev); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return ac97; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_soc_alloc_ac97_component); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci/** 2028c2ecf20Sopenharmony_ci * snd_soc_new_ac97_component - initailise AC97 device 2038c2ecf20Sopenharmony_ci * @component: audio component 2048c2ecf20Sopenharmony_ci * @id: The expected device ID 2058c2ecf20Sopenharmony_ci * @id_mask: Mask that is applied to the device ID before comparing with @id 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * Initialises AC97 component resources for use by ad-hoc devices only. 2088c2ecf20Sopenharmony_ci * 2098c2ecf20Sopenharmony_ci * If @id is not 0 this function will reset the device, then read the ID from 2108c2ecf20Sopenharmony_ci * the device and check if it matches the expected ID. If it doesn't match an 2118c2ecf20Sopenharmony_ci * error will be returned and device will not be registered. 2128c2ecf20Sopenharmony_ci * 2138c2ecf20Sopenharmony_ci * Returns: A PTR_ERR() on failure or a valid snd_ac97 struct on success. 2148c2ecf20Sopenharmony_ci */ 2158c2ecf20Sopenharmony_cistruct snd_ac97 *snd_soc_new_ac97_component(struct snd_soc_component *component, 2168c2ecf20Sopenharmony_ci unsigned int id, unsigned int id_mask) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct snd_ac97 *ac97; 2198c2ecf20Sopenharmony_ci int ret; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci ac97 = snd_soc_alloc_ac97_component(component); 2228c2ecf20Sopenharmony_ci if (IS_ERR(ac97)) 2238c2ecf20Sopenharmony_ci return ac97; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (id) { 2268c2ecf20Sopenharmony_ci ret = snd_ac97_reset(ac97, false, id, id_mask); 2278c2ecf20Sopenharmony_ci if (ret < 0) { 2288c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to reset AC97 device: %d\n", 2298c2ecf20Sopenharmony_ci ret); 2308c2ecf20Sopenharmony_ci goto err_put_device; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci ret = device_add(&ac97->dev); 2358c2ecf20Sopenharmony_ci if (ret) 2368c2ecf20Sopenharmony_ci goto err_put_device; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci ret = snd_soc_ac97_init_gpio(ac97, component); 2398c2ecf20Sopenharmony_ci if (ret) 2408c2ecf20Sopenharmony_ci goto err_put_device; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci return ac97; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cierr_put_device: 2458c2ecf20Sopenharmony_ci put_device(&ac97->dev); 2468c2ecf20Sopenharmony_ci return ERR_PTR(ret); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_new_ac97_component); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci/** 2518c2ecf20Sopenharmony_ci * snd_soc_free_ac97_component - free AC97 component device 2528c2ecf20Sopenharmony_ci * @ac97: snd_ac97 device to be freed 2538c2ecf20Sopenharmony_ci * 2548c2ecf20Sopenharmony_ci * Frees AC97 component device resources. 2558c2ecf20Sopenharmony_ci */ 2568c2ecf20Sopenharmony_civoid snd_soc_free_ac97_component(struct snd_ac97 *ac97) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci snd_soc_ac97_free_gpio(ac97); 2598c2ecf20Sopenharmony_ci device_del(&ac97->dev); 2608c2ecf20Sopenharmony_ci ac97->bus = NULL; 2618c2ecf20Sopenharmony_ci put_device(&ac97->dev); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_free_ac97_component); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic struct snd_ac97_reset_cfg snd_ac97_rst_cfg; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic void snd_soc_ac97_warm_reset(struct snd_ac97 *ac97) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct pinctrl *pctl = snd_ac97_rst_cfg.pctl; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_warm_reset); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 1); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci udelay(10); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run); 2808c2ecf20Sopenharmony_ci msleep(2); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic void snd_soc_ac97_reset(struct snd_ac97 *ac97) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct pinctrl *pctl = snd_ac97_rst_cfg.pctl; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_reset); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0); 2908c2ecf20Sopenharmony_ci gpio_direction_output(snd_ac97_rst_cfg.gpio_sdata, 0); 2918c2ecf20Sopenharmony_ci gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 0); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci udelay(10); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 1); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run); 2988c2ecf20Sopenharmony_ci msleep(2); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic int snd_soc_ac97_parse_pinctl(struct device *dev, 3028c2ecf20Sopenharmony_ci struct snd_ac97_reset_cfg *cfg) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct pinctrl *p; 3058c2ecf20Sopenharmony_ci struct pinctrl_state *state; 3068c2ecf20Sopenharmony_ci int gpio; 3078c2ecf20Sopenharmony_ci int ret; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci p = devm_pinctrl_get(dev); 3108c2ecf20Sopenharmony_ci if (IS_ERR(p)) { 3118c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get pinctrl\n"); 3128c2ecf20Sopenharmony_ci return PTR_ERR(p); 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci cfg->pctl = p; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci state = pinctrl_lookup_state(p, "ac97-reset"); 3178c2ecf20Sopenharmony_ci if (IS_ERR(state)) { 3188c2ecf20Sopenharmony_ci dev_err(dev, "Can't find pinctrl state ac97-reset\n"); 3198c2ecf20Sopenharmony_ci return PTR_ERR(state); 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci cfg->pstate_reset = state; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci state = pinctrl_lookup_state(p, "ac97-warm-reset"); 3248c2ecf20Sopenharmony_ci if (IS_ERR(state)) { 3258c2ecf20Sopenharmony_ci dev_err(dev, "Can't find pinctrl state ac97-warm-reset\n"); 3268c2ecf20Sopenharmony_ci return PTR_ERR(state); 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci cfg->pstate_warm_reset = state; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci state = pinctrl_lookup_state(p, "ac97-running"); 3318c2ecf20Sopenharmony_ci if (IS_ERR(state)) { 3328c2ecf20Sopenharmony_ci dev_err(dev, "Can't find pinctrl state ac97-running\n"); 3338c2ecf20Sopenharmony_ci return PTR_ERR(state); 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci cfg->pstate_run = state; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 0); 3388c2ecf20Sopenharmony_ci if (gpio < 0) { 3398c2ecf20Sopenharmony_ci dev_err(dev, "Can't find ac97-sync gpio\n"); 3408c2ecf20Sopenharmony_ci return gpio; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci ret = devm_gpio_request(dev, gpio, "AC97 link sync"); 3438c2ecf20Sopenharmony_ci if (ret) { 3448c2ecf20Sopenharmony_ci dev_err(dev, "Failed requesting ac97-sync gpio\n"); 3458c2ecf20Sopenharmony_ci return ret; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci cfg->gpio_sync = gpio; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 1); 3508c2ecf20Sopenharmony_ci if (gpio < 0) { 3518c2ecf20Sopenharmony_ci dev_err(dev, "Can't find ac97-sdata gpio %d\n", gpio); 3528c2ecf20Sopenharmony_ci return gpio; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci ret = devm_gpio_request(dev, gpio, "AC97 link sdata"); 3558c2ecf20Sopenharmony_ci if (ret) { 3568c2ecf20Sopenharmony_ci dev_err(dev, "Failed requesting ac97-sdata gpio\n"); 3578c2ecf20Sopenharmony_ci return ret; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci cfg->gpio_sdata = gpio; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 2); 3628c2ecf20Sopenharmony_ci if (gpio < 0) { 3638c2ecf20Sopenharmony_ci dev_err(dev, "Can't find ac97-reset gpio\n"); 3648c2ecf20Sopenharmony_ci return gpio; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci ret = devm_gpio_request(dev, gpio, "AC97 link reset"); 3678c2ecf20Sopenharmony_ci if (ret) { 3688c2ecf20Sopenharmony_ci dev_err(dev, "Failed requesting ac97-reset gpio\n"); 3698c2ecf20Sopenharmony_ci return ret; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci cfg->gpio_reset = gpio; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci return 0; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistruct snd_ac97_bus_ops *soc_ac97_ops; 3778c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(soc_ac97_ops); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ciint snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci if (ops == soc_ac97_ops) 3828c2ecf20Sopenharmony_ci return 0; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (soc_ac97_ops && ops) 3858c2ecf20Sopenharmony_ci return -EBUSY; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci soc_ac97_ops = ops; 3888c2ecf20Sopenharmony_ci soc_ac97_bus.ops = ops; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci return 0; 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci/** 3958c2ecf20Sopenharmony_ci * snd_soc_set_ac97_ops_of_reset - Set ac97 ops with generic ac97 reset functions 3968c2ecf20Sopenharmony_ci * @ops: bus ops 3978c2ecf20Sopenharmony_ci * @pdev: platform device 3988c2ecf20Sopenharmony_ci * 3998c2ecf20Sopenharmony_ci * This function sets the reset and warm_reset properties of ops and parses 4008c2ecf20Sopenharmony_ci * the device node of pdev to get pinctrl states and gpio numbers to use. 4018c2ecf20Sopenharmony_ci */ 4028c2ecf20Sopenharmony_ciint snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops, 4038c2ecf20Sopenharmony_ci struct platform_device *pdev) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 4068c2ecf20Sopenharmony_ci struct snd_ac97_reset_cfg cfg; 4078c2ecf20Sopenharmony_ci int ret; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci ret = snd_soc_ac97_parse_pinctl(dev, &cfg); 4108c2ecf20Sopenharmony_ci if (ret) 4118c2ecf20Sopenharmony_ci return ret; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci ret = snd_soc_set_ac97_ops(ops); 4148c2ecf20Sopenharmony_ci if (ret) 4158c2ecf20Sopenharmony_ci return ret; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci ops->warm_reset = snd_soc_ac97_warm_reset; 4188c2ecf20Sopenharmony_ci ops->reset = snd_soc_ac97_reset; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci snd_ac97_rst_cfg = cfg; 4218c2ecf20Sopenharmony_ci return 0; 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset); 424