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