xref: /linux/sound/soc/codecs/tas2781-comlib.c (revision a9e6060bb2a6cae6d43a98ec0794844ad01273d3)
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // TAS2563/TAS2781 Common functions for HDA and ASoC Audio drivers
4 //
5 // Copyright 2023 - 2025 Texas Instruments, Inc.
6 //
7 // Author: Shenghao Ding <shenghao-ding@ti.com>
8 
9 #include <linux/crc8.h>
10 #include <linux/dev_printk.h>
11 #include <linux/firmware.h>
12 #include <linux/gpio/consumer.h>
13 #include <linux/init.h>
14 #include <linux/interrupt.h>
15 #include <linux/module.h>
16 #include <linux/of.h>
17 #include <linux/of_irq.h>
18 #include <linux/regmap.h>
19 #include <linux/slab.h>
20 #include <sound/tas2781.h>
21 
tasdevice_dev_read(struct tasdevice_priv * tas_priv,unsigned short chn,unsigned int reg,unsigned int * val)22 int tasdevice_dev_read(struct tasdevice_priv *tas_priv,
23 	unsigned short chn, unsigned int reg, unsigned int *val)
24 {
25 	int ret = 0;
26 
27 	if (chn < tas_priv->ndev) {
28 		struct regmap *map = tas_priv->regmap;
29 
30 		ret = tas_priv->change_chn_book(tas_priv, chn,
31 			TASDEVICE_BOOK_ID(reg));
32 		if (ret < 0)
33 			goto out;
34 
35 		ret = regmap_read(map, TASDEVICE_PGRG(reg), val);
36 		if (ret < 0)
37 			dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
38 	} else {
39 		ret = -EINVAL;
40 		dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
41 			chn);
42 	}
43 
44 out:
45 	return ret;
46 }
47 EXPORT_SYMBOL_GPL(tasdevice_dev_read);
48 
tasdevice_dev_bulk_read(struct tasdevice_priv * tas_priv,unsigned short chn,unsigned int reg,unsigned char * data,unsigned int len)49 int tasdevice_dev_bulk_read(struct tasdevice_priv *tas_priv,
50 	unsigned short chn, unsigned int reg, unsigned char *data,
51 	unsigned int len)
52 {
53 	int ret = 0;
54 
55 	if (chn < tas_priv->ndev) {
56 		struct regmap *map = tas_priv->regmap;
57 
58 		ret = tas_priv->change_chn_book(tas_priv, chn,
59 			TASDEVICE_BOOK_ID(reg));
60 		if (ret < 0)
61 			goto out;
62 
63 		ret = regmap_bulk_read(map, TASDEVICE_PGRG(reg), data, len);
64 		if (ret < 0)
65 			dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
66 	} else
67 		dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
68 			chn);
69 
70 out:
71 	return ret;
72 }
73 EXPORT_SYMBOL_GPL(tasdevice_dev_bulk_read);
74 
tasdevice_dev_write(struct tasdevice_priv * tas_priv,unsigned short chn,unsigned int reg,unsigned int value)75 int tasdevice_dev_write(struct tasdevice_priv *tas_priv,
76 	unsigned short chn, unsigned int reg, unsigned int value)
77 {
78 	int ret = 0;
79 
80 	if (chn < tas_priv->ndev) {
81 		struct regmap *map = tas_priv->regmap;
82 
83 		ret = tas_priv->change_chn_book(tas_priv, chn,
84 			TASDEVICE_BOOK_ID(reg));
85 		if (ret < 0)
86 			goto out;
87 
88 		ret = regmap_write(map, TASDEVICE_PGRG(reg),
89 			value);
90 		if (ret < 0)
91 			dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
92 	} else {
93 		ret = -EINVAL;
94 		dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
95 			chn);
96 	}
97 
98 out:
99 	return ret;
100 }
101 EXPORT_SYMBOL_GPL(tasdevice_dev_write);
102 
tasdevice_dev_bulk_write(struct tasdevice_priv * tas_priv,unsigned short chn,unsigned int reg,unsigned char * data,unsigned int len)103 int tasdevice_dev_bulk_write(
104 	struct tasdevice_priv *tas_priv, unsigned short chn,
105 	unsigned int reg, unsigned char *data,
106 	unsigned int len)
107 {
108 	int ret = 0;
109 
110 	if (chn < tas_priv->ndev) {
111 		struct regmap *map = tas_priv->regmap;
112 
113 		ret = tas_priv->change_chn_book(tas_priv, chn,
114 			TASDEVICE_BOOK_ID(reg));
115 		if (ret < 0)
116 			goto out;
117 
118 		ret = regmap_bulk_write(map, TASDEVICE_PGRG(reg),
119 			data, len);
120 		if (ret < 0)
121 			dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
122 	} else {
123 		ret = -EINVAL;
124 		dev_err(tas_priv->dev, "%s, no such channel(%d)\n", __func__,
125 			chn);
126 	}
127 
128 out:
129 	return ret;
130 }
131 EXPORT_SYMBOL_GPL(tasdevice_dev_bulk_write);
132 
tasdev_dsp_prog_blk_remove(struct tasdevice_prog * prog)133 static void tasdev_dsp_prog_blk_remove(struct tasdevice_prog *prog)
134 {
135 	struct tasdevice_data *tas_dt;
136 	struct tasdev_blk *blk;
137 	unsigned int i;
138 
139 	if (!prog)
140 		return;
141 
142 	tas_dt = &(prog->dev_data);
143 
144 	if (!tas_dt->dev_blks)
145 		return;
146 
147 	for (i = 0; i < tas_dt->nr_blk; i++) {
148 		blk = &(tas_dt->dev_blks[i]);
149 		kfree(blk->data);
150 	}
151 	kfree(tas_dt->dev_blks);
152 }
153 
tasdev_dsp_prog_remove(struct tasdevice_prog * prog,unsigned short nr)154 static void tasdev_dsp_prog_remove(struct tasdevice_prog *prog,
155 	unsigned short nr)
156 {
157 	int i;
158 
159 	for (i = 0; i < nr; i++)
160 		tasdev_dsp_prog_blk_remove(&prog[i]);
161 	kfree(prog);
162 }
163 
tasdev_dsp_cfg_blk_remove(struct tasdevice_config * cfg)164 static void tasdev_dsp_cfg_blk_remove(struct tasdevice_config *cfg)
165 {
166 	struct tasdevice_data *tas_dt;
167 	struct tasdev_blk *blk;
168 	unsigned int i;
169 
170 	if (cfg) {
171 		tas_dt = &(cfg->dev_data);
172 
173 		if (!tas_dt->dev_blks)
174 			return;
175 
176 		for (i = 0; i < tas_dt->nr_blk; i++) {
177 			blk = &(tas_dt->dev_blks[i]);
178 			kfree(blk->data);
179 		}
180 		kfree(tas_dt->dev_blks);
181 	}
182 }
183 
tasdev_dsp_cfg_remove(struct tasdevice_config * config,unsigned short nr)184 static void tasdev_dsp_cfg_remove(struct tasdevice_config *config,
185 	unsigned short nr)
186 {
187 	int i;
188 
189 	for (i = 0; i < nr; i++)
190 		tasdev_dsp_cfg_blk_remove(&config[i]);
191 	kfree(config);
192 }
193 
tasdevice_dsp_remove(void * context)194 void tasdevice_dsp_remove(void *context)
195 {
196 	struct tasdevice_priv *tas_dev = (struct tasdevice_priv *) context;
197 	struct tasdevice_fw *tas_fmw = tas_dev->fmw;
198 
199 	if (!tas_dev->fmw)
200 		return;
201 
202 	if (tas_fmw->programs)
203 		tasdev_dsp_prog_remove(tas_fmw->programs,
204 			tas_fmw->nr_programs);
205 	if (tas_fmw->configs)
206 		tasdev_dsp_cfg_remove(tas_fmw->configs,
207 			tas_fmw->nr_configurations);
208 	kfree(tas_fmw);
209 	tas_dev->fmw = NULL;
210 }
211 EXPORT_SYMBOL_GPL(tasdevice_dsp_remove);
212 
tasdevice_remove(struct tasdevice_priv * tas_priv)213 void tasdevice_remove(struct tasdevice_priv *tas_priv)
214 {
215 	mutex_destroy(&tas_priv->codec_lock);
216 }
217 EXPORT_SYMBOL_GPL(tasdevice_remove);
218 
219 MODULE_DESCRIPTION("TAS2781 common library");
220 MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
221 MODULE_LICENSE("GPL");
222