• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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);