1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved. 4 * Author: James.Qian.Wang <james.qian.wang@arm.com> 5 * 6 */ 7 #include <linux/module.h> 8 #include <linux/kernel.h> 9 #include <linux/of.h> 10 #include <linux/platform_device.h> 11 #include <linux/pm_runtime.h> 12 #include <drm/drm_fbdev_generic.h> 13 #include <drm/drm_module.h> 14 #include <drm/drm_of.h> 15 #include "komeda_dev.h" 16 #include "komeda_kms.h" 17 18 struct komeda_drv { 19 struct komeda_dev *mdev; 20 struct komeda_kms_dev *kms; 21 }; 22 23 struct komeda_dev *dev_to_mdev(struct device *dev) 24 { 25 struct komeda_drv *mdrv = dev_get_drvdata(dev); 26 27 return mdrv ? mdrv->mdev : NULL; 28 } 29 30 static void komeda_platform_remove(struct platform_device *pdev) 31 { 32 struct device *dev = &pdev->dev; 33 struct komeda_drv *mdrv = dev_get_drvdata(dev); 34 35 komeda_kms_detach(mdrv->kms); 36 37 if (pm_runtime_enabled(dev)) 38 pm_runtime_disable(dev); 39 else 40 komeda_dev_suspend(mdrv->mdev); 41 42 komeda_dev_destroy(mdrv->mdev); 43 44 dev_set_drvdata(dev, NULL); 45 devm_kfree(dev, mdrv); 46 } 47 48 static void komeda_platform_shutdown(struct platform_device *pdev) 49 { 50 struct device *dev = &pdev->dev; 51 struct komeda_drv *mdrv = dev_get_drvdata(dev); 52 53 komeda_kms_shutdown(mdrv->kms); 54 } 55 56 static int komeda_platform_probe(struct platform_device *pdev) 57 { 58 struct device *dev = &pdev->dev; 59 struct komeda_drv *mdrv; 60 int err; 61 62 mdrv = devm_kzalloc(dev, sizeof(*mdrv), GFP_KERNEL); 63 if (!mdrv) 64 return -ENOMEM; 65 66 mdrv->mdev = komeda_dev_create(dev); 67 if (IS_ERR(mdrv->mdev)) { 68 err = PTR_ERR(mdrv->mdev); 69 goto free_mdrv; 70 } 71 72 pm_runtime_enable(dev); 73 if (!pm_runtime_enabled(dev)) 74 komeda_dev_resume(mdrv->mdev); 75 76 mdrv->kms = komeda_kms_attach(mdrv->mdev); 77 if (IS_ERR(mdrv->kms)) { 78 err = PTR_ERR(mdrv->kms); 79 goto destroy_mdev; 80 } 81 82 dev_set_drvdata(dev, mdrv); 83 drm_fbdev_generic_setup(&mdrv->kms->base, 32); 84 85 return 0; 86 87 destroy_mdev: 88 if (pm_runtime_enabled(dev)) 89 pm_runtime_disable(dev); 90 else 91 komeda_dev_suspend(mdrv->mdev); 92 93 komeda_dev_destroy(mdrv->mdev); 94 95 free_mdrv: 96 devm_kfree(dev, mdrv); 97 return err; 98 } 99 100 static const struct of_device_id komeda_of_match[] = { 101 { .compatible = "arm,mali-d71", .data = d71_identify, }, 102 { .compatible = "arm,mali-d32", .data = d71_identify, }, 103 {}, 104 }; 105 106 MODULE_DEVICE_TABLE(of, komeda_of_match); 107 108 static int __maybe_unused komeda_rt_pm_suspend(struct device *dev) 109 { 110 struct komeda_drv *mdrv = dev_get_drvdata(dev); 111 112 return komeda_dev_suspend(mdrv->mdev); 113 } 114 115 static int __maybe_unused komeda_rt_pm_resume(struct device *dev) 116 { 117 struct komeda_drv *mdrv = dev_get_drvdata(dev); 118 119 return komeda_dev_resume(mdrv->mdev); 120 } 121 122 static int __maybe_unused komeda_pm_suspend(struct device *dev) 123 { 124 struct komeda_drv *mdrv = dev_get_drvdata(dev); 125 int res; 126 127 res = drm_mode_config_helper_suspend(&mdrv->kms->base); 128 129 if (!pm_runtime_status_suspended(dev)) 130 komeda_dev_suspend(mdrv->mdev); 131 132 return res; 133 } 134 135 static int __maybe_unused komeda_pm_resume(struct device *dev) 136 { 137 struct komeda_drv *mdrv = dev_get_drvdata(dev); 138 139 if (!pm_runtime_status_suspended(dev)) 140 komeda_dev_resume(mdrv->mdev); 141 142 return drm_mode_config_helper_resume(&mdrv->kms->base); 143 } 144 145 static const struct dev_pm_ops komeda_pm_ops = { 146 SET_SYSTEM_SLEEP_PM_OPS(komeda_pm_suspend, komeda_pm_resume) 147 SET_RUNTIME_PM_OPS(komeda_rt_pm_suspend, komeda_rt_pm_resume, NULL) 148 }; 149 150 static struct platform_driver komeda_platform_driver = { 151 .probe = komeda_platform_probe, 152 .remove_new = komeda_platform_remove, 153 .shutdown = komeda_platform_shutdown, 154 .driver = { 155 .name = "komeda", 156 .of_match_table = komeda_of_match, 157 .pm = &komeda_pm_ops, 158 }, 159 }; 160 161 drm_module_platform_driver(komeda_platform_driver); 162 163 MODULE_AUTHOR("James.Qian.Wang <james.qian.wang@arm.com>"); 164 MODULE_DESCRIPTION("Komeda KMS driver"); 165 MODULE_LICENSE("GPL v2"); 166