1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. 4 * Copyright (c) 2022, Linaro Ltd 5 */ 6 #include <linux/auxiliary_bus.h> 7 #include <linux/module.h> 8 #include <linux/of.h> 9 #include <linux/platform_device.h> 10 #include <linux/rpmsg.h> 11 #include <linux/slab.h> 12 #include <linux/soc/qcom/pdr.h> 13 #include <linux/soc/qcom/pmic_glink.h> 14 15 enum { 16 PMIC_GLINK_CLIENT_BATT = 0, 17 PMIC_GLINK_CLIENT_ALTMODE, 18 PMIC_GLINK_CLIENT_UCSI, 19 }; 20 21 struct pmic_glink { 22 struct device *dev; 23 struct pdr_handle *pdr; 24 25 struct rpmsg_endpoint *ept; 26 27 unsigned long client_mask; 28 29 struct auxiliary_device altmode_aux; 30 struct auxiliary_device ps_aux; 31 struct auxiliary_device ucsi_aux; 32 33 /* serializing client_state and pdr_state updates */ 34 struct mutex state_lock; 35 unsigned int client_state; 36 unsigned int pdr_state; 37 38 /* serializing clients list updates */ 39 struct mutex client_lock; 40 struct list_head clients; 41 }; 42 43 static struct pmic_glink *__pmic_glink; 44 static DEFINE_MUTEX(__pmic_glink_lock); 45 46 struct pmic_glink_client { 47 struct list_head node; 48 49 struct pmic_glink *pg; 50 unsigned int id; 51 52 void (*cb)(const void *data, size_t len, void *priv); 53 void (*pdr_notify)(void *priv, int state); 54 void *priv; 55 }; 56 57 static void _devm_pmic_glink_release_client(struct device *dev, void *res) 58 { 59 struct pmic_glink_client *client = (struct pmic_glink_client *)res; 60 struct pmic_glink *pg = client->pg; 61 62 mutex_lock(&pg->client_lock); 63 list_del(&client->node); 64 mutex_unlock(&pg->client_lock); 65 } 66 67 struct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev, 68 unsigned int id, 69 void (*cb)(const void *, size_t, void *), 70 void (*pdr)(void *, int), 71 void *priv) 72 { 73 struct pmic_glink_client *client; 74 struct pmic_glink *pg = dev_get_drvdata(dev->parent); 75 76 client = devres_alloc(_devm_pmic_glink_release_client, sizeof(*client), GFP_KERNEL); 77 if (!client) 78 return ERR_PTR(-ENOMEM); 79 80 client->pg = pg; 81 client->id = id; 82 client->cb = cb; 83 client->pdr_notify = pdr; 84 client->priv = priv; 85 86 mutex_lock(&pg->client_lock); 87 list_add(&client->node, &pg->clients); 88 mutex_unlock(&pg->client_lock); 89 90 devres_add(dev, client); 91 92 return client; 93 } 94 EXPORT_SYMBOL_GPL(devm_pmic_glink_register_client); 95 96 int pmic_glink_send(struct pmic_glink_client *client, void *data, size_t len) 97 { 98 struct pmic_glink *pg = client->pg; 99 100 return rpmsg_send(pg->ept, data, len); 101 } 102 EXPORT_SYMBOL_GPL(pmic_glink_send); 103 104 static int pmic_glink_rpmsg_callback(struct rpmsg_device *rpdev, void *data, 105 int len, void *priv, u32 addr) 106 { 107 struct pmic_glink_client *client; 108 struct pmic_glink_hdr *hdr; 109 struct pmic_glink *pg = dev_get_drvdata(&rpdev->dev); 110 111 if (len < sizeof(*hdr)) { 112 dev_warn(pg->dev, "ignoring truncated message\n"); 113 return 0; 114 } 115 116 hdr = data; 117 118 list_for_each_entry(client, &pg->clients, node) { 119 if (client->id == le32_to_cpu(hdr->owner)) 120 client->cb(data, len, client->priv); 121 } 122 123 return 0; 124 } 125 126 static void pmic_glink_aux_release(struct device *dev) {} 127 128 static int pmic_glink_add_aux_device(struct pmic_glink *pg, 129 struct auxiliary_device *aux, 130 const char *name) 131 { 132 struct device *parent = pg->dev; 133 int ret; 134 135 aux->name = name; 136 aux->dev.parent = parent; 137 aux->dev.release = pmic_glink_aux_release; 138 device_set_of_node_from_dev(&aux->dev, parent); 139 ret = auxiliary_device_init(aux); 140 if (ret) 141 return ret; 142 143 ret = auxiliary_device_add(aux); 144 if (ret) 145 auxiliary_device_uninit(aux); 146 147 return ret; 148 } 149 150 static void pmic_glink_del_aux_device(struct pmic_glink *pg, 151 struct auxiliary_device *aux) 152 { 153 auxiliary_device_delete(aux); 154 auxiliary_device_uninit(aux); 155 } 156 157 static void pmic_glink_state_notify_clients(struct pmic_glink *pg) 158 { 159 struct pmic_glink_client *client; 160 unsigned int new_state = pg->client_state; 161 162 if (pg->client_state != SERVREG_SERVICE_STATE_UP) { 163 if (pg->pdr_state == SERVREG_SERVICE_STATE_UP && pg->ept) 164 new_state = SERVREG_SERVICE_STATE_UP; 165 } else { 166 if (pg->pdr_state == SERVREG_SERVICE_STATE_UP && pg->ept) 167 new_state = SERVREG_SERVICE_STATE_DOWN; 168 } 169 170 if (new_state != pg->client_state) { 171 list_for_each_entry(client, &pg->clients, node) 172 client->pdr_notify(client->priv, new_state); 173 pg->client_state = new_state; 174 } 175 } 176 177 static void pmic_glink_pdr_callback(int state, char *svc_path, void *priv) 178 { 179 struct pmic_glink *pg = priv; 180 181 mutex_lock(&pg->state_lock); 182 pg->pdr_state = state; 183 184 pmic_glink_state_notify_clients(pg); 185 mutex_unlock(&pg->state_lock); 186 } 187 188 static int pmic_glink_rpmsg_probe(struct rpmsg_device *rpdev) 189 { 190 struct pmic_glink *pg = __pmic_glink; 191 int ret = 0; 192 193 mutex_lock(&__pmic_glink_lock); 194 if (!pg) { 195 ret = dev_err_probe(&rpdev->dev, -ENODEV, "no pmic_glink device to attach to\n"); 196 goto out_unlock; 197 } 198 199 dev_set_drvdata(&rpdev->dev, pg); 200 201 mutex_lock(&pg->state_lock); 202 pg->ept = rpdev->ept; 203 pmic_glink_state_notify_clients(pg); 204 mutex_unlock(&pg->state_lock); 205 206 out_unlock: 207 mutex_unlock(&__pmic_glink_lock); 208 return ret; 209 } 210 211 static void pmic_glink_rpmsg_remove(struct rpmsg_device *rpdev) 212 { 213 struct pmic_glink *pg; 214 215 mutex_lock(&__pmic_glink_lock); 216 pg = __pmic_glink; 217 if (!pg) 218 goto out_unlock; 219 220 mutex_lock(&pg->state_lock); 221 pg->ept = NULL; 222 pmic_glink_state_notify_clients(pg); 223 mutex_unlock(&pg->state_lock); 224 out_unlock: 225 mutex_unlock(&__pmic_glink_lock); 226 } 227 228 static const struct rpmsg_device_id pmic_glink_rpmsg_id_match[] = { 229 { "PMIC_RTR_ADSP_APPS" }, 230 {} 231 }; 232 233 static struct rpmsg_driver pmic_glink_rpmsg_driver = { 234 .probe = pmic_glink_rpmsg_probe, 235 .remove = pmic_glink_rpmsg_remove, 236 .callback = pmic_glink_rpmsg_callback, 237 .id_table = pmic_glink_rpmsg_id_match, 238 .drv = { 239 .name = "qcom_pmic_glink_rpmsg", 240 }, 241 }; 242 243 static int pmic_glink_probe(struct platform_device *pdev) 244 { 245 const unsigned long *match_data; 246 struct pdr_service *service; 247 struct pmic_glink *pg; 248 int ret; 249 250 pg = devm_kzalloc(&pdev->dev, sizeof(*pg), GFP_KERNEL); 251 if (!pg) 252 return -ENOMEM; 253 254 dev_set_drvdata(&pdev->dev, pg); 255 256 pg->dev = &pdev->dev; 257 258 INIT_LIST_HEAD(&pg->clients); 259 mutex_init(&pg->client_lock); 260 mutex_init(&pg->state_lock); 261 262 match_data = (unsigned long *)of_device_get_match_data(&pdev->dev); 263 if (!match_data) 264 return -EINVAL; 265 266 pg->client_mask = *match_data; 267 268 if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) { 269 ret = pmic_glink_add_aux_device(pg, &pg->ucsi_aux, "ucsi"); 270 if (ret) 271 return ret; 272 } 273 if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) { 274 ret = pmic_glink_add_aux_device(pg, &pg->altmode_aux, "altmode"); 275 if (ret) 276 goto out_release_ucsi_aux; 277 } 278 if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) { 279 ret = pmic_glink_add_aux_device(pg, &pg->ps_aux, "power-supply"); 280 if (ret) 281 goto out_release_altmode_aux; 282 } 283 284 pg->pdr = pdr_handle_alloc(pmic_glink_pdr_callback, pg); 285 if (IS_ERR(pg->pdr)) { 286 ret = dev_err_probe(&pdev->dev, PTR_ERR(pg->pdr), "failed to initialize pdr\n"); 287 goto out_release_aux_devices; 288 } 289 290 service = pdr_add_lookup(pg->pdr, "tms/servreg", "msm/adsp/charger_pd"); 291 if (IS_ERR(service)) { 292 ret = dev_err_probe(&pdev->dev, PTR_ERR(service), 293 "failed adding pdr lookup for charger_pd\n"); 294 goto out_release_pdr_handle; 295 } 296 297 mutex_lock(&__pmic_glink_lock); 298 __pmic_glink = pg; 299 mutex_unlock(&__pmic_glink_lock); 300 301 return 0; 302 303 out_release_pdr_handle: 304 pdr_handle_release(pg->pdr); 305 out_release_aux_devices: 306 if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) 307 pmic_glink_del_aux_device(pg, &pg->ps_aux); 308 out_release_altmode_aux: 309 if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) 310 pmic_glink_del_aux_device(pg, &pg->altmode_aux); 311 out_release_ucsi_aux: 312 if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) 313 pmic_glink_del_aux_device(pg, &pg->ucsi_aux); 314 315 return ret; 316 } 317 318 static void pmic_glink_remove(struct platform_device *pdev) 319 { 320 struct pmic_glink *pg = dev_get_drvdata(&pdev->dev); 321 322 pdr_handle_release(pg->pdr); 323 324 if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) 325 pmic_glink_del_aux_device(pg, &pg->ps_aux); 326 if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) 327 pmic_glink_del_aux_device(pg, &pg->altmode_aux); 328 if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) 329 pmic_glink_del_aux_device(pg, &pg->ucsi_aux); 330 331 mutex_lock(&__pmic_glink_lock); 332 __pmic_glink = NULL; 333 mutex_unlock(&__pmic_glink_lock); 334 } 335 336 static const unsigned long pmic_glink_sc8180x_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) | 337 BIT(PMIC_GLINK_CLIENT_ALTMODE); 338 339 static const unsigned long pmic_glink_sm8450_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) | 340 BIT(PMIC_GLINK_CLIENT_ALTMODE) | 341 BIT(PMIC_GLINK_CLIENT_UCSI); 342 343 static const struct of_device_id pmic_glink_of_match[] = { 344 { .compatible = "qcom,sc8180x-pmic-glink", .data = &pmic_glink_sc8180x_client_mask }, 345 { .compatible = "qcom,sc8280xp-pmic-glink", .data = &pmic_glink_sc8180x_client_mask }, 346 { .compatible = "qcom,pmic-glink", .data = &pmic_glink_sm8450_client_mask }, 347 {} 348 }; 349 MODULE_DEVICE_TABLE(of, pmic_glink_of_match); 350 351 static struct platform_driver pmic_glink_driver = { 352 .probe = pmic_glink_probe, 353 .remove_new = pmic_glink_remove, 354 .driver = { 355 .name = "qcom_pmic_glink", 356 .of_match_table = pmic_glink_of_match, 357 }, 358 }; 359 360 static int pmic_glink_init(void) 361 { 362 platform_driver_register(&pmic_glink_driver); 363 register_rpmsg_driver(&pmic_glink_rpmsg_driver); 364 365 return 0; 366 } 367 module_init(pmic_glink_init); 368 369 static void pmic_glink_exit(void) 370 { 371 unregister_rpmsg_driver(&pmic_glink_rpmsg_driver); 372 platform_driver_unregister(&pmic_glink_driver); 373 } 374 module_exit(pmic_glink_exit); 375 376 MODULE_DESCRIPTION("Qualcomm PMIC GLINK driver"); 377 MODULE_LICENSE("GPL"); 378