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