xref: /linux/drivers/usb/misc/qcom_eud.c (revision 6093a688a07da07808f0122f9aa2a3eed250d853)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
4  */
5 
6 #include <linux/bitops.h>
7 #include <linux/err.h>
8 #include <linux/interrupt.h>
9 #include <linux/io.h>
10 #include <linux/iopoll.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/of.h>
14 #include <linux/platform_device.h>
15 #include <linux/slab.h>
16 #include <linux/sysfs.h>
17 #include <linux/usb/role.h>
18 #include <linux/firmware/qcom/qcom_scm.h>
19 
20 #define EUD_REG_INT1_EN_MASK	0x0024
21 #define EUD_REG_INT_STATUS_1	0x0044
22 #define EUD_REG_CTL_OUT_1	0x0074
23 #define EUD_REG_VBUS_INT_CLR	0x0080
24 #define EUD_REG_CSR_EUD_EN	0x1014
25 #define EUD_REG_SW_ATTACH_DET	0x1018
26 #define EUD_REG_EUD_EN2		0x0000
27 
28 #define EUD_ENABLE		BIT(0)
29 #define EUD_INT_PET_EUD		BIT(0)
30 #define EUD_INT_VBUS		BIT(2)
31 #define EUD_INT_SAFE_MODE	BIT(4)
32 #define EUD_INT_ALL		(EUD_INT_VBUS | EUD_INT_SAFE_MODE)
33 
34 struct eud_chip {
35 	struct device			*dev;
36 	struct usb_role_switch		*role_sw;
37 	void __iomem			*base;
38 	phys_addr_t			mode_mgr;
39 	unsigned int			int_status;
40 	int				irq;
41 	bool				enabled;
42 	bool				usb_attached;
43 };
44 
45 static int enable_eud(struct eud_chip *priv)
46 {
47 	int ret;
48 
49 	ret = qcom_scm_io_writel(priv->mode_mgr + EUD_REG_EUD_EN2, 1);
50 	if (ret)
51 		return ret;
52 
53 	writel(EUD_ENABLE, priv->base + EUD_REG_CSR_EUD_EN);
54 	writel(EUD_INT_VBUS | EUD_INT_SAFE_MODE,
55 			priv->base + EUD_REG_INT1_EN_MASK);
56 
57 	return usb_role_switch_set_role(priv->role_sw, USB_ROLE_DEVICE);
58 }
59 
60 static int disable_eud(struct eud_chip *priv)
61 {
62 	int ret;
63 
64 	ret = qcom_scm_io_writel(priv->mode_mgr + EUD_REG_EUD_EN2, 0);
65 	if (ret)
66 		return ret;
67 
68 	writel(0, priv->base + EUD_REG_CSR_EUD_EN);
69 	return 0;
70 }
71 
72 static ssize_t enable_show(struct device *dev,
73 		struct device_attribute *attr, char *buf)
74 {
75 	struct eud_chip *chip = dev_get_drvdata(dev);
76 
77 	return sysfs_emit(buf, "%d\n", chip->enabled);
78 }
79 
80 static ssize_t enable_store(struct device *dev,
81 		struct device_attribute *attr,
82 		const char *buf, size_t count)
83 {
84 	struct eud_chip *chip = dev_get_drvdata(dev);
85 	bool enable;
86 	int ret;
87 
88 	if (kstrtobool(buf, &enable))
89 		return -EINVAL;
90 
91 	if (enable) {
92 		ret = enable_eud(chip);
93 		if (!ret)
94 			chip->enabled = enable;
95 		else
96 			disable_eud(chip);
97 
98 	} else {
99 		ret = disable_eud(chip);
100 	}
101 
102 	return ret < 0 ? ret : count;
103 }
104 
105 static DEVICE_ATTR_RW(enable);
106 
107 static struct attribute *eud_attrs[] = {
108 	&dev_attr_enable.attr,
109 	NULL,
110 };
111 ATTRIBUTE_GROUPS(eud);
112 
113 static void usb_attach_detach(struct eud_chip *chip)
114 {
115 	u32 reg;
116 
117 	/* read ctl_out_1[4] to find USB attach or detach event */
118 	reg = readl(chip->base + EUD_REG_CTL_OUT_1);
119 	chip->usb_attached = reg & EUD_INT_SAFE_MODE;
120 }
121 
122 static void pet_eud(struct eud_chip *chip)
123 {
124 	u32 reg;
125 	int ret;
126 
127 	/* When the EUD_INT_PET_EUD in SW_ATTACH_DET is set, the cable has been
128 	 * disconnected and we need to detach the pet to check if EUD is in safe
129 	 * mode before attaching again.
130 	 */
131 	reg = readl(chip->base + EUD_REG_SW_ATTACH_DET);
132 	if (reg & EUD_INT_PET_EUD) {
133 		/* Detach & Attach pet for EUD */
134 		writel(0, chip->base + EUD_REG_SW_ATTACH_DET);
135 		/* Delay to make sure detach pet is done before attach pet */
136 		ret = readl_poll_timeout(chip->base + EUD_REG_SW_ATTACH_DET,
137 					reg, (reg == 0), 1, 100);
138 		if (ret) {
139 			dev_err(chip->dev, "Detach pet failed\n");
140 			return;
141 		}
142 	}
143 	/* Attach pet for EUD */
144 	writel(EUD_INT_PET_EUD, chip->base + EUD_REG_SW_ATTACH_DET);
145 }
146 
147 static irqreturn_t handle_eud_irq(int irq, void *data)
148 {
149 	struct eud_chip *chip = data;
150 	u32 reg;
151 
152 	reg = readl(chip->base + EUD_REG_INT_STATUS_1);
153 	switch (reg & EUD_INT_ALL) {
154 	case EUD_INT_VBUS:
155 		usb_attach_detach(chip);
156 		return IRQ_WAKE_THREAD;
157 	case EUD_INT_SAFE_MODE:
158 		pet_eud(chip);
159 		return IRQ_HANDLED;
160 	default:
161 		return IRQ_NONE;
162 	}
163 }
164 
165 static irqreturn_t handle_eud_irq_thread(int irq, void *data)
166 {
167 	struct eud_chip *chip = data;
168 	int ret;
169 
170 	if (chip->usb_attached)
171 		ret = usb_role_switch_set_role(chip->role_sw, USB_ROLE_DEVICE);
172 	else
173 		ret = usb_role_switch_set_role(chip->role_sw, USB_ROLE_HOST);
174 	if (ret)
175 		dev_err(chip->dev, "failed to set role switch\n");
176 
177 	/* set and clear vbus_int_clr[0] to clear interrupt */
178 	writel(BIT(0), chip->base + EUD_REG_VBUS_INT_CLR);
179 	writel(0, chip->base + EUD_REG_VBUS_INT_CLR);
180 
181 	return IRQ_HANDLED;
182 }
183 
184 static void eud_role_switch_release(void *data)
185 {
186 	struct eud_chip *chip = data;
187 
188 	usb_role_switch_put(chip->role_sw);
189 }
190 
191 static int eud_probe(struct platform_device *pdev)
192 {
193 	struct eud_chip *chip;
194 	struct resource *res;
195 	int ret;
196 
197 	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
198 	if (!chip)
199 		return -ENOMEM;
200 
201 	chip->dev = &pdev->dev;
202 
203 	chip->role_sw = usb_role_switch_get(&pdev->dev);
204 	if (IS_ERR(chip->role_sw))
205 		return dev_err_probe(chip->dev, PTR_ERR(chip->role_sw),
206 					"failed to get role switch\n");
207 
208 	ret = devm_add_action_or_reset(chip->dev, eud_role_switch_release, chip);
209 	if (ret)
210 		return ret;
211 
212 	chip->base = devm_platform_ioremap_resource(pdev, 0);
213 	if (IS_ERR(chip->base))
214 		return PTR_ERR(chip->base);
215 
216 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
217 	if (!res)
218 		return -ENODEV;
219 	chip->mode_mgr = res->start;
220 
221 	chip->irq = platform_get_irq(pdev, 0);
222 	if (chip->irq < 0)
223 		return chip->irq;
224 
225 	ret = devm_request_threaded_irq(&pdev->dev, chip->irq, handle_eud_irq,
226 			handle_eud_irq_thread, IRQF_ONESHOT, NULL, chip);
227 	if (ret)
228 		return dev_err_probe(chip->dev, ret, "failed to allocate irq\n");
229 
230 	enable_irq_wake(chip->irq);
231 
232 	platform_set_drvdata(pdev, chip);
233 
234 	return 0;
235 }
236 
237 static void eud_remove(struct platform_device *pdev)
238 {
239 	struct eud_chip *chip = platform_get_drvdata(pdev);
240 
241 	if (chip->enabled)
242 		disable_eud(chip);
243 
244 	device_init_wakeup(&pdev->dev, false);
245 	disable_irq_wake(chip->irq);
246 }
247 
248 static const struct of_device_id eud_dt_match[] = {
249 	{ .compatible = "qcom,eud" },
250 	{ }
251 };
252 MODULE_DEVICE_TABLE(of, eud_dt_match);
253 
254 static struct platform_driver eud_driver = {
255 	.probe	= eud_probe,
256 	.remove = eud_remove,
257 	.driver	= {
258 		.name = "qcom_eud",
259 		.dev_groups = eud_groups,
260 		.of_match_table = eud_dt_match,
261 	},
262 };
263 module_platform_driver(eud_driver);
264 
265 MODULE_DESCRIPTION("QTI EUD driver");
266 MODULE_LICENSE("GPL v2");
267