| .. | .. |
|---|
| 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); |
|---|