]>
Commit | Line | Data |
---|---|---|
1a8f0a3c KM |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // | |
3 | // soc-ac97.c -- ALSA SoC Audio Layer AC97 support | |
4 | // | |
5 | // Copyright 2005 Wolfson Microelectronics PLC. | |
6 | // Copyright 2005 Openedhand Ltd. | |
7 | // Copyright (C) 2010 Slimlogic Ltd. | |
8 | // Copyright (C) 2010 Texas Instruments Inc. | |
9 | // | |
10 | // Author: Liam Girdwood <[email protected]> | |
11 | // with code, comments and ideas from :- | |
12 | // Richard Purdie <[email protected]> | |
336b8423 LPC |
13 | |
14 | #include <linux/ctype.h> | |
15 | #include <linux/delay.h> | |
16 | #include <linux/export.h> | |
17 | #include <linux/gpio.h> | |
9bf5c3d1 | 18 | #include <linux/gpio/driver.h> |
336b8423 LPC |
19 | #include <linux/init.h> |
20 | #include <linux/of_gpio.h> | |
21 | #include <linux/of.h> | |
22 | #include <linux/pinctrl/consumer.h> | |
23 | #include <linux/slab.h> | |
24 | #include <sound/ac97_codec.h> | |
25 | #include <sound/soc.h> | |
26 | ||
27 | struct snd_ac97_reset_cfg { | |
28 | struct pinctrl *pctl; | |
29 | struct pinctrl_state *pstate_reset; | |
30 | struct pinctrl_state *pstate_warm_reset; | |
31 | struct pinctrl_state *pstate_run; | |
32 | int gpio_sdata; | |
33 | int gpio_sync; | |
34 | int gpio_reset; | |
35 | }; | |
36 | ||
9bf5c3d1 RJ |
37 | struct snd_ac97_gpio_priv { |
38 | #ifdef CONFIG_GPIOLIB | |
39 | struct gpio_chip gpio_chip; | |
40 | #endif | |
41 | unsigned int gpios_set; | |
c95869e5 | 42 | struct snd_soc_component *component; |
9bf5c3d1 RJ |
43 | }; |
44 | ||
eda1a701 LPC |
45 | static struct snd_ac97_bus soc_ac97_bus = { |
46 | .ops = NULL, /* Gets initialized in snd_soc_set_ac97_ops() */ | |
47 | }; | |
48 | ||
336b8423 LPC |
49 | static void soc_ac97_device_release(struct device *dev) |
50 | { | |
51 | kfree(to_ac97_t(dev)); | |
52 | } | |
53 | ||
9bf5c3d1 | 54 | #ifdef CONFIG_GPIOLIB |
c95869e5 | 55 | static inline struct snd_soc_component *gpio_to_component(struct gpio_chip *chip) |
9bf5c3d1 | 56 | { |
f7cb5120 | 57 | struct snd_ac97_gpio_priv *gpio_priv = gpiochip_get_data(chip); |
9bf5c3d1 | 58 | |
c95869e5 | 59 | return gpio_priv->component; |
9bf5c3d1 RJ |
60 | } |
61 | ||
62 | static int snd_soc_ac97_gpio_request(struct gpio_chip *chip, unsigned offset) | |
63 | { | |
64 | if (offset >= AC97_NUM_GPIOS) | |
65 | return -EINVAL; | |
66 | ||
67 | return 0; | |
68 | } | |
69 | ||
70 | static int snd_soc_ac97_gpio_direction_in(struct gpio_chip *chip, | |
71 | unsigned offset) | |
72 | { | |
c95869e5 | 73 | struct snd_soc_component *component = gpio_to_component(chip); |
9bf5c3d1 | 74 | |
c95869e5 KM |
75 | dev_dbg(component->dev, "set gpio %d to output\n", offset); |
76 | return snd_soc_component_update_bits(component, AC97_GPIO_CFG, | |
9bf5c3d1 RJ |
77 | 1 << offset, 1 << offset); |
78 | } | |
79 | ||
80 | static int snd_soc_ac97_gpio_get(struct gpio_chip *chip, unsigned offset) | |
81 | { | |
c95869e5 | 82 | struct snd_soc_component *component = gpio_to_component(chip); |
9bf5c3d1 RJ |
83 | int ret; |
84 | ||
c95869e5 KM |
85 | if (snd_soc_component_read(component, AC97_GPIO_STATUS, &ret) < 0) |
86 | ret = -1; | |
87 | ||
88 | dev_dbg(component->dev, "get gpio %d : %d\n", offset, | |
9bf5c3d1 RJ |
89 | ret < 0 ? ret : ret & (1 << offset)); |
90 | ||
34015f5e | 91 | return ret < 0 ? ret : !!(ret & (1 << offset)); |
9bf5c3d1 RJ |
92 | } |
93 | ||
94 | static void snd_soc_ac97_gpio_set(struct gpio_chip *chip, unsigned offset, | |
95 | int value) | |
96 | { | |
f7cb5120 | 97 | struct snd_ac97_gpio_priv *gpio_priv = gpiochip_get_data(chip); |
c95869e5 | 98 | struct snd_soc_component *component = gpio_to_component(chip); |
9bf5c3d1 RJ |
99 | |
100 | gpio_priv->gpios_set &= ~(1 << offset); | |
101 | gpio_priv->gpios_set |= (!!value) << offset; | |
c95869e5 KM |
102 | snd_soc_component_write(component, AC97_GPIO_STATUS, |
103 | gpio_priv->gpios_set); | |
104 | dev_dbg(component->dev, "set gpio %d to %d\n", offset, !!value); | |
9bf5c3d1 RJ |
105 | } |
106 | ||
107 | static int snd_soc_ac97_gpio_direction_out(struct gpio_chip *chip, | |
108 | unsigned offset, int value) | |
109 | { | |
c95869e5 | 110 | struct snd_soc_component *component = gpio_to_component(chip); |
9bf5c3d1 | 111 | |
c95869e5 | 112 | dev_dbg(component->dev, "set gpio %d to output\n", offset); |
9bf5c3d1 | 113 | snd_soc_ac97_gpio_set(chip, offset, value); |
c95869e5 KM |
114 | return snd_soc_component_update_bits(component, AC97_GPIO_CFG, |
115 | 1 << offset, 0); | |
9bf5c3d1 RJ |
116 | } |
117 | ||
52abe541 | 118 | static const struct gpio_chip snd_soc_ac97_gpio_chip = { |
9bf5c3d1 RJ |
119 | .label = "snd_soc_ac97", |
120 | .owner = THIS_MODULE, | |
121 | .request = snd_soc_ac97_gpio_request, | |
122 | .direction_input = snd_soc_ac97_gpio_direction_in, | |
123 | .get = snd_soc_ac97_gpio_get, | |
124 | .direction_output = snd_soc_ac97_gpio_direction_out, | |
125 | .set = snd_soc_ac97_gpio_set, | |
126 | .can_sleep = 1, | |
127 | }; | |
128 | ||
129 | static int snd_soc_ac97_init_gpio(struct snd_ac97 *ac97, | |
c95869e5 | 130 | struct snd_soc_component *component) |
9bf5c3d1 RJ |
131 | { |
132 | struct snd_ac97_gpio_priv *gpio_priv; | |
133 | int ret; | |
134 | ||
c95869e5 | 135 | gpio_priv = devm_kzalloc(component->dev, sizeof(*gpio_priv), GFP_KERNEL); |
9bf5c3d1 RJ |
136 | if (!gpio_priv) |
137 | return -ENOMEM; | |
138 | ac97->gpio_priv = gpio_priv; | |
c95869e5 | 139 | gpio_priv->component = component; |
9bf5c3d1 RJ |
140 | gpio_priv->gpio_chip = snd_soc_ac97_gpio_chip; |
141 | gpio_priv->gpio_chip.ngpio = AC97_NUM_GPIOS; | |
c95869e5 | 142 | gpio_priv->gpio_chip.parent = component->dev; |
9bf5c3d1 RJ |
143 | gpio_priv->gpio_chip.base = -1; |
144 | ||
f7cb5120 | 145 | ret = gpiochip_add_data(&gpio_priv->gpio_chip, gpio_priv); |
9bf5c3d1 | 146 | if (ret != 0) |
c95869e5 | 147 | dev_err(component->dev, "Failed to add GPIOs: %d\n", ret); |
9bf5c3d1 RJ |
148 | return ret; |
149 | } | |
150 | ||
151 | static void snd_soc_ac97_free_gpio(struct snd_ac97 *ac97) | |
152 | { | |
153 | gpiochip_remove(&ac97->gpio_priv->gpio_chip); | |
154 | } | |
155 | #else | |
156 | static int snd_soc_ac97_init_gpio(struct snd_ac97 *ac97, | |
c95869e5 | 157 | struct snd_soc_component *component) |
9bf5c3d1 RJ |
158 | { |
159 | return 0; | |
160 | } | |
161 | ||
162 | static void snd_soc_ac97_free_gpio(struct snd_ac97 *ac97) | |
163 | { | |
164 | } | |
165 | #endif | |
166 | ||
336b8423 | 167 | /** |
c95869e5 KM |
168 | * snd_soc_alloc_ac97_component() - Allocate new a AC'97 device |
169 | * @component: The COMPONENT for which to create the AC'97 device | |
336b8423 | 170 | * |
47e03941 LPC |
171 | * Allocated a new snd_ac97 device and intializes it, but does not yet register |
172 | * it. The caller is responsible to either call device_add(&ac97->dev) to | |
173 | * register the device, or to call put_device(&ac97->dev) to free the device. | |
174 | * | |
175 | * Returns: A snd_ac97 device or a PTR_ERR in case of an error. | |
336b8423 | 176 | */ |
c95869e5 | 177 | struct snd_ac97 *snd_soc_alloc_ac97_component(struct snd_soc_component *component) |
336b8423 | 178 | { |
358a8bb5 | 179 | struct snd_ac97 *ac97; |
6794f709 | 180 | |
358a8bb5 LPC |
181 | ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); |
182 | if (ac97 == NULL) | |
183 | return ERR_PTR(-ENOMEM); | |
336b8423 | 184 | |
358a8bb5 LPC |
185 | ac97->bus = &soc_ac97_bus; |
186 | ac97->num = 0; | |
6794f709 | 187 | |
358a8bb5 | 188 | ac97->dev.bus = &ac97_bus_type; |
c95869e5 | 189 | ac97->dev.parent = component->card->dev; |
358a8bb5 | 190 | ac97->dev.release = soc_ac97_device_release; |
336b8423 | 191 | |
358a8bb5 | 192 | dev_set_name(&ac97->dev, "%d-%d:%s", |
c95869e5 KM |
193 | component->card->snd_card->number, 0, |
194 | component->name); | |
6794f709 | 195 | |
47e03941 LPC |
196 | device_initialize(&ac97->dev); |
197 | ||
198 | return ac97; | |
199 | } | |
c95869e5 | 200 | EXPORT_SYMBOL(snd_soc_alloc_ac97_component); |
47e03941 LPC |
201 | |
202 | /** | |
c95869e5 KM |
203 | * snd_soc_new_ac97_component - initailise AC97 device |
204 | * @component: audio component | |
7361fbea LPC |
205 | * @id: The expected device ID |
206 | * @id_mask: Mask that is applied to the device ID before comparing with @id | |
47e03941 | 207 | * |
c95869e5 | 208 | * Initialises AC97 component resources for use by ad-hoc devices only. |
7361fbea LPC |
209 | * |
210 | * If @id is not 0 this function will reset the device, then read the ID from | |
211 | * the device and check if it matches the expected ID. If it doesn't match an | |
212 | * error will be returned and device will not be registered. | |
213 | * | |
214 | * Returns: A PTR_ERR() on failure or a valid snd_ac97 struct on success. | |
47e03941 | 215 | */ |
c95869e5 | 216 | struct snd_ac97 *snd_soc_new_ac97_component(struct snd_soc_component *component, |
7361fbea | 217 | unsigned int id, unsigned int id_mask) |
47e03941 LPC |
218 | { |
219 | struct snd_ac97 *ac97; | |
220 | int ret; | |
221 | ||
c95869e5 | 222 | ac97 = snd_soc_alloc_ac97_component(component); |
47e03941 LPC |
223 | if (IS_ERR(ac97)) |
224 | return ac97; | |
225 | ||
7361fbea LPC |
226 | if (id) { |
227 | ret = snd_ac97_reset(ac97, false, id, id_mask); | |
228 | if (ret < 0) { | |
c95869e5 | 229 | dev_err(component->dev, "Failed to reset AC97 device: %d\n", |
7361fbea LPC |
230 | ret); |
231 | goto err_put_device; | |
232 | } | |
358a8bb5 | 233 | } |
336b8423 | 234 | |
7361fbea LPC |
235 | ret = device_add(&ac97->dev); |
236 | if (ret) | |
237 | goto err_put_device; | |
238 | ||
c95869e5 | 239 | ret = snd_soc_ac97_init_gpio(ac97, component); |
9bf5c3d1 RJ |
240 | if (ret) |
241 | goto err_put_device; | |
242 | ||
358a8bb5 | 243 | return ac97; |
7361fbea LPC |
244 | |
245 | err_put_device: | |
246 | put_device(&ac97->dev); | |
247 | return ERR_PTR(ret); | |
336b8423 | 248 | } |
c95869e5 | 249 | EXPORT_SYMBOL_GPL(snd_soc_new_ac97_component); |
336b8423 LPC |
250 | |
251 | /** | |
c95869e5 | 252 | * snd_soc_free_ac97_component - free AC97 component device |
8abab35f | 253 | * @ac97: snd_ac97 device to be freed |
336b8423 | 254 | * |
c95869e5 | 255 | * Frees AC97 component device resources. |
336b8423 | 256 | */ |
c95869e5 | 257 | void snd_soc_free_ac97_component(struct snd_ac97 *ac97) |
336b8423 | 258 | { |
9bf5c3d1 | 259 | snd_soc_ac97_free_gpio(ac97); |
358a8bb5 LPC |
260 | device_del(&ac97->dev); |
261 | ac97->bus = NULL; | |
262 | put_device(&ac97->dev); | |
336b8423 | 263 | } |
c95869e5 | 264 | EXPORT_SYMBOL_GPL(snd_soc_free_ac97_component); |
336b8423 LPC |
265 | |
266 | static struct snd_ac97_reset_cfg snd_ac97_rst_cfg; | |
267 | ||
268 | static void snd_soc_ac97_warm_reset(struct snd_ac97 *ac97) | |
269 | { | |
270 | struct pinctrl *pctl = snd_ac97_rst_cfg.pctl; | |
271 | ||
272 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_warm_reset); | |
273 | ||
274 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 1); | |
275 | ||
276 | udelay(10); | |
277 | ||
278 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0); | |
279 | ||
280 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run); | |
281 | msleep(2); | |
282 | } | |
283 | ||
284 | static void snd_soc_ac97_reset(struct snd_ac97 *ac97) | |
285 | { | |
286 | struct pinctrl *pctl = snd_ac97_rst_cfg.pctl; | |
287 | ||
288 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_reset); | |
289 | ||
290 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0); | |
291 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sdata, 0); | |
292 | gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 0); | |
293 | ||
294 | udelay(10); | |
295 | ||
296 | gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 1); | |
297 | ||
298 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run); | |
299 | msleep(2); | |
300 | } | |
301 | ||
302 | static int snd_soc_ac97_parse_pinctl(struct device *dev, | |
303 | struct snd_ac97_reset_cfg *cfg) | |
304 | { | |
305 | struct pinctrl *p; | |
306 | struct pinctrl_state *state; | |
307 | int gpio; | |
308 | int ret; | |
309 | ||
310 | p = devm_pinctrl_get(dev); | |
311 | if (IS_ERR(p)) { | |
312 | dev_err(dev, "Failed to get pinctrl\n"); | |
313 | return PTR_ERR(p); | |
314 | } | |
315 | cfg->pctl = p; | |
316 | ||
317 | state = pinctrl_lookup_state(p, "ac97-reset"); | |
318 | if (IS_ERR(state)) { | |
319 | dev_err(dev, "Can't find pinctrl state ac97-reset\n"); | |
320 | return PTR_ERR(state); | |
321 | } | |
322 | cfg->pstate_reset = state; | |
323 | ||
324 | state = pinctrl_lookup_state(p, "ac97-warm-reset"); | |
325 | if (IS_ERR(state)) { | |
326 | dev_err(dev, "Can't find pinctrl state ac97-warm-reset\n"); | |
327 | return PTR_ERR(state); | |
328 | } | |
329 | cfg->pstate_warm_reset = state; | |
330 | ||
331 | state = pinctrl_lookup_state(p, "ac97-running"); | |
332 | if (IS_ERR(state)) { | |
333 | dev_err(dev, "Can't find pinctrl state ac97-running\n"); | |
334 | return PTR_ERR(state); | |
335 | } | |
336 | cfg->pstate_run = state; | |
337 | ||
338 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 0); | |
339 | if (gpio < 0) { | |
340 | dev_err(dev, "Can't find ac97-sync gpio\n"); | |
341 | return gpio; | |
342 | } | |
343 | ret = devm_gpio_request(dev, gpio, "AC97 link sync"); | |
344 | if (ret) { | |
345 | dev_err(dev, "Failed requesting ac97-sync gpio\n"); | |
346 | return ret; | |
347 | } | |
348 | cfg->gpio_sync = gpio; | |
349 | ||
350 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 1); | |
351 | if (gpio < 0) { | |
352 | dev_err(dev, "Can't find ac97-sdata gpio %d\n", gpio); | |
353 | return gpio; | |
354 | } | |
355 | ret = devm_gpio_request(dev, gpio, "AC97 link sdata"); | |
356 | if (ret) { | |
357 | dev_err(dev, "Failed requesting ac97-sdata gpio\n"); | |
358 | return ret; | |
359 | } | |
360 | cfg->gpio_sdata = gpio; | |
361 | ||
362 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 2); | |
363 | if (gpio < 0) { | |
364 | dev_err(dev, "Can't find ac97-reset gpio\n"); | |
365 | return gpio; | |
366 | } | |
367 | ret = devm_gpio_request(dev, gpio, "AC97 link reset"); | |
368 | if (ret) { | |
369 | dev_err(dev, "Failed requesting ac97-reset gpio\n"); | |
370 | return ret; | |
371 | } | |
372 | cfg->gpio_reset = gpio; | |
373 | ||
374 | return 0; | |
375 | } | |
376 | ||
377 | struct snd_ac97_bus_ops *soc_ac97_ops; | |
378 | EXPORT_SYMBOL_GPL(soc_ac97_ops); | |
379 | ||
380 | int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops) | |
381 | { | |
382 | if (ops == soc_ac97_ops) | |
383 | return 0; | |
384 | ||
385 | if (soc_ac97_ops && ops) | |
386 | return -EBUSY; | |
387 | ||
388 | soc_ac97_ops = ops; | |
eda1a701 | 389 | soc_ac97_bus.ops = ops; |
336b8423 LPC |
390 | |
391 | return 0; | |
392 | } | |
393 | EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops); | |
394 | ||
395 | /** | |
396 | * snd_soc_set_ac97_ops_of_reset - Set ac97 ops with generic ac97 reset functions | |
397 | * | |
398 | * This function sets the reset and warm_reset properties of ops and parses | |
399 | * the device node of pdev to get pinctrl states and gpio numbers to use. | |
400 | */ | |
401 | int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops, | |
402 | struct platform_device *pdev) | |
403 | { | |
404 | struct device *dev = &pdev->dev; | |
405 | struct snd_ac97_reset_cfg cfg; | |
406 | int ret; | |
407 | ||
408 | ret = snd_soc_ac97_parse_pinctl(dev, &cfg); | |
409 | if (ret) | |
410 | return ret; | |
411 | ||
412 | ret = snd_soc_set_ac97_ops(ops); | |
413 | if (ret) | |
414 | return ret; | |
415 | ||
416 | ops->warm_reset = snd_soc_ac97_warm_reset; | |
417 | ops->reset = snd_soc_ac97_reset; | |
418 | ||
419 | snd_ac97_rst_cfg = cfg; | |
420 | return 0; | |
421 | } | |
422 | EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset); |