OSDN Git Service

sound: import xiaomi changes
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / sound / soc / codecs / usb-headset.c
1 /*
2  *  USB analog headset driver
3  *
4  *  Copyright (c) 2016 WangNannan <wangnannan@xiaomi.com>
5  *  Copyright (C) 2017 XiaoMi, Inc.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #define DEBUG
23 #include <linux/delay.h>
24 #include <linux/platform_device.h>
25 #include <linux/err.h>
26 #include <linux/module.h>
27 #include <linux/slab.h>
28 #include <linux/gpio.h>
29 #include <linux/power_supply.h>
30 #include <linux/regulator/consumer.h>
31 #include <linux/of.h>
32 #include <linux/of_gpio.h>
33 #include <linux/mfd/msm-cdc-pinctrl.h>
34 #include <soc/qcom/socinfo.h>
35 #include "usb-headset.h"
36
37 #undef pr_debug
38 #define pr_debug pr_err
39 #undef dev_dbg
40 #define dev_dbg dev_err
41 #undef pr_info
42 #define pr_info pr_err
43
44
45 #define USBHS_SWITCH_AUDIO              0
46 #define USBHS_SWITCH_USB                1
47
48 struct usb_headset {
49         struct power_supply *psy;
50         struct notifier_block power_supply_notifier;
51         struct work_struct psy_work;
52         int typec_mode;
53         int pr;
54
55         int asel_gpio;
56         enum of_gpio_flags asel_flags;
57         int hsdet_gpio;
58         enum of_gpio_flags hsdet_flags;
59         struct device_node *us_euro_en_gpio_p;
60 };
61
62 static struct usb_headset *usb_hs;
63
64 static void usbhs_select(struct usb_headset *usbhs, bool audio)
65 {
66         if (gpio_is_valid(usbhs->asel_gpio)) {
67                 if (audio) {
68                         if (usbhs->asel_flags == OF_GPIO_ACTIVE_LOW)
69                                 gpio_set_value(usbhs->asel_gpio, 0);
70                         else
71                                 gpio_set_value(usbhs->asel_gpio, 1);
72                 } else {
73                         if (usbhs->asel_flags == OF_GPIO_ACTIVE_LOW)
74                                 gpio_set_value(usbhs->asel_gpio, 1);
75                         else
76                                 gpio_set_value(usbhs->asel_gpio, 0);
77                 }
78         }
79 }
80
81 static void usbhs_detect(struct usb_headset *usbhs, bool inserted)
82 {
83         if (gpio_is_valid(usbhs->hsdet_gpio)) {
84                 if (inserted) {
85                         if (usbhs->hsdet_flags == OF_GPIO_ACTIVE_LOW)
86                                 gpio_set_value(usbhs->hsdet_gpio, 0);
87                         else
88                                 gpio_set_value(usbhs->hsdet_gpio, 1);
89                 } else {
90                         if (usbhs->hsdet_flags == OF_GPIO_ACTIVE_LOW)
91                                 gpio_set_value(usbhs->hsdet_gpio, 1);
92                         else
93                                 gpio_set_value(usbhs->hsdet_gpio, 0);
94                 }
95         }
96 }
97
98 static void usbhs_switch_state(struct usb_headset *usbhs)
99 {
100         union power_supply_propval pval;
101
102         memset(&pval, 0, sizeof(pval));
103
104         switch (usbhs->typec_mode) {
105         case POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER:
106                 pr_debug("%s: Switch to state AUDIO\n", __func__);
107                 power_supply_get_property(usbhs->psy, POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &pval);
108                 usbhs->pr = pval.intval;
109                 pr_info("%s: backup power role %d\n", __func__, pval.intval);
110                 pr_info("%s: set power role to SOURCE\n", __func__);
111                 pval.intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
112                 if (power_supply_set_property(usbhs->psy, POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &pval))
113                         pr_err("%s: force PR_SOURCE mode unsuccessful\n", __func__);
114                 if (usbhs->us_euro_en_gpio_p)
115                         msm_cdc_pinctrl_select_active_state(usbhs->us_euro_en_gpio_p);
116                 if (get_hw_version_platform() != HARDWARE_PLATFORM_SAGIT)
117                         msleep(200);
118                 usbhs_select(usbhs, true);
119                 usbhs_detect(usbhs, true);
120                 break;
121
122         case POWER_SUPPLY_TYPEC_NONE:
123                 pr_debug("%s: Switch to state USB\n", __func__);
124                 usbhs_detect(usbhs, false);
125                 if (usbhs->us_euro_en_gpio_p)
126                         msm_cdc_pinctrl_select_sleep_state(usbhs->us_euro_en_gpio_p);
127                 usbhs_select(usbhs, false);
128                 pr_info("%s: restore power role to %d\n", __func__, usbhs->pr);
129                 pval.intval = usbhs->pr;
130                 if (power_supply_set_property(usbhs->psy, POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &pval))
131                         pr_err("%s: force PR_DUAL mode unsuccessful\n", __func__);
132                 break;
133
134         default:
135                 pr_err("%s: Invalid mode %d\n", __func__, usbhs->typec_mode);
136                 break;
137         }
138 }
139
140 static int usbhs_get_typec_mode(struct usb_headset *usbhs)
141 {
142         int ret = 0;
143         union power_supply_propval prop;
144
145         ret = power_supply_get_property(usbhs->psy, POWER_SUPPLY_PROP_TYPEC_MODE, &prop);
146         if (ret < 0) {
147                 pr_err("%s: Cannot get typec mode property %d\n", __func__, ret);
148                 return ret;
149         }
150
151         pr_debug("%s: Type-C mode is %d\n", __func__, prop.intval);
152         return prop.intval;
153 }
154
155 static void usbhs_psy_work(struct work_struct *work)
156 {
157         struct usb_headset *usbhs = container_of(work, struct usb_headset, psy_work);
158
159         pr_debug("%s: Switch state to %d\n", __func__, usbhs->typec_mode);
160         usbhs_switch_state(usbhs);
161 }
162
163 static int usbhs_power_supply_event(struct notifier_block *nb, unsigned long event, void *ptr)
164 {
165         struct usb_headset *usbhs = container_of(nb, struct usb_headset, power_supply_notifier);
166         int mode;
167
168         if (ptr != usbhs->psy || event != PSY_EVENT_PROP_CHANGED)
169                 return 0;
170
171         if (strncmp(usbhs->psy->desc->name, "usb", strlen("usb")) != 0)
172                 return 0;
173
174         pr_debug("%s: enter\n", __func__);
175         mode = usbhs_get_typec_mode(usbhs);
176         if (mode < 0) {
177                 pr_err("%s: Unable to read USB TYPEC_MODE: %d\n", __func__, mode);
178                 return 0;
179         }
180
181         switch (mode) {
182         case POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER:
183         case POWER_SUPPLY_TYPEC_NONE:
184                 pr_debug("%s: typec mode %d to %d\n", __func__,
185                         usbhs->typec_mode, mode);
186                 if (usbhs->typec_mode == mode)
187                         break;
188                 usbhs->typec_mode = mode;
189                 schedule_work(&usbhs->psy_work);
190                 break;
191         default:
192                 break;
193         }
194
195         return 0;
196 }
197
198 static int usbhs_parse_dt(struct device *dev, struct usb_headset *usbhs)
199 {
200         struct device_node *np = dev->of_node;
201
202         usbhs->hsdet_gpio = of_get_named_gpio_flags(np, "qcom,hsdet-gpio",
203                                 0, &usbhs->hsdet_flags);
204         if (!gpio_is_valid(usbhs->hsdet_gpio))
205                 pr_info("%s: Not get hsdet gpio\n", __func__);
206
207         usbhs->asel_gpio = of_get_named_gpio_flags(np, "qcom,asel-gpio",
208                                         0, &usbhs->asel_flags);
209         switch (get_hw_version_platform()) {
210         case HARDWARE_PLATFORM_CHIRON:
211         case HARDWARE_PLATFORM_CHIRON_S:
212                 if ((get_hw_version_major() == 1) &&
213                     (get_hw_version_minor() == 0)) {
214                         usbhs->asel_gpio = of_get_named_gpio_flags(np, "qcom,asel-p1-gpio",
215                                                         0, &usbhs->asel_flags);
216                 }
217                 break;
218         default:
219                 break;
220         }
221
222         pr_info("%s: audio select gpio is %d\n", __func__, usbhs->asel_gpio);
223         if (!gpio_is_valid(usbhs->asel_gpio))
224                 pr_info("%s: Not get ASEL gpio\n", __func__);
225
226         usbhs->us_euro_en_gpio_p = of_parse_phandle(np,
227                                         "qcom,us-euro-switch-en-gpio", 0);
228         if (!usbhs->us_euro_en_gpio_p) {
229                 pr_info("%s: property %s not detected in node %s", __func__,
230                         "qcom,us-euro-switch-en-gpio", np->full_name);
231         }
232
233         return 0;
234 }
235
236 int usbhs_init(struct platform_device *pdev)
237 {
238         int ret = 0;
239         struct usb_headset *usbhs;
240
241         if (!pdev->dev.of_node) {
242                 pr_err("%s: Invalid platform data!\n", __func__);
243                 return -EINVAL;
244         }
245
246         usbhs = devm_kzalloc(&pdev->dev,
247                         sizeof(struct usb_headset), GFP_KERNEL);
248         if (!usbhs) {
249                 pr_err("%s: Failed to allocate usbhs memory!", __func__);
250                 return -ENOMEM;
251         }
252
253         ret = usbhs_parse_dt(&pdev->dev, usbhs);
254         if (ret < 0) {
255                 pr_err("%s: Failed parsing device tree!\n", __func__);
256                 goto err_free_usbhs;
257         }
258
259         if (gpio_is_valid(usbhs->asel_gpio)) {
260                 if (usbhs->asel_flags == OF_GPIO_ACTIVE_LOW) {
261                         ret = gpio_request_one(usbhs->asel_gpio,
262                                 GPIOF_OUT_INIT_HIGH, "usb_asel");
263                 } else {
264                         ret = gpio_request_one(usbhs->asel_gpio,
265                                 GPIOF_OUT_INIT_LOW, "usb_asel");
266                 }
267                 if (ret < 0) {
268                         pr_err("%s: Unable to request asel gpio %d\n", __func__,
269                                         usbhs->asel_gpio);
270                         goto err_free_usbhs;
271                 }
272         }
273
274         if (gpio_is_valid(usbhs->hsdet_gpio)) {
275                 if (usbhs->hsdet_flags == OF_GPIO_ACTIVE_LOW) {
276                         ret = gpio_request_one(usbhs->hsdet_gpio,
277                                 GPIOF_OUT_INIT_HIGH, "headset_detect");
278                 } else {
279                         ret = gpio_request_one(usbhs->hsdet_gpio,
280                                 GPIOF_OUT_INIT_LOW, "headset_detect");
281                 }
282                 if (ret < 0) {
283                         pr_err("%s: Unable to request hsdet gpio %d\n", __func__,
284                                         usbhs->hsdet_gpio);
285                         goto err_free_asel;
286                 }
287         }
288
289         if (usbhs->us_euro_en_gpio_p)
290                 msm_cdc_pinctrl_select_sleep_state(usbhs->us_euro_en_gpio_p);
291
292         usbhs->psy = power_supply_get_by_name("usb");
293         if (IS_ERR_OR_NULL(usbhs->psy)) {
294                 pr_err("%s: could not get USB psy info\n", __func__);
295                 ret = -EPROBE_DEFER;
296                 if (IS_ERR(usbhs->psy))
297                         ret = PTR_ERR(usbhs->psy);
298                 usbhs->psy = NULL;
299                 goto err_free_hsdet;
300         }
301
302         usbhs->power_supply_notifier.notifier_call = usbhs_power_supply_event;
303         ret = power_supply_reg_notifier(&usbhs->power_supply_notifier);
304         if (ret < 0) {
305                 pr_err("%s: Error register power supply notifier!\n", __func__);
306                 goto err_free_psy;
307         }
308         INIT_WORK(&usbhs->psy_work, usbhs_psy_work);
309
310         /* Set initial Type-C state */
311         usbhs->pr = POWER_SUPPLY_TYPEC_PR_DUAL;
312         usbhs->typec_mode = usbhs_get_typec_mode(usbhs);
313         pr_info("%s: Switch to initial Type-C state %d\n", __func__, usbhs->typec_mode);
314         usbhs_switch_state(usbhs);
315
316         usb_hs = usbhs;
317         pr_info("%s: succeeded\n", __func__);
318
319         return 0;
320
321 err_free_psy:
322         power_supply_put(usbhs->psy);
323 err_free_hsdet:
324         gpio_free(usbhs->hsdet_gpio);
325 err_free_asel:
326         gpio_free(usbhs->asel_gpio);
327 err_free_usbhs:
328         devm_kfree(&pdev->dev, usbhs);
329
330         return ret;
331 }
332 EXPORT_SYMBOL(usbhs_init);
333
334 void usbhs_deinit()
335 {
336         if (!usb_hs) {
337                 cancel_work_sync(&usb_hs->psy_work);
338                 power_supply_unreg_notifier(&usb_hs->power_supply_notifier);
339                 power_supply_put(usb_hs->psy);
340                 gpio_free(usb_hs->asel_gpio);
341                 gpio_free(usb_hs->hsdet_gpio);
342                 usb_hs = NULL;
343         }
344
345         return;
346 }
347 EXPORT_SYMBOL(usbhs_deinit);
348
349 MODULE_DESCRIPTION("USB Analog headset module");
350 MODULE_LICENSE("GPL");