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