2 * USB analog headset driver
4 * Copyright (c) 2016 WangNannan <wangnannan@xiaomi.com>
5 * Copyright (C) 2017 XiaoMi, Inc.
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.
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.
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.
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>
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"
38 #define pr_debug pr_err
40 #define dev_dbg dev_err
42 #define pr_info pr_err
45 #define USBHS_SWITCH_AUDIO 0
46 #define USBHS_SWITCH_USB 1
49 struct power_supply *psy;
50 struct notifier_block power_supply_notifier;
51 struct work_struct psy_work;
56 enum of_gpio_flags asel_flags;
58 enum of_gpio_flags hsdet_flags;
59 struct device_node *us_euro_en_gpio_p;
62 static struct usb_headset *usb_hs;
64 static void usbhs_select(struct usb_headset *usbhs, bool audio)
66 if (gpio_is_valid(usbhs->asel_gpio)) {
68 if (usbhs->asel_flags == OF_GPIO_ACTIVE_LOW)
69 gpio_set_value(usbhs->asel_gpio, 0);
71 gpio_set_value(usbhs->asel_gpio, 1);
73 if (usbhs->asel_flags == OF_GPIO_ACTIVE_LOW)
74 gpio_set_value(usbhs->asel_gpio, 1);
76 gpio_set_value(usbhs->asel_gpio, 0);
81 static void usbhs_detect(struct usb_headset *usbhs, bool inserted)
83 if (gpio_is_valid(usbhs->hsdet_gpio)) {
85 if (usbhs->hsdet_flags == OF_GPIO_ACTIVE_LOW)
86 gpio_set_value(usbhs->hsdet_gpio, 0);
88 gpio_set_value(usbhs->hsdet_gpio, 1);
90 if (usbhs->hsdet_flags == OF_GPIO_ACTIVE_LOW)
91 gpio_set_value(usbhs->hsdet_gpio, 1);
93 gpio_set_value(usbhs->hsdet_gpio, 0);
98 static void usbhs_switch_state(struct usb_headset *usbhs)
100 union power_supply_propval pval;
102 memset(&pval, 0, sizeof(pval));
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)
118 usbhs_select(usbhs, true);
119 usbhs_detect(usbhs, true);
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__);
135 pr_err("%s: Invalid mode %d\n", __func__, usbhs->typec_mode);
140 static int usbhs_get_typec_mode(struct usb_headset *usbhs)
143 union power_supply_propval prop;
145 ret = power_supply_get_property(usbhs->psy, POWER_SUPPLY_PROP_TYPEC_MODE, &prop);
147 pr_err("%s: Cannot get typec mode property %d\n", __func__, ret);
151 pr_debug("%s: Type-C mode is %d\n", __func__, prop.intval);
155 static void usbhs_psy_work(struct work_struct *work)
157 struct usb_headset *usbhs = container_of(work, struct usb_headset, psy_work);
159 pr_debug("%s: Switch state to %d\n", __func__, usbhs->typec_mode);
160 usbhs_switch_state(usbhs);
163 static int usbhs_power_supply_event(struct notifier_block *nb, unsigned long event, void *ptr)
165 struct usb_headset *usbhs = container_of(nb, struct usb_headset, power_supply_notifier);
168 if (ptr != usbhs->psy || event != PSY_EVENT_PROP_CHANGED)
171 if (strncmp(usbhs->psy->desc->name, "usb", strlen("usb")) != 0)
174 pr_debug("%s: enter\n", __func__);
175 mode = usbhs_get_typec_mode(usbhs);
177 pr_err("%s: Unable to read USB TYPEC_MODE: %d\n", __func__, 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)
188 usbhs->typec_mode = mode;
189 schedule_work(&usbhs->psy_work);
198 static int usbhs_parse_dt(struct device *dev, struct usb_headset *usbhs)
200 struct device_node *np = dev->of_node;
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__);
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);
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__);
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);
236 int usbhs_init(struct platform_device *pdev)
239 struct usb_headset *usbhs;
241 if (!pdev->dev.of_node) {
242 pr_err("%s: Invalid platform data!\n", __func__);
246 usbhs = devm_kzalloc(&pdev->dev,
247 sizeof(struct usb_headset), GFP_KERNEL);
249 pr_err("%s: Failed to allocate usbhs memory!", __func__);
253 ret = usbhs_parse_dt(&pdev->dev, usbhs);
255 pr_err("%s: Failed parsing device tree!\n", __func__);
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");
264 ret = gpio_request_one(usbhs->asel_gpio,
265 GPIOF_OUT_INIT_LOW, "usb_asel");
268 pr_err("%s: Unable to request asel gpio %d\n", __func__,
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");
279 ret = gpio_request_one(usbhs->hsdet_gpio,
280 GPIOF_OUT_INIT_LOW, "headset_detect");
283 pr_err("%s: Unable to request hsdet gpio %d\n", __func__,
289 if (usbhs->us_euro_en_gpio_p)
290 msm_cdc_pinctrl_select_sleep_state(usbhs->us_euro_en_gpio_p);
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__);
296 if (IS_ERR(usbhs->psy))
297 ret = PTR_ERR(usbhs->psy);
302 usbhs->power_supply_notifier.notifier_call = usbhs_power_supply_event;
303 ret = power_supply_reg_notifier(&usbhs->power_supply_notifier);
305 pr_err("%s: Error register power supply notifier!\n", __func__);
308 INIT_WORK(&usbhs->psy_work, usbhs_psy_work);
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);
317 pr_info("%s: succeeded\n", __func__);
322 power_supply_put(usbhs->psy);
324 gpio_free(usbhs->hsdet_gpio);
326 gpio_free(usbhs->asel_gpio);
328 devm_kfree(&pdev->dev, usbhs);
332 EXPORT_SYMBOL(usbhs_init);
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);
347 EXPORT_SYMBOL(usbhs_deinit);
349 MODULE_DESCRIPTION("USB Analog headset module");
350 MODULE_LICENSE("GPL");