blob: efb68187871a1f5febd6292fdf9ae2f64b7a894a [file] [log] [blame]
developere0cea0f2021-12-16 16:08:26 +08001// SPDX-License-Identifier: GPL-2.0
2
3#include <linux/module.h>
4#include <linux/init.h>
5
6
7#include <linux/kernel.h>
8#include <linux/err.h>
9#include <linux/delay.h>
10
11#include <linux/regmap.h>
12#include <linux/spi/spi.h>
13
14
15#include <sound/core.h>
16#include <sound/pcm.h>
17#include <sound/pcm_params.h>
18#include <sound/soc.h>
19#include <sound/tlv.h>
20
21#include "proslic_sys.h"
22#include "si3218x.h"
23#include "inc/proslic.h"
24#include "timer.h"
25
26#include "spi.h"
27
28#ifdef SI3218X
29#include "inc/si3218x.h"
30#include "inc/si3218x_intf.h"
31#endif
32
33#define NUMBER_OF_DEVICES 1
34#if defined(SI3218X)
35#define CHAN_PER_DEVICE 1
36#define NUMBER_OF_CHAN (NUMBER_OF_DEVICES*CHAN_PER_DEVICE)
37#define NUMBER_OF_PROSLIC (NUMBER_OF_CHAN)
38#define PROSLIC_DEVICE_TYPE SI3218X_TYPE
39#endif
40
41static int slic_init = 0;
42
43ctrl_S spiGciObj; /* User¡¦s control interface object */
44systemTimer_S timerObj; /* User¡¦s timer object */
45chanState ports[NUMBER_OF_CHAN]; /* User¡¦s channel object, which has
46 ** a member defined as
47 ** proslicChanType_ptr ProObj;
48 */
49/* Define ProSLIC control interface object */
50controlInterfaceType *ProHWIntf;
51/* Define array of ProSLIC device objects */
52ProslicDeviceType *ProSLICDevices[NUMBER_OF_PROSLIC];
53/* Define array of ProSLIC channel object pointers */
54proslicChanType_ptr arrayOfProslicChans[NUMBER_OF_CHAN];
55
56static int ProSLIC_HWInit(void)
57{
58 int32 i, result= 0;
59
60 printk ("%s()\n",__FUNCTION__);
61 /*
62 ** Step 1: (required)
63 ** Create ProSLIC Control Interface Object
64 */
65 ProSLIC_createControlInterface(&ProHWIntf);
66
67 /*
68 ** Step 2: (required)
69 ** Create ProSLIC Device Objects
70 */
71 for(i=0;i<NUMBER_OF_PROSLIC;i++)
72 {
73 ProSLIC_createDevice(&(ProSLICDevices[i]));
74 }
75
76 /*
77 ** Step 3: (required)
78 ** Create and initialize ProSLIC channel objects
79 ** Also initialize array pointers to user¡¦s proslic channel object
80 ** members to simplify initialization process.
81 */
82 for(i=0;i<NUMBER_OF_CHAN;i++)
83 {
84 ProSLIC_createChannel(&(ports[i].ProObj));
85 ProSLIC_SWInitChan(ports[i].ProObj,i,PROSLIC_DEVICE_TYPE,
86 ProSLICDevices[i/CHAN_PER_DEVICE],ProHWIntf);
87 arrayOfProslicChans[i] = ports[i].ProObj;
88 ProSLIC_setSWDebugMode(ports[i].ProObj,TRUE); /* optional */
89 }
90
91 /*
92 ** Step 4: (required)
93 ** Establish linkage between host objects/functions and
94 ** ProSLIC API
95 */
96 ProSLIC_setControlInterfaceCtrlObj (ProHWIntf, &spiGciObj);
97 ProSLIC_setControlInterfaceReset (ProHWIntf, ctrl_ResetWrapper);
98 ProSLIC_setControlInterfaceWriteRegister (ProHWIntf, ctrl_WriteRegisterWrapper);
99 ProSLIC_setControlInterfaceReadRegister (ProHWIntf, ctrl_ReadRegisterWrapper);
100 ProSLIC_setControlInterfaceWriteRAM (ProHWIntf, ctrl_WriteRAMWrapper);
101 ProSLIC_setControlInterfaceReadRAM (ProHWIntf, ctrl_ReadRAMWrapper);
102 ProSLIC_setControlInterfaceTimerObj (ProHWIntf, &timerObj);
103 ProSLIC_setControlInterfaceDelay (ProHWIntf, time_DelayWrapper);
104 ProSLIC_setControlInterfaceTimeElapsed (ProHWIntf, time_TimeElapsedWrapper);
105 ProSLIC_setControlInterfaceGetTime (ProHWIntf, time_GetTimeWrapper);
106 ProSLIC_setControlInterfaceSemaphore (ProHWIntf, NULL);
107
108 /*
109 ** Step 5: (system dependent)
110 ** Assert hardware Reset ¡V ensure VDD, PCLK, and FSYNC are present and stable
111 ** before releasing reset
112 */
113 ProSLIC_Reset(ports[0].ProObj);
114
115 /*
116 ** Step 6: (required)
117 ** Initialize device (loading of general parameters, calibrations,
118 ** dc-dc powerup, etc.)
119 */
120 ProSLIC_Init(arrayOfProslicChans,NUMBER_OF_CHAN);
121 for(i=0;i<NUMBER_OF_CHAN;i++)
122 {
123 if(arrayOfProslicChans[i]->error!=0)
124 {
125 printk("ProSLIC_Init[%d] ERR=%d\n",i,arrayOfProslicChans[i]->error);
126 return 0;
127 }
128 }
129
130
131 /*
132 ** Step 7: (design dependent)
133 ** Execute longitudinal balance calibration
134 ** or reload coefficients from factory LB cal
135 **
136 ** Note: all batteries should be up and stable prior to
137 ** executing the lb cal
138 */
139 ProSLIC_LBCal(arrayOfProslicChans,NUMBER_OF_CHAN);
140 for(i=0;i<NUMBER_OF_CHAN;i++)
141 {
142 ProSLIC_GetLBCalResultPacked(arrayOfProslicChans[i], &result);
143 printk("LBCal=0x%08X\n",result);
144 }
145
146 /*
147 ** Step 8: (design dependent)
148 ** Load custom configuration presets(generated using
149 ** ProSLIC API Config Tool)
150 */
151 for(i=0;i<NUMBER_OF_CHAN;i++)
152 {
153 ProSLIC_PCMTimeSlotSetup(ports[i].ProObj,0,0);
154 ProSLIC_DCFeedSetup(ports[i].ProObj,DCFEED_48V_20MA);
155 ProSLIC_RingSetup(ports[i].ProObj,RING_F20_45VRMS_0VDC_LPR);
156 ProSLIC_PCMSetup(ports[i].ProObj,PCM_16LIN_WB); /* PCM_DEFAULT_CONFIG */
157 ProSLIC_ZsynthSetup(ports[i].ProObj,ZSYN_600_0_0_30_0);
158 ProSLIC_ToneGenSetup(ports[i].ProObj,TONEGEN_FCC_DIAL);
159 }
160
161 for(i=0;i<NUMBER_OF_CHAN;i++)
162 {
163 ProSLIC_PCMStart(ports[i].ProObj);
164 }
165 for(i=0;i<NUMBER_OF_CHAN;i++)
166 {
167 ProSLIC_SetLinefeedStatus(ports[i].ProObj,LF_FWD_ACTIVE);
168 }
169
170 /*
171 ** Step 9: (required)
172 ** SLIC settings - set TX_START and RX_START to 1 and
173 ** disable Free-Run mode.
174 */
175 ProSLIC_WriteReg(ports[0].ProObj, 12, 1);
176 ProSLIC_WriteReg(ports[0].ProObj, 14, 1);
177 ProSLIC_WriteReg(ports[0].ProObj, 47, 1);
178
179 return 1;
180}
181
182static int si3218x_component_probe(struct snd_soc_component *component)
183{
184 dev_info(component->dev, "%s\n", __func__);
185 return 0;
186}
187
188static void si3218x_component_remove(struct snd_soc_component *component)
189{
190 struct si3218x_chip *chip = snd_soc_component_get_drvdata(component);
191
192 dev_info(component->dev, "%s\n", __func__);
193
194 chip->component = NULL;
195}
196
197static const struct snd_soc_dapm_widget si3218x_component_dapm_widgets[] = {
198 SND_SOC_DAPM_INPUT("VINP"),
199 SND_SOC_DAPM_OUTPUT("VOUTP"),
200};
201
202static const struct snd_soc_dapm_route si3218x_component_dapm_routes[] = {
203 { "VOUTP", NULL, "aif_playback"},
204 { "aif_capture", NULL, "VINP"},
205};
206
207static const char * const slic_control_str[] = {
208 "off", "on"
209};
210
211static const struct soc_enum si3218x_slic_enum[] = {
212 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slic_control_str),
213 slic_control_str),
214};
215
216static int si3218x_init_get(struct snd_kcontrol *kcontrol,
217 struct snd_ctl_elem_value *ucontrol)
218{
219 ucontrol->value.integer.value[0] = slic_init;
220
221 return 0;
222}
223
224static int si3218x_init_set(struct snd_kcontrol *kcontrol,
225 struct snd_ctl_elem_value *ucontrol)
226{
227 if (ucontrol->value.integer.value[0]) {
228 ProSLIC_HWInit();
229 slic_init = 1;
230 }
231
232 return 0;
233}
234
235static int si3218x_ring_get(struct snd_kcontrol *kcontrol,
236 struct snd_ctl_elem_value *ucontrol)
237{
238 if (!slic_init)
239 return 0;
240
241 ucontrol->value.integer.value[0] =
242 (ProSLIC_ReadReg(ports[0].ProObj,30) == 4) ? 1 : 0;
243 return 0;
244}
245
246static int si3218x_ring_set(struct snd_kcontrol *kcontrol,
247 struct snd_ctl_elem_value *ucontrol)
248{
249 if (!slic_init)
250 return 0;
251
252 if (ucontrol->value.integer.value[0])
253 ProSLIC_WriteReg(ports[0].ProObj, 30, 4);
254 else
255 ProSLIC_WriteReg(ports[0].ProObj, 30, 1);
256
257 return 0;
258}
259
260static const struct snd_kcontrol_new si3218x_component_snd_controls[] = {
261 SOC_ENUM_EXT("proslic_init", si3218x_slic_enum[0],
262 si3218x_init_get, si3218x_init_set),
263 SOC_ENUM_EXT("proslic_ring", si3218x_slic_enum[0],
264 si3218x_ring_get, si3218x_ring_set),
265};
266
267static const struct snd_soc_component_driver si3218x_component_driver = {
268 .probe = si3218x_component_probe,
269 .remove = si3218x_component_remove,
270
271 .controls = si3218x_component_snd_controls,
272 .num_controls = ARRAY_SIZE(si3218x_component_snd_controls),
273 .dapm_widgets = si3218x_component_dapm_widgets,
274 .num_dapm_widgets = ARRAY_SIZE(si3218x_component_dapm_widgets),
275 .dapm_routes = si3218x_component_dapm_routes,
276 .num_dapm_routes = ARRAY_SIZE(si3218x_component_dapm_routes),
277
278 .idle_bias_on = false,
279};
280
281static int si3218x_component_aif_hw_params(struct snd_pcm_substream *substream,
282 struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai)
283{
284 int word_len = params_physical_width(hw_params);
285 int aud_bit = params_width(hw_params);
286
287 dev_dbg(dai->dev, "format: 0x%08x\n", params_format(hw_params));
288 dev_dbg(dai->dev, "rate: 0x%08x\n", params_rate(hw_params));
289 dev_dbg(dai->dev, "word_len: %d, aud_bit: %d\n", word_len, aud_bit);
290 if (word_len > 32 || word_len < 16) {
291 dev_err(dai->dev, "not supported word length\n");
292 return -ENOTSUPP;
293 }
294
295 dev_dbg(dai->dev, "%s: --\n", __func__);
296 return 0;
297}
298
299static const struct snd_soc_dai_ops si3218x_component_aif_ops = {
300 .hw_params = si3218x_component_aif_hw_params,
301};
302
303#define STUB_RATES SNDRV_PCM_RATE_8000_192000
304#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
305 SNDRV_PCM_FMTBIT_U16_LE | \
306 SNDRV_PCM_FMTBIT_S24_LE | \
307 SNDRV_PCM_FMTBIT_U24_LE | \
308 SNDRV_PCM_FMTBIT_S32_LE | \
309 SNDRV_PCM_FMTBIT_U32_LE)
310
311static struct snd_soc_dai_driver si3218x_codec_dai = {
312 .name = "proslic_spi-aif",
313 .playback = {
314 .stream_name = "aif_playback",
315 .channels_min = 1,
316 .channels_max = 2,
317 .rates = STUB_RATES,
318 .formats = STUB_FORMATS,
319 },
320 .capture = {
321 .stream_name = "aif_capture",
322 .channels_min = 1,
323 .channels_max = 2,
324 .rates = STUB_RATES,
325 .formats = STUB_FORMATS,
326 },
327 /* dai properties */
328 .symmetric_rates = 1,
329 .symmetric_channels = 1,
330 .symmetric_samplebits = 1,
331 /* dai operations */
332 .ops = &si3218x_component_aif_ops,
333};
334
335int si3218x_spi_probe(struct spi_device *spi, struct spi_driver *spi_drv)
336{
337 int ret;
338
339 printk(KERN_INFO "PROSLIC si3218x_spi_probe\n");
340
341 ret = proslic_spi_probe(spi,spi_drv);
342
343 return snd_soc_register_component(&spi->dev, &si3218x_component_driver,
344 &si3218x_codec_dai, 1);
345}
346EXPORT_SYMBOL(si3218x_spi_probe);
347
348int si3218x_spi_remove(struct spi_device *spi)
349{
350 proslic_spi_remove(spi);
351 snd_soc_unregister_component(&spi->dev);
352
353 return 0;
354}
355EXPORT_SYMBOL(si3218x_spi_remove);