1 // SPDX-License-Identifier: GPL-2.0+ 2 // 3 // extcon-ptn5150.c - PTN5150 CC logic extcon driver to support USB detection 4 // 5 // Based on extcon-sm5502.c driver 6 // Copyright (c) 2018-2019 by Vijai Kumar K 7 // Author: Vijai Kumar K <vijaikumar.kanagarajan@gmail.com> 8 // Copyright (c) 2020 Krzysztof Kozlowski <krzk@kernel.org> 9 10 #include <linux/err.h> 11 #include <linux/i2c.h> 12 #include <linux/interrupt.h> 13 #include <linux/kernel.h> 14 #include <linux/module.h> 15 #include <linux/regmap.h> 16 #include <linux/slab.h> 17 #include <linux/extcon-provider.h> 18 #include <linux/gpio/consumer.h> 19 20 /* PTN5150 registers */ 21 enum ptn5150_reg { 22 PTN5150_REG_DEVICE_ID = 0x01, 23 PTN5150_REG_CONTROL, 24 PTN5150_REG_INT_STATUS, 25 PTN5150_REG_CC_STATUS, 26 PTN5150_REG_CON_DET = 0x09, 27 PTN5150_REG_VCONN_STATUS, 28 PTN5150_REG_RESET, 29 PTN5150_REG_INT_MASK = 0x18, 30 PTN5150_REG_INT_REG_STATUS, 31 PTN5150_REG_END, 32 }; 33 34 #define PTN5150_DFP_ATTACHED 0x1 35 #define PTN5150_UFP_ATTACHED 0x2 36 37 /* Define PTN5150 MASK/SHIFT constant */ 38 #define PTN5150_REG_DEVICE_ID_VENDOR_SHIFT 0 39 #define PTN5150_REG_DEVICE_ID_VENDOR_MASK \ 40 (0x3 << PTN5150_REG_DEVICE_ID_VENDOR_SHIFT) 41 42 #define PTN5150_REG_DEVICE_ID_VERSION_SHIFT 3 43 #define PTN5150_REG_DEVICE_ID_VERSION_MASK \ 44 (0x1f << PTN5150_REG_DEVICE_ID_VERSION_SHIFT) 45 46 #define PTN5150_REG_CC_PORT_ATTACHMENT_SHIFT 2 47 #define PTN5150_REG_CC_PORT_ATTACHMENT_MASK \ 48 (0x7 << PTN5150_REG_CC_PORT_ATTACHMENT_SHIFT) 49 50 #define PTN5150_REG_CC_VBUS_DETECTION_SHIFT 7 51 #define PTN5150_REG_CC_VBUS_DETECTION_MASK \ 52 (0x1 << PTN5150_REG_CC_VBUS_DETECTION_SHIFT) 53 54 #define PTN5150_REG_INT_CABLE_ATTACH_SHIFT 0 55 #define PTN5150_REG_INT_CABLE_ATTACH_MASK \ 56 (0x1 << PTN5150_REG_INT_CABLE_ATTACH_SHIFT) 57 58 #define PTN5150_REG_INT_CABLE_DETACH_SHIFT 1 59 #define PTN5150_REG_INT_CABLE_DETACH_MASK \ 60 (0x1 << PTN5150_REG_CC_CABLE_DETACH_SHIFT) 61 62 struct ptn5150_info { 63 struct device *dev; 64 struct extcon_dev *edev; 65 struct i2c_client *i2c; 66 struct regmap *regmap; 67 struct gpio_desc *int_gpiod; 68 struct gpio_desc *vbus_gpiod; 69 int irq; 70 struct work_struct irq_work; 71 struct mutex mutex; 72 }; 73 74 /* List of detectable cables */ 75 static const unsigned int ptn5150_extcon_cable[] = { 76 EXTCON_USB, 77 EXTCON_USB_HOST, 78 EXTCON_NONE, 79 }; 80 81 static const struct regmap_config ptn5150_regmap_config = { 82 .reg_bits = 8, 83 .val_bits = 8, 84 .max_register = PTN5150_REG_END, 85 }; 86 87 static void ptn5150_check_state(struct ptn5150_info *info) 88 { 89 unsigned int port_status, reg_data, vbus; 90 int ret; 91 92 ret = regmap_read(info->regmap, PTN5150_REG_CC_STATUS, ®_data); 93 if (ret) { 94 dev_err(info->dev, "failed to read CC STATUS %d\n", ret); 95 return; 96 } 97 98 port_status = ((reg_data & 99 PTN5150_REG_CC_PORT_ATTACHMENT_MASK) >> 100 PTN5150_REG_CC_PORT_ATTACHMENT_SHIFT); 101 102 switch (port_status) { 103 case PTN5150_DFP_ATTACHED: 104 extcon_set_state_sync(info->edev, EXTCON_USB_HOST, false); 105 gpiod_set_value_cansleep(info->vbus_gpiod, 0); 106 extcon_set_state_sync(info->edev, EXTCON_USB, true); 107 break; 108 case PTN5150_UFP_ATTACHED: 109 extcon_set_state_sync(info->edev, EXTCON_USB, false); 110 vbus = ((reg_data & PTN5150_REG_CC_VBUS_DETECTION_MASK) >> 111 PTN5150_REG_CC_VBUS_DETECTION_SHIFT); 112 if (vbus) 113 gpiod_set_value_cansleep(info->vbus_gpiod, 0); 114 else 115 gpiod_set_value_cansleep(info->vbus_gpiod, 1); 116 117 extcon_set_state_sync(info->edev, EXTCON_USB_HOST, true); 118 break; 119 default: 120 dev_err(info->dev, "Unknown Port status : %x\n", port_status); 121 break; 122 } 123 } 124 125 static void ptn5150_irq_work(struct work_struct *work) 126 { 127 struct ptn5150_info *info = container_of(work, 128 struct ptn5150_info, irq_work); 129 int ret = 0; 130 unsigned int int_status; 131 132 if (!info->edev) 133 return; 134 135 mutex_lock(&info->mutex); 136 137 /* Clear interrupt. Read would clear the register */ 138 ret = regmap_read(info->regmap, PTN5150_REG_INT_STATUS, &int_status); 139 if (ret) { 140 dev_err(info->dev, "failed to read INT STATUS %d\n", ret); 141 mutex_unlock(&info->mutex); 142 return; 143 } 144 145 if (int_status) { 146 unsigned int cable_attach; 147 148 cable_attach = int_status & PTN5150_REG_INT_CABLE_ATTACH_MASK; 149 if (cable_attach) { 150 ptn5150_check_state(info); 151 } else { 152 extcon_set_state_sync(info->edev, 153 EXTCON_USB_HOST, false); 154 extcon_set_state_sync(info->edev, 155 EXTCON_USB, false); 156 gpiod_set_value_cansleep(info->vbus_gpiod, 0); 157 } 158 } 159 160 /* Clear interrupt. Read would clear the register */ 161 ret = regmap_read(info->regmap, PTN5150_REG_INT_REG_STATUS, 162 &int_status); 163 if (ret) { 164 dev_err(info->dev, 165 "failed to read INT REG STATUS %d\n", ret); 166 mutex_unlock(&info->mutex); 167 return; 168 } 169 170 mutex_unlock(&info->mutex); 171 } 172 173 174 static irqreturn_t ptn5150_irq_handler(int irq, void *data) 175 { 176 struct ptn5150_info *info = data; 177 178 schedule_work(&info->irq_work); 179 180 return IRQ_HANDLED; 181 } 182 183 static int ptn5150_init_dev_type(struct ptn5150_info *info) 184 { 185 unsigned int reg_data, vendor_id, version_id; 186 int ret; 187 188 ret = regmap_read(info->regmap, PTN5150_REG_DEVICE_ID, ®_data); 189 if (ret) { 190 dev_err(info->dev, "failed to read DEVICE_ID %d\n", ret); 191 return -EINVAL; 192 } 193 194 vendor_id = ((reg_data & PTN5150_REG_DEVICE_ID_VENDOR_MASK) >> 195 PTN5150_REG_DEVICE_ID_VENDOR_SHIFT); 196 version_id = ((reg_data & PTN5150_REG_DEVICE_ID_VERSION_MASK) >> 197 PTN5150_REG_DEVICE_ID_VERSION_SHIFT); 198 199 dev_dbg(info->dev, "Device type: version: 0x%x, vendor: 0x%x\n", 200 version_id, vendor_id); 201 202 /* Clear any existing interrupts */ 203 ret = regmap_read(info->regmap, PTN5150_REG_INT_STATUS, ®_data); 204 if (ret) { 205 dev_err(info->dev, 206 "failed to read PTN5150_REG_INT_STATUS %d\n", 207 ret); 208 return -EINVAL; 209 } 210 211 ret = regmap_read(info->regmap, PTN5150_REG_INT_REG_STATUS, ®_data); 212 if (ret) { 213 dev_err(info->dev, 214 "failed to read PTN5150_REG_INT_REG_STATUS %d\n", ret); 215 return -EINVAL; 216 } 217 218 return 0; 219 } 220 221 static int ptn5150_i2c_probe(struct i2c_client *i2c, 222 const struct i2c_device_id *id) 223 { 224 struct device *dev = &i2c->dev; 225 struct device_node *np = i2c->dev.of_node; 226 struct ptn5150_info *info; 227 int ret; 228 229 if (!np) 230 return -EINVAL; 231 232 info = devm_kzalloc(&i2c->dev, sizeof(*info), GFP_KERNEL); 233 if (!info) 234 return -ENOMEM; 235 i2c_set_clientdata(i2c, info); 236 237 info->dev = &i2c->dev; 238 info->i2c = i2c; 239 info->vbus_gpiod = devm_gpiod_get(&i2c->dev, "vbus", GPIOD_OUT_LOW); 240 if (IS_ERR(info->vbus_gpiod)) { 241 dev_err(dev, "failed to get VBUS GPIO\n"); 242 return PTR_ERR(info->vbus_gpiod); 243 } 244 245 mutex_init(&info->mutex); 246 247 INIT_WORK(&info->irq_work, ptn5150_irq_work); 248 249 info->regmap = devm_regmap_init_i2c(i2c, &ptn5150_regmap_config); 250 if (IS_ERR(info->regmap)) { 251 ret = PTR_ERR(info->regmap); 252 dev_err(info->dev, "failed to allocate register map: %d\n", 253 ret); 254 return ret; 255 } 256 257 if (i2c->irq > 0) { 258 info->irq = i2c->irq; 259 } else { 260 info->int_gpiod = devm_gpiod_get(&i2c->dev, "int", GPIOD_IN); 261 if (IS_ERR(info->int_gpiod)) { 262 dev_err(dev, "failed to get INT GPIO\n"); 263 return PTR_ERR(info->int_gpiod); 264 } 265 266 info->irq = gpiod_to_irq(info->int_gpiod); 267 if (info->irq < 0) { 268 dev_err(dev, "failed to get INTB IRQ\n"); 269 return info->irq; 270 } 271 } 272 273 ret = devm_request_threaded_irq(dev, info->irq, NULL, 274 ptn5150_irq_handler, 275 IRQF_TRIGGER_FALLING | 276 IRQF_ONESHOT, 277 i2c->name, info); 278 if (ret < 0) { 279 dev_err(dev, "failed to request handler for INTB IRQ\n"); 280 return ret; 281 } 282 283 /* Allocate extcon device */ 284 info->edev = devm_extcon_dev_allocate(info->dev, ptn5150_extcon_cable); 285 if (IS_ERR(info->edev)) { 286 dev_err(info->dev, "failed to allocate memory for extcon\n"); 287 return -ENOMEM; 288 } 289 290 /* Register extcon device */ 291 ret = devm_extcon_dev_register(info->dev, info->edev); 292 if (ret) { 293 dev_err(info->dev, "failed to register extcon device\n"); 294 return ret; 295 } 296 297 /* Initialize PTN5150 device and print vendor id and version id */ 298 ret = ptn5150_init_dev_type(info); 299 if (ret) 300 return -EINVAL; 301 302 /* 303 * Update current extcon state if for example OTG connection was there 304 * before the probe 305 */ 306 mutex_lock(&info->mutex); 307 ptn5150_check_state(info); 308 mutex_unlock(&info->mutex); 309 310 return 0; 311 } 312 313 static const struct of_device_id ptn5150_dt_match[] = { 314 { .compatible = "nxp,ptn5150" }, 315 { }, 316 }; 317 MODULE_DEVICE_TABLE(of, ptn5150_dt_match); 318 319 static const struct i2c_device_id ptn5150_i2c_id[] = { 320 { "ptn5150", 0 }, 321 { } 322 }; 323 MODULE_DEVICE_TABLE(i2c, ptn5150_i2c_id); 324 325 static struct i2c_driver ptn5150_i2c_driver = { 326 .driver = { 327 .name = "ptn5150", 328 .of_match_table = ptn5150_dt_match, 329 }, 330 .probe = ptn5150_i2c_probe, 331 .id_table = ptn5150_i2c_id, 332 }; 333 334 static int __init ptn5150_i2c_init(void) 335 { 336 return i2c_add_driver(&ptn5150_i2c_driver); 337 } 338 subsys_initcall(ptn5150_i2c_init); 339 340 MODULE_DESCRIPTION("NXP PTN5150 CC logic Extcon driver"); 341 MODULE_AUTHOR("Vijai Kumar K <vijaikumar.kanagarajan@gmail.com>"); 342 MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>"); 343 MODULE_LICENSE("GPL v2"); 344