at master 266 lines 6.1 kB view raw
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 34struct 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 45static 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 60static 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 72static 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 80static 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 105static DEVICE_ATTR_RW(enable); 106 107static struct attribute *eud_attrs[] = { 108 &dev_attr_enable.attr, 109 NULL, 110}; 111ATTRIBUTE_GROUPS(eud); 112 113static 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 122static 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 147static 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 165static 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 184static 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 191static 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 237static 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 248static const struct of_device_id eud_dt_match[] = { 249 { .compatible = "qcom,eud" }, 250 { } 251}; 252MODULE_DEVICE_TABLE(of, eud_dt_match); 253 254static 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}; 263module_platform_driver(eud_driver); 264 265MODULE_DESCRIPTION("QTI EUD driver"); 266MODULE_LICENSE("GPL v2");