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