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