1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include <linux/iio/consumer.h>
10 #include <linux/platform_device.h>
11 #include "analog_headset.h"
12 #include "device_resource_if.h"
13 #include "osal_mem.h"
14 #include "securec.h"
15 #include "gpio_if.h"
16
17 #define HDF_LOG_TAG analog_headset_core
18
19 static struct HeadsetPdata *g_pdataInfo = NULL;
20 static struct HdfDeviceObject *g_hdfDevice = NULL;
InitHeadsetPdata(struct HeadsetPdata * pdata)21 static void InitHeadsetPdata(struct HeadsetPdata *pdata)
22 {
23 if (pdata == NULL) {
24 AUDIO_DEVICE_LOG_ERR("pdata is NULL!");
25 return;
26 }
27 if (g_hdfDevice == NULL) {
28 AUDIO_DEVICE_LOG_ERR("g_hdfDevice is NULL!");
29 return;
30 }
31
32 pdata->device = g_hdfDevice;
33 pdata->hsGpioFlags = 0;
34 pdata->hsGpio = 0;
35 pdata->hsInsertType = (pdata->hsGpioFlags & OF_GPIO_ACTIVE_LOW) ? HEADSET_IN_LOW : HEADSET_IN_HIGH;
36
37 /* hook */
38 pdata->hookGpio = 0;
39 pdata->hookDownType = 0;
40 pdata->isHookAdcMode = false;
41
42 /* mic */
43 #ifdef CONFIG_MODEM_MIC_SWITCH
44 pdata->micGpioFlags = 0;
45 pdata->hsGpio = 0;
46 pdata->hpMicIoValue = GPIO_VAL_LOW;
47 pdata->mainMicIoValue = GPIO_VAL_HIGH;
48 #endif
49
50 pdata->hsWakeup = true;
51 }
52
GpioDirectionInput(struct device * dev,uint32_t gpio,const char * label)53 static int32_t GpioDirectionInput(struct device *dev, uint32_t gpio, const char *label)
54 {
55 int32_t ret;
56
57 if ((dev == NULL) || (label == NULL)) {
58 AUDIO_DEVICE_LOG_ERR("dev or label is NULL.");
59 return -EINVAL;
60 }
61
62 ret = GpioSetDir(gpio, GPIO_DIR_IN);
63 if (ret < 0) {
64 AUDIO_DEVICE_LOG_ERR("[GpioSetDir] failed.");
65 return ret;
66 }
67
68 return ret;
69 }
70
TraceInfo(const struct HeadsetPdata * pdata)71 static int32_t TraceInfo(const struct HeadsetPdata *pdata)
72 {
73 if (pdata == NULL) {
74 AUDIO_DEVICE_LOG_ERR("pdata is null");
75 return -EINVAL;
76 }
77
78 AUDIO_DEVICE_LOG_DEBUG("hsGpioFlags = %d, isHookAdcMode = %s",
79 pdata->hsGpioFlags, pdata->isHookAdcMode ? "true" : "false");
80 #ifdef CONFIG_MODEM_MIC_SWITCH
81 AUDIO_DEVICE_LOG_DEBUG("micGpioFlags = %d, micSwitchGpio = %u, hpMicIoValue = %u, mainMicIoValue = %u.",
82 pdata->micGpioFlags, pdata->micSwitchGpio, pdata->hpMicIoValue, pdata->mainMicIoValue);
83 #endif
84
85 AUDIO_DEVICE_LOG_DEBUG("hsGpio = %u, hookGpio = %u, hookDownType = %u, hsWakeup = %s.",
86 pdata->hsGpio, pdata->hookGpio, pdata->hookDownType, pdata->hsWakeup ? "true" : "false");
87
88 return 0;
89 }
90
LinuxReadMicConfig(struct device_node * node,struct HeadsetPdata * pdata)91 static int32_t LinuxReadMicConfig(struct device_node *node, struct HeadsetPdata *pdata)
92 {
93 #ifdef CONFIG_MODEM_MIC_SWITCH
94 /* mic */
95 int32_t ret;
96
97 if ((node == NULL) || (pdata == NULL)) {
98 AUDIO_DEVICE_LOG_ERR("node or pdata is NULL.");
99 return -EINVAL;
100 }
101
102 ret = of_get_named_gpio_flags(node, "mic_switch_gpio", 0, &pdata->micGpioFlags);
103 if (ret < 0) {
104 AUDIO_DEVICE_LOG_DEBUG("Can not read property micSwitchGpio.");
105 } else {
106 pdata->hsGpio = ret;
107 ret = of_property_read_u32(node, "hp_mic_io_value", &pdata->hpMicIoValue);
108 if (ret < 0) {
109 AUDIO_DEVICE_LOG_DEBUG("have not set hpMicIoValue ,so default set pull down low level.");
110 pdata->hpMicIoValue = GPIO_VAL_LOW;
111 }
112 ret = of_property_read_u32(node, "main_mic_io_value", &pdata->mainMicIoValue);
113 if (ret < 0) {
114 AUDIO_DEVICE_LOG_DEBUG("have not set mainMicIoValue ,so default set pull down low level.");
115 pdata->mainMicIoValue = GPIO_VAL_HIGH;
116 }
117 }
118 #endif
119
120 return 0;
121 }
122
LinuxReadConfig(struct device_node * node,struct HeadsetPdata * pdata)123 static int32_t LinuxReadConfig(struct device_node *node, struct HeadsetPdata *pdata)
124 {
125 int32_t ret;
126 int32_t wakeup;
127
128 if ((node == NULL) || (pdata == NULL)) {
129 AUDIO_DEVICE_LOG_ERR("node or pdata is NULL.");
130 return -EINVAL;
131 }
132
133 /* headset */
134 ret = of_get_named_gpio_flags(node, "headset_gpio", 0, &pdata->hsGpioFlags);
135 if (ret < 0) {
136 AUDIO_DEVICE_LOG_ERR("Can not read property hsGpio.");
137 return ret;
138 }
139 pdata->hsGpio = ret;
140 pdata->hsInsertType = (pdata->hsGpioFlags & OF_GPIO_ACTIVE_LOW) ? HEADSET_IN_LOW : HEADSET_IN_HIGH;
141
142 /* hook */
143 ret = of_get_named_gpio_flags(node, "hook_gpio", 0, &pdata->hookGpio);
144 if (ret < 0) {
145 AUDIO_DEVICE_LOG_WARNING("Can not read property hookGpio.");
146 pdata->hookGpio = 0;
147 /* adc mode */
148 pdata->isHookAdcMode = true;
149 } else {
150 ret = of_property_read_u32(node, "hook_down_type", &pdata->hookDownType);
151 if (ret < 0) {
152 AUDIO_DEVICE_LOG_WARNING("have not set hookDownType,set >hook< insert type low level default.");
153 pdata->hookDownType = 0;
154 }
155 pdata->isHookAdcMode = false;
156 }
157 /* mic */
158 (void)LinuxReadMicConfig(node, pdata);
159
160 ret = of_property_read_u32(node, "rockchip,headset_wakeup", &wakeup);
161 if (ret < 0) {
162 pdata->hsWakeup = true;
163 } else {
164 pdata->hsWakeup = (wakeup == 0) ? false : true;
165 }
166
167 return 0;
168 }
169
ReadHookModeConfig(struct DeviceResourceIface * parser,const struct DeviceResourceNode * node,struct HeadsetPdata * pdata)170 static int32_t ReadHookModeConfig(struct DeviceResourceIface *parser,
171 const struct DeviceResourceNode *node, struct HeadsetPdata *pdata)
172 {
173 int32_t ret;
174
175 if ((pdata == NULL) || (node == NULL) || (parser == NULL)) {
176 AUDIO_DEVICE_LOG_ERR("pdata, node or parser is NULL.");
177 return HDF_ERR_INVALID_PARAM;
178 }
179
180 pdata->isHookAdcMode = true;
181 ret = parser->GetUint32(node, "hook_gpio", &pdata->hookGpio, 0);
182 if (ret != HDF_SUCCESS) {
183 AUDIO_DEVICE_LOG_DEBUG("[GetUint32]-[hook_gpio] is null.");
184 pdata->isHookAdcMode = false;
185 }
186
187 if (pdata->isHookAdcMode) { /* hook adc mode */
188 AUDIO_DEVICE_LOG_DEBUG("headset have hook adc mode.");
189 ret = parser->GetUint32(node, "adc_controller_no", &pdata->adcConfig.devNum, 0);
190 if (ret != HDF_SUCCESS) {
191 AUDIO_DEVICE_LOG_ERR("[GetUint32]-[adc_controller_no] failed.");
192 return ret;
193 }
194 ret = parser->GetUint32(node, "adc_channel", &pdata->adcConfig.chanNo, 0);
195 if (ret != HDF_SUCCESS) {
196 AUDIO_DEVICE_LOG_ERR("[GetUint32]-[adc_channel] failed.");
197 return ret;
198 }
199 } else { /* hook interrupt mode */
200 ret = parser->GetUint32(node, "hook_down_type", &pdata->hookDownType, 0);
201 if (ret != HDF_SUCCESS) {
202 AUDIO_DEVICE_LOG_ERR("[GetUint32]-[hook_down_type] failed.");
203 return ret;
204 }
205 }
206 AUDIO_DEVICE_LOG_DEBUG("hook mode: %s.", pdata->isHookAdcMode ? "sar-adc" : "gpio-int");
207
208 return HDF_SUCCESS;
209 }
210
ReadMicConfig(struct DeviceResourceIface * parser,const struct DeviceResourceNode * node,struct HeadsetPdata * pdata)211 static int32_t ReadMicConfig(struct DeviceResourceIface *parser,
212 const struct DeviceResourceNode *node, struct HeadsetPdata *pdata)
213 {
214 #ifdef CONFIG_MODEM_MIC_SWITCH
215 /* mic */
216 int32_t ret;
217
218 if ((pdata == NULL) || (parser == NULL) || (node == NULL)) {
219 AUDIO_DEVICE_LOG_ERR("node or pdata is NULL.");
220 return HDF_ERR_INVALID_PARAM;
221 }
222
223 ret = parser->GetUint32(node, "mic_switch_gpio", &pdata->hsGpio, 0);
224 if (ret != HDF_SUCCESS) {
225 AUDIO_DEVICE_LOG_ERR("[mic_switch_gpio] failed.");
226 return ret;
227 }
228
229 ret = parser->GetUint32(node, "hp_mic_io_value", &pdata->hpMicIoValue, 0);
230 if (ret != HDF_SUCCESS) {
231 AUDIO_DEVICE_LOG_ERR("[hp_mic_io_value] failed.");
232 return ret;
233 }
234 ret = parser->GetUint32(node, "main_mic_io_value", &pdata->mainMicIoValue, 1);
235 if (ret != HDF_SUCCESS) {
236 AUDIO_DEVICE_LOG_ERR("[main_mic_io_value] failed.");
237 return ret;
238 }
239 #endif
240
241 return HDF_SUCCESS;
242 }
243
ReadConfig(const struct DeviceResourceNode * node,struct HeadsetPdata * pdata)244 static int32_t ReadConfig(const struct DeviceResourceNode *node, struct HeadsetPdata *pdata)
245 {
246 int32_t ret;
247 int32_t temp;
248 struct DeviceResourceIface *parser = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
249
250 if ((pdata == NULL) || (node == NULL) || (parser == NULL)) {
251 AUDIO_DEVICE_LOG_ERR("pdata, node or parser is NULL.");
252 return HDF_FAILURE;
253 }
254 ret = parser->GetString(node, "dev_name", &pdata->devName, NULL);
255 if (ret != HDF_SUCCESS) {
256 AUDIO_DEVICE_LOG_ERR("[GetString]-[dev_name] failed.");
257 return ret;
258 }
259 /* headset */
260 ret = parser->GetUint32(node, "headset_gpio", &pdata->hsGpio, 0);
261 if (ret != HDF_SUCCESS) {
262 AUDIO_DEVICE_LOG_ERR("[GetUint32]-[headset_gpio] failed.");
263 return ret;
264 }
265 ret = parser->GetUint32(node, "headset_gpio_flag", &pdata->hsGpioFlag, OF_GPIO_ACTIVE_LOW);
266 if (ret != HDF_SUCCESS) {
267 AUDIO_DEVICE_LOG_ERR("[GetUint32]-[headset_gpio_flag] failed.");
268 return ret;
269 }
270 /* hook */
271 ret = ReadHookModeConfig(parser, node, pdata);
272 if (ret != HDF_SUCCESS) {
273 AUDIO_DEVICE_LOG_ERR("[ReadHookModeConfig] failed.");
274 return ret;
275 }
276 /* mic */
277 (void)ReadMicConfig(parser, node, pdata);
278
279 ret = parser->GetUint32(node, "headset_wakeup", &temp, 0);
280 if (ret != HDF_SUCCESS) {
281 AUDIO_DEVICE_LOG_WARNING("[GetUint32]-[headset_wakeup] failed.");
282 temp = 1;
283 }
284 pdata->hsWakeup = (temp == 0) ? false : true;
285
286 return HDF_SUCCESS;
287 }
288
AnalogHeadsetInit(struct platform_device * pdev,struct HeadsetPdata * pdata)289 static int32_t AnalogHeadsetInit(struct platform_device *pdev, struct HeadsetPdata *pdata)
290 {
291 int32_t ret;
292
293 if ((pdev == NULL) || (pdata == NULL)) {
294 AUDIO_DEVICE_LOG_ERR("pdev or pdata is NULL.");
295 return -EINVAL;
296 }
297
298 /* headset */
299 ret = GpioSetDir(pdata->hsGpio, GPIO_DIR_IN);
300 if (ret < 0) {
301 AUDIO_DEVICE_LOG_ERR("[GpioSetDir]-[hsGpio] failed.");
302 return ret;
303 }
304
305 /* hook */
306 if (pdata->isHookAdcMode) {
307 pdata->chan = iio_channel_get(&pdev->dev, NULL);
308 if (IS_ERR(pdata->chan)) {
309 pdata->chan = NULL;
310 AUDIO_DEVICE_LOG_WARNING("have not set adc chan.");
311 }
312 } else {
313 ret = GpioSetDir(pdata->hookGpio, GPIO_DIR_IN);
314 if (ret < 0) {
315 AUDIO_DEVICE_LOG_ERR("[GpioSetDir]-[hookGpio] failed.");
316 return ret;
317 }
318 }
319
320 if (pdata->chan != NULL) { /* hook adc mode */
321 AUDIO_DEVICE_LOG_DEBUG("headset have hook adc mode.");
322 ret = AnalogHeadsetAdcInit(pdev, pdata);
323 if (ret < 0) {
324 AUDIO_DEVICE_LOG_ERR("[AnalogHeadsetAdcInit] failed.");
325 return ret;
326 }
327 } else { /* hook interrupt mode and not hook */
328 AUDIO_DEVICE_LOG_DEBUG("headset have %s mode.", pdata->hookGpio ? "interrupt hook" : "no hook");
329 ret = AnalogHeadsetGpioInit(pdev, pdata);
330 if (ret < 0) {
331 AUDIO_DEVICE_LOG_ERR("[AnalogHeadsetGpioInit] failed.");
332 return ret;
333 }
334 }
335 return ret;
336 }
337
AudioHeadsetProbe(struct platform_device * pdev)338 static int AudioHeadsetProbe(struct platform_device *pdev)
339 {
340 struct device_node *node = pdev->dev.of_node;
341 struct HeadsetPdata *pdata;
342 int32_t ret;
343
344 AUDIO_DEVICE_LOG_INFO("enter.");
345 pdata = (struct HeadsetPdata *)OsalMemCalloc(sizeof(*pdata));
346 if (pdata == NULL) {
347 AUDIO_DEVICE_LOG_ERR("[OsalMemCalloc] failed!");
348 return HDF_ERR_MALLOC_FAIL;
349 }
350 InitHeadsetPdata(pdata);
351 g_pdataInfo = pdata;
352
353 ret = LinuxReadConfig(node, pdata);
354 (void)TraceInfo(pdata);
355 if (ret < 0) {
356 AUDIO_DEVICE_LOG_ERR("[LinuxReadConfig] failed.");
357 return ret;
358 }
359
360 ret = AnalogHeadsetInit(pdev, pdata);
361 if (ret < 0) {
362 AUDIO_DEVICE_LOG_ERR("[AnalogHeadsetInit] failed.");
363 return ret;
364 }
365 AUDIO_DEVICE_LOG_INFO("success.");
366
367 return ret;
368 }
369
AudioHeadsetRemove(struct platform_device * pdev)370 static int AudioHeadsetRemove(struct platform_device *pdev)
371 {
372 (void)pdev;
373 return 0;
374 }
375
AudioHeadsetSuspend(struct platform_device * pdev,pm_message_t state)376 static int AudioHeadsetSuspend(struct platform_device *pdev, pm_message_t state)
377 {
378 if (g_pdataInfo->chan != NULL) {
379 return AnalogHeadsetAdcSuspend(pdev, state);
380 }
381 return 0;
382 }
383
AudioHeadsetResume(struct platform_device * pdev)384 static int AudioHeadsetResume(struct platform_device *pdev)
385 {
386 if (g_pdataInfo->chan != NULL) {
387 return AnalogHeadsetAdcResume(pdev);
388 }
389 return 0;
390 }
391
392 static const struct of_device_id g_headsetOfMatch[] = {
393 { .compatible = "rockchip_headset", },
394 {},
395 };
396 MODULE_DEVICE_TABLE(of, g_headsetOfMatch);
397
398 static struct platform_driver AudioHeadsetDriver = {
399 .probe = AudioHeadsetProbe,
400 .remove = AudioHeadsetRemove,
401 .resume = AudioHeadsetResume,
402 .suspend = AudioHeadsetSuspend,
403 .driver = {
404 .name = "rockchip_headset",
405 .owner = THIS_MODULE,
406 .of_match_table = of_match_ptr(g_headsetOfMatch),
407 },
408 };
409
HdfHeadsetBindDriver(struct HdfDeviceObject * device)410 static int32_t HdfHeadsetBindDriver(struct HdfDeviceObject *device)
411 {
412 if (device == NULL) {
413 AUDIO_DEVICE_LOG_ERR("device is NULL.");
414 return HDF_ERR_INVALID_PARAM;
415 }
416
417 g_hdfDevice = device;
418 g_pdataInfo = NULL;
419
420 return HDF_SUCCESS;
421 }
422
HdfHeadsetInit(struct HdfDeviceObject * device)423 static int32_t HdfHeadsetInit(struct HdfDeviceObject *device)
424 {
425 int32_t ret;
426 static struct IDeviceIoService headsetService = {
427 .object.objectId = 1,
428 };
429 const struct DeviceResourceNode *node = NULL;
430 static struct HeadsetPdata pdata;
431
432 AUDIO_DEVICE_LOG_INFO("enter.");
433 platform_driver_register(&AudioHeadsetDriver);
434 if (device == NULL) {
435 AUDIO_DEVICE_LOG_ERR(" is NULL.");
436 return HDF_ERR_INVALID_PARAM;
437 }
438
439 if (g_pdataInfo == NULL) {
440 AUDIO_DEVICE_LOG_ERR("g_pdataInfo is NULL!");
441 return HDF_ERR_MALLOC_FAIL;
442 }
443
444 node = device->property;
445 ret = ReadConfig(node, &pdata);
446 if (ret != HDF_SUCCESS) {
447 AUDIO_DEVICE_LOG_ERR("[ReadConfig] failed.");
448 }
449 (void)TraceInfo(&pdata);
450
451 g_pdataInfo->device = device;
452 g_pdataInfo->ioService = headsetService;
453 device->service = &g_pdataInfo->ioService;
454 device->priv = (void *)g_pdataInfo;
455 AUDIO_DEVICE_LOG_INFO("success.");
456
457 return HDF_SUCCESS;
458 }
459
HdfHeadsetExit(struct HdfDeviceObject * device)460 static void HdfHeadsetExit(struct HdfDeviceObject *device)
461 {
462 struct HeadsetPdata *drvData = NULL;
463
464 AUDIO_DEVICE_LOG_INFO("enter.");
465 if (device == NULL) {
466 AUDIO_DEVICE_LOG_ERR("device or device->service is NULL.");
467 return;
468 }
469
470 platform_driver_unregister(&AudioHeadsetDriver);
471
472 if ((device == NULL) || (device->priv == NULL)) {
473 AUDIO_DEVICE_LOG_ERR("device or device->priv is NULL.");
474 return;
475 }
476 drvData = (struct HeadsetPdata *)device->priv;
477 if (drvData->chan != NULL) { // hook adc mode
478 AnalogHeadsetAdcRelease(drvData);
479 } else { // hook interrupt mode and not hook
480 AnalogHeadsetGpioRelease(drvData);
481 }
482 OsalMemFree(drvData);
483 device->priv = NULL;
484 g_pdataInfo = NULL;
485 g_hdfDevice = NULL;
486
487 AUDIO_DEVICE_LOG_INFO("done.");
488 }
489
490 /* HdfDriverEntry definitions */
491 struct HdfDriverEntry g_headsetDevEntry = {
492 .moduleVersion = 1,
493 .moduleName = "AUDIO_ANALOG_HEADSET",
494 .Bind = HdfHeadsetBindDriver,
495 .Init = HdfHeadsetInit,
496 .Release = HdfHeadsetExit,
497 };
498
499 HDF_INIT(g_headsetDevEntry);