.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Codec driver for ST STA32x 2.1-channel high-efficiency digital audio system |
---|
3 | 4 | * |
---|
.. | .. |
---|
9 | 10 | * Mark Brown <broonie@opensource.wolfsonmicro.com> |
---|
10 | 11 | * Freescale Semiconductor, Inc. |
---|
11 | 12 | * Timur Tabi <timur@freescale.com> |
---|
12 | | - * |
---|
13 | | - * This program is free software; you can redistribute it and/or modify it |
---|
14 | | - * under the terms of the GNU General Public License as published by the |
---|
15 | | - * Free Software Foundation; either version 2 of the License, or (at your |
---|
16 | | - * option) any later version. |
---|
17 | 13 | */ |
---|
18 | 14 | |
---|
19 | 15 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__ |
---|
.. | .. |
---|
21 | 17 | #include <linux/module.h> |
---|
22 | 18 | #include <linux/moduleparam.h> |
---|
23 | 19 | #include <linux/init.h> |
---|
| 20 | +#include <linux/clk.h> |
---|
24 | 21 | #include <linux/delay.h> |
---|
25 | 22 | #include <linux/pm.h> |
---|
26 | 23 | #include <linux/i2c.h> |
---|
.. | .. |
---|
142 | 139 | /* codec private data */ |
---|
143 | 140 | struct sta32x_priv { |
---|
144 | 141 | struct regmap *regmap; |
---|
| 142 | + struct clk *xti_clk; |
---|
145 | 143 | struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)]; |
---|
146 | 144 | struct snd_soc_component *component; |
---|
147 | 145 | struct sta32x_platform_data *pdata; |
---|
.. | .. |
---|
399 | 397 | unsigned int confa, confa_cached; |
---|
400 | 398 | |
---|
401 | 399 | /* check if sta32x has reset itself */ |
---|
402 | | - confa_cached = snd_soc_component_read32(component, STA32X_CONFA); |
---|
| 400 | + confa_cached = snd_soc_component_read(component, STA32X_CONFA); |
---|
403 | 401 | regcache_cache_bypass(sta32x->regmap, true); |
---|
404 | | - confa = snd_soc_component_read32(component, STA32X_CONFA); |
---|
| 402 | + confa = snd_soc_component_read(component, STA32X_CONFA); |
---|
405 | 403 | regcache_cache_bypass(sta32x->regmap, false); |
---|
406 | 404 | if (confa != confa_cached) { |
---|
407 | 405 | regcache_mark_dirty(sta32x->regmap); |
---|
.. | .. |
---|
699 | 697 | switch (params_width(params)) { |
---|
700 | 698 | case 24: |
---|
701 | 699 | dev_dbg(component->dev, "24bit\n"); |
---|
702 | | - /* fall through */ |
---|
| 700 | + fallthrough; |
---|
703 | 701 | case 32: |
---|
704 | 702 | dev_dbg(component->dev, "24bit or 32bit\n"); |
---|
705 | 703 | switch (sta32x->format) { |
---|
.. | .. |
---|
882 | 880 | |
---|
883 | 881 | sta32x->component = component; |
---|
884 | 882 | |
---|
| 883 | + if (sta32x->xti_clk) { |
---|
| 884 | + ret = clk_prepare_enable(sta32x->xti_clk); |
---|
| 885 | + if (ret != 0) { |
---|
| 886 | + dev_err(component->dev, |
---|
| 887 | + "Failed to enable clock: %d\n", ret); |
---|
| 888 | + return ret; |
---|
| 889 | + } |
---|
| 890 | + } |
---|
| 891 | + |
---|
885 | 892 | ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), |
---|
886 | 893 | sta32x->supplies); |
---|
887 | 894 | if (ret != 0) { |
---|
888 | 895 | dev_err(component->dev, "Failed to enable supplies: %d\n", ret); |
---|
889 | | - return ret; |
---|
| 896 | + goto err_clk_disable_unprepare; |
---|
890 | 897 | } |
---|
891 | 898 | |
---|
892 | 899 | ret = sta32x_startup_sequence(sta32x); |
---|
893 | 900 | if (ret < 0) { |
---|
894 | 901 | dev_err(component->dev, "Failed to startup device\n"); |
---|
895 | | - return ret; |
---|
| 902 | + goto err_regulator_bulk_disable; |
---|
896 | 903 | } |
---|
897 | 904 | |
---|
898 | 905 | /* CONFA */ |
---|
.. | .. |
---|
976 | 983 | regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); |
---|
977 | 984 | |
---|
978 | 985 | return 0; |
---|
| 986 | + |
---|
| 987 | +err_regulator_bulk_disable: |
---|
| 988 | + regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); |
---|
| 989 | +err_clk_disable_unprepare: |
---|
| 990 | + if (sta32x->xti_clk) |
---|
| 991 | + clk_disable_unprepare(sta32x->xti_clk); |
---|
| 992 | + return ret; |
---|
979 | 993 | } |
---|
980 | 994 | |
---|
981 | 995 | static void sta32x_remove(struct snd_soc_component *component) |
---|
.. | .. |
---|
984 | 998 | |
---|
985 | 999 | sta32x_watchdog_stop(sta32x); |
---|
986 | 1000 | regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); |
---|
| 1001 | + |
---|
| 1002 | + if (sta32x->xti_clk) |
---|
| 1003 | + clk_disable_unprepare(sta32x->xti_clk); |
---|
987 | 1004 | } |
---|
988 | 1005 | |
---|
989 | 1006 | static const struct snd_soc_component_driver sta32x_component = { |
---|
.. | .. |
---|
1041 | 1058 | of_property_read_u8(np, "st,ch3-output-mapping", |
---|
1042 | 1059 | &pdata->ch3_output_mapping); |
---|
1043 | 1060 | |
---|
| 1061 | + if (of_get_property(np, "st,fault-detect-recovery", NULL)) |
---|
| 1062 | + pdata->fault_detect_recovery = 1; |
---|
1044 | 1063 | if (of_get_property(np, "st,thermal-warning-recovery", NULL)) |
---|
1045 | 1064 | pdata->thermal_warning_recovery = 1; |
---|
1046 | 1065 | if (of_get_property(np, "st,thermal-warning-adjustment", NULL)) |
---|
.. | .. |
---|
1098 | 1117 | } |
---|
1099 | 1118 | #endif |
---|
1100 | 1119 | |
---|
| 1120 | + /* Clock */ |
---|
| 1121 | + sta32x->xti_clk = devm_clk_get(dev, "xti"); |
---|
| 1122 | + if (IS_ERR(sta32x->xti_clk)) { |
---|
| 1123 | + ret = PTR_ERR(sta32x->xti_clk); |
---|
| 1124 | + |
---|
| 1125 | + if (ret == -EPROBE_DEFER) |
---|
| 1126 | + return ret; |
---|
| 1127 | + |
---|
| 1128 | + sta32x->xti_clk = NULL; |
---|
| 1129 | + } |
---|
| 1130 | + |
---|
1101 | 1131 | /* GPIOs */ |
---|
1102 | 1132 | sta32x->gpiod_nreset = devm_gpiod_get_optional(dev, "reset", |
---|
1103 | 1133 | GPIOD_OUT_LOW); |
---|