162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2022, Linaro Ltd 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/auxiliary_bus.h> 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include <linux/of.h> 962306a36Sopenharmony_ci#include <linux/platform_device.h> 1062306a36Sopenharmony_ci#include <linux/rpmsg.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/soc/qcom/pdr.h> 1362306a36Sopenharmony_ci#include <linux/soc/qcom/pmic_glink.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cienum { 1662306a36Sopenharmony_ci PMIC_GLINK_CLIENT_BATT = 0, 1762306a36Sopenharmony_ci PMIC_GLINK_CLIENT_ALTMODE, 1862306a36Sopenharmony_ci PMIC_GLINK_CLIENT_UCSI, 1962306a36Sopenharmony_ci}; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define PMIC_GLINK_CLIENT_DEFAULT (BIT(PMIC_GLINK_CLIENT_BATT) | \ 2262306a36Sopenharmony_ci BIT(PMIC_GLINK_CLIENT_ALTMODE)) 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistruct pmic_glink { 2562306a36Sopenharmony_ci struct device *dev; 2662306a36Sopenharmony_ci struct pdr_handle *pdr; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci struct rpmsg_endpoint *ept; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci unsigned long client_mask; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci struct auxiliary_device altmode_aux; 3362306a36Sopenharmony_ci struct auxiliary_device ps_aux; 3462306a36Sopenharmony_ci struct auxiliary_device ucsi_aux; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci /* serializing client_state and pdr_state updates */ 3762306a36Sopenharmony_ci struct mutex state_lock; 3862306a36Sopenharmony_ci unsigned int client_state; 3962306a36Sopenharmony_ci unsigned int pdr_state; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci /* serializing clients list updates */ 4262306a36Sopenharmony_ci struct mutex client_lock; 4362306a36Sopenharmony_ci struct list_head clients; 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic struct pmic_glink *__pmic_glink; 4762306a36Sopenharmony_cistatic DEFINE_MUTEX(__pmic_glink_lock); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistruct pmic_glink_client { 5062306a36Sopenharmony_ci struct list_head node; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci struct pmic_glink *pg; 5362306a36Sopenharmony_ci unsigned int id; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci void (*cb)(const void *data, size_t len, void *priv); 5662306a36Sopenharmony_ci void (*pdr_notify)(void *priv, int state); 5762306a36Sopenharmony_ci void *priv; 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic void _devm_pmic_glink_release_client(struct device *dev, void *res) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci struct pmic_glink_client *client = (struct pmic_glink_client *)res; 6362306a36Sopenharmony_ci struct pmic_glink *pg = client->pg; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci mutex_lock(&pg->client_lock); 6662306a36Sopenharmony_ci list_del(&client->node); 6762306a36Sopenharmony_ci mutex_unlock(&pg->client_lock); 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistruct pmic_glink_client *devm_pmic_glink_register_client(struct device *dev, 7162306a36Sopenharmony_ci unsigned int id, 7262306a36Sopenharmony_ci void (*cb)(const void *, size_t, void *), 7362306a36Sopenharmony_ci void (*pdr)(void *, int), 7462306a36Sopenharmony_ci void *priv) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct pmic_glink_client *client; 7762306a36Sopenharmony_ci struct pmic_glink *pg = dev_get_drvdata(dev->parent); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci client = devres_alloc(_devm_pmic_glink_release_client, sizeof(*client), GFP_KERNEL); 8062306a36Sopenharmony_ci if (!client) 8162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci client->pg = pg; 8462306a36Sopenharmony_ci client->id = id; 8562306a36Sopenharmony_ci client->cb = cb; 8662306a36Sopenharmony_ci client->pdr_notify = pdr; 8762306a36Sopenharmony_ci client->priv = priv; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci mutex_lock(&pg->client_lock); 9062306a36Sopenharmony_ci list_add(&client->node, &pg->clients); 9162306a36Sopenharmony_ci mutex_unlock(&pg->client_lock); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci devres_add(dev, client); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return client; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_pmic_glink_register_client); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ciint pmic_glink_send(struct pmic_glink_client *client, void *data, size_t len) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct pmic_glink *pg = client->pg; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci return rpmsg_send(pg->ept, data, len); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pmic_glink_send); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic int pmic_glink_rpmsg_callback(struct rpmsg_device *rpdev, void *data, 10862306a36Sopenharmony_ci int len, void *priv, u32 addr) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct pmic_glink_client *client; 11162306a36Sopenharmony_ci struct pmic_glink_hdr *hdr; 11262306a36Sopenharmony_ci struct pmic_glink *pg = dev_get_drvdata(&rpdev->dev); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (len < sizeof(*hdr)) { 11562306a36Sopenharmony_ci dev_warn(pg->dev, "ignoring truncated message\n"); 11662306a36Sopenharmony_ci return 0; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci hdr = data; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci list_for_each_entry(client, &pg->clients, node) { 12262306a36Sopenharmony_ci if (client->id == le32_to_cpu(hdr->owner)) 12362306a36Sopenharmony_ci client->cb(data, len, client->priv); 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci return 0; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic void pmic_glink_aux_release(struct device *dev) {} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic int pmic_glink_add_aux_device(struct pmic_glink *pg, 13262306a36Sopenharmony_ci struct auxiliary_device *aux, 13362306a36Sopenharmony_ci const char *name) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci struct device *parent = pg->dev; 13662306a36Sopenharmony_ci int ret; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci aux->name = name; 13962306a36Sopenharmony_ci aux->dev.parent = parent; 14062306a36Sopenharmony_ci aux->dev.release = pmic_glink_aux_release; 14162306a36Sopenharmony_ci device_set_of_node_from_dev(&aux->dev, parent); 14262306a36Sopenharmony_ci ret = auxiliary_device_init(aux); 14362306a36Sopenharmony_ci if (ret) 14462306a36Sopenharmony_ci return ret; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci ret = auxiliary_device_add(aux); 14762306a36Sopenharmony_ci if (ret) 14862306a36Sopenharmony_ci auxiliary_device_uninit(aux); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return ret; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic void pmic_glink_del_aux_device(struct pmic_glink *pg, 15462306a36Sopenharmony_ci struct auxiliary_device *aux) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci auxiliary_device_delete(aux); 15762306a36Sopenharmony_ci auxiliary_device_uninit(aux); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic void pmic_glink_state_notify_clients(struct pmic_glink *pg) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci struct pmic_glink_client *client; 16362306a36Sopenharmony_ci unsigned int new_state = pg->client_state; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci if (pg->client_state != SERVREG_SERVICE_STATE_UP) { 16662306a36Sopenharmony_ci if (pg->pdr_state == SERVREG_SERVICE_STATE_UP && pg->ept) 16762306a36Sopenharmony_ci new_state = SERVREG_SERVICE_STATE_UP; 16862306a36Sopenharmony_ci } else { 16962306a36Sopenharmony_ci if (pg->pdr_state == SERVREG_SERVICE_STATE_UP && pg->ept) 17062306a36Sopenharmony_ci new_state = SERVREG_SERVICE_STATE_DOWN; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (new_state != pg->client_state) { 17462306a36Sopenharmony_ci list_for_each_entry(client, &pg->clients, node) 17562306a36Sopenharmony_ci client->pdr_notify(client->priv, new_state); 17662306a36Sopenharmony_ci pg->client_state = new_state; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic void pmic_glink_pdr_callback(int state, char *svc_path, void *priv) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci struct pmic_glink *pg = priv; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci mutex_lock(&pg->state_lock); 18562306a36Sopenharmony_ci pg->pdr_state = state; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci pmic_glink_state_notify_clients(pg); 18862306a36Sopenharmony_ci mutex_unlock(&pg->state_lock); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic int pmic_glink_rpmsg_probe(struct rpmsg_device *rpdev) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct pmic_glink *pg = __pmic_glink; 19462306a36Sopenharmony_ci int ret = 0; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci mutex_lock(&__pmic_glink_lock); 19762306a36Sopenharmony_ci if (!pg) { 19862306a36Sopenharmony_ci ret = dev_err_probe(&rpdev->dev, -ENODEV, "no pmic_glink device to attach to\n"); 19962306a36Sopenharmony_ci goto out_unlock; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci dev_set_drvdata(&rpdev->dev, pg); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci mutex_lock(&pg->state_lock); 20562306a36Sopenharmony_ci pg->ept = rpdev->ept; 20662306a36Sopenharmony_ci pmic_glink_state_notify_clients(pg); 20762306a36Sopenharmony_ci mutex_unlock(&pg->state_lock); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ciout_unlock: 21062306a36Sopenharmony_ci mutex_unlock(&__pmic_glink_lock); 21162306a36Sopenharmony_ci return ret; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic void pmic_glink_rpmsg_remove(struct rpmsg_device *rpdev) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci struct pmic_glink *pg; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci mutex_lock(&__pmic_glink_lock); 21962306a36Sopenharmony_ci pg = __pmic_glink; 22062306a36Sopenharmony_ci if (!pg) 22162306a36Sopenharmony_ci goto out_unlock; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci mutex_lock(&pg->state_lock); 22462306a36Sopenharmony_ci pg->ept = NULL; 22562306a36Sopenharmony_ci pmic_glink_state_notify_clients(pg); 22662306a36Sopenharmony_ci mutex_unlock(&pg->state_lock); 22762306a36Sopenharmony_ciout_unlock: 22862306a36Sopenharmony_ci mutex_unlock(&__pmic_glink_lock); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic const struct rpmsg_device_id pmic_glink_rpmsg_id_match[] = { 23262306a36Sopenharmony_ci { "PMIC_RTR_ADSP_APPS" }, 23362306a36Sopenharmony_ci {} 23462306a36Sopenharmony_ci}; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic struct rpmsg_driver pmic_glink_rpmsg_driver = { 23762306a36Sopenharmony_ci .probe = pmic_glink_rpmsg_probe, 23862306a36Sopenharmony_ci .remove = pmic_glink_rpmsg_remove, 23962306a36Sopenharmony_ci .callback = pmic_glink_rpmsg_callback, 24062306a36Sopenharmony_ci .id_table = pmic_glink_rpmsg_id_match, 24162306a36Sopenharmony_ci .drv = { 24262306a36Sopenharmony_ci .name = "qcom_pmic_glink_rpmsg", 24362306a36Sopenharmony_ci }, 24462306a36Sopenharmony_ci}; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic int pmic_glink_probe(struct platform_device *pdev) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci const unsigned long *match_data; 24962306a36Sopenharmony_ci struct pdr_service *service; 25062306a36Sopenharmony_ci struct pmic_glink *pg; 25162306a36Sopenharmony_ci int ret; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci pg = devm_kzalloc(&pdev->dev, sizeof(*pg), GFP_KERNEL); 25462306a36Sopenharmony_ci if (!pg) 25562306a36Sopenharmony_ci return -ENOMEM; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci dev_set_drvdata(&pdev->dev, pg); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci pg->dev = &pdev->dev; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci INIT_LIST_HEAD(&pg->clients); 26262306a36Sopenharmony_ci mutex_init(&pg->client_lock); 26362306a36Sopenharmony_ci mutex_init(&pg->state_lock); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci match_data = (unsigned long *)of_device_get_match_data(&pdev->dev); 26662306a36Sopenharmony_ci if (match_data) 26762306a36Sopenharmony_ci pg->client_mask = *match_data; 26862306a36Sopenharmony_ci else 26962306a36Sopenharmony_ci pg->client_mask = PMIC_GLINK_CLIENT_DEFAULT; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci pg->pdr = pdr_handle_alloc(pmic_glink_pdr_callback, pg); 27262306a36Sopenharmony_ci if (IS_ERR(pg->pdr)) { 27362306a36Sopenharmony_ci ret = dev_err_probe(&pdev->dev, PTR_ERR(pg->pdr), 27462306a36Sopenharmony_ci "failed to initialize pdr\n"); 27562306a36Sopenharmony_ci return ret; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) { 27962306a36Sopenharmony_ci ret = pmic_glink_add_aux_device(pg, &pg->ucsi_aux, "ucsi"); 28062306a36Sopenharmony_ci if (ret) 28162306a36Sopenharmony_ci goto out_release_pdr_handle; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) { 28462306a36Sopenharmony_ci ret = pmic_glink_add_aux_device(pg, &pg->altmode_aux, "altmode"); 28562306a36Sopenharmony_ci if (ret) 28662306a36Sopenharmony_ci goto out_release_ucsi_aux; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) { 28962306a36Sopenharmony_ci ret = pmic_glink_add_aux_device(pg, &pg->ps_aux, "power-supply"); 29062306a36Sopenharmony_ci if (ret) 29162306a36Sopenharmony_ci goto out_release_altmode_aux; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci service = pdr_add_lookup(pg->pdr, "tms/servreg", "msm/adsp/charger_pd"); 29562306a36Sopenharmony_ci if (IS_ERR(service)) { 29662306a36Sopenharmony_ci ret = dev_err_probe(&pdev->dev, PTR_ERR(service), 29762306a36Sopenharmony_ci "failed adding pdr lookup for charger_pd\n"); 29862306a36Sopenharmony_ci goto out_release_aux_devices; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci mutex_lock(&__pmic_glink_lock); 30262306a36Sopenharmony_ci __pmic_glink = pg; 30362306a36Sopenharmony_ci mutex_unlock(&__pmic_glink_lock); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci return 0; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ciout_release_aux_devices: 30862306a36Sopenharmony_ci if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) 30962306a36Sopenharmony_ci pmic_glink_del_aux_device(pg, &pg->ps_aux); 31062306a36Sopenharmony_ciout_release_altmode_aux: 31162306a36Sopenharmony_ci if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) 31262306a36Sopenharmony_ci pmic_glink_del_aux_device(pg, &pg->altmode_aux); 31362306a36Sopenharmony_ciout_release_ucsi_aux: 31462306a36Sopenharmony_ci if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) 31562306a36Sopenharmony_ci pmic_glink_del_aux_device(pg, &pg->ucsi_aux); 31662306a36Sopenharmony_ciout_release_pdr_handle: 31762306a36Sopenharmony_ci pdr_handle_release(pg->pdr); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci return ret; 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic int pmic_glink_remove(struct platform_device *pdev) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct pmic_glink *pg = dev_get_drvdata(&pdev->dev); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci pdr_handle_release(pg->pdr); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_BATT)) 32962306a36Sopenharmony_ci pmic_glink_del_aux_device(pg, &pg->ps_aux); 33062306a36Sopenharmony_ci if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_ALTMODE)) 33162306a36Sopenharmony_ci pmic_glink_del_aux_device(pg, &pg->altmode_aux); 33262306a36Sopenharmony_ci if (pg->client_mask & BIT(PMIC_GLINK_CLIENT_UCSI)) 33362306a36Sopenharmony_ci pmic_glink_del_aux_device(pg, &pg->ucsi_aux); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci mutex_lock(&__pmic_glink_lock); 33662306a36Sopenharmony_ci __pmic_glink = NULL; 33762306a36Sopenharmony_ci mutex_unlock(&__pmic_glink_lock); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci return 0; 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic const unsigned long pmic_glink_sm8450_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) | 34362306a36Sopenharmony_ci BIT(PMIC_GLINK_CLIENT_ALTMODE) | 34462306a36Sopenharmony_ci BIT(PMIC_GLINK_CLIENT_UCSI); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic const struct of_device_id pmic_glink_of_match[] = { 34762306a36Sopenharmony_ci { .compatible = "qcom,sm8450-pmic-glink", .data = &pmic_glink_sm8450_client_mask }, 34862306a36Sopenharmony_ci { .compatible = "qcom,sm8550-pmic-glink", .data = &pmic_glink_sm8450_client_mask }, 34962306a36Sopenharmony_ci { .compatible = "qcom,pmic-glink" }, 35062306a36Sopenharmony_ci {} 35162306a36Sopenharmony_ci}; 35262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, pmic_glink_of_match); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic struct platform_driver pmic_glink_driver = { 35562306a36Sopenharmony_ci .probe = pmic_glink_probe, 35662306a36Sopenharmony_ci .remove = pmic_glink_remove, 35762306a36Sopenharmony_ci .driver = { 35862306a36Sopenharmony_ci .name = "qcom_pmic_glink", 35962306a36Sopenharmony_ci .of_match_table = pmic_glink_of_match, 36062306a36Sopenharmony_ci }, 36162306a36Sopenharmony_ci}; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic int pmic_glink_init(void) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci platform_driver_register(&pmic_glink_driver); 36662306a36Sopenharmony_ci register_rpmsg_driver(&pmic_glink_rpmsg_driver); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return 0; 36962306a36Sopenharmony_ci}; 37062306a36Sopenharmony_cimodule_init(pmic_glink_init); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic void pmic_glink_exit(void) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci unregister_rpmsg_driver(&pmic_glink_rpmsg_driver); 37562306a36Sopenharmony_ci platform_driver_unregister(&pmic_glink_driver); 37662306a36Sopenharmony_ci}; 37762306a36Sopenharmony_cimodule_exit(pmic_glink_exit); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ciMODULE_DESCRIPTION("Qualcomm PMIC GLINK driver"); 38062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 381