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 int komeda_platform_probe(struct platform_device *pdev) 49 { 50 struct device *dev = &pdev->dev; 51 struct komeda_drv *mdrv; 52 int err; 53 54 mdrv = devm_kzalloc(dev, sizeof(*mdrv), GFP_KERNEL); 55 if (!mdrv) 56 return -ENOMEM; 57 58 mdrv->mdev = komeda_dev_create(dev); 59 if (IS_ERR(mdrv->mdev)) { 60 err = PTR_ERR(mdrv->mdev); 61 goto free_mdrv; 62 } 63 64 pm_runtime_enable(dev); 65 if (!pm_runtime_enabled(dev)) 66 komeda_dev_resume(mdrv->mdev); 67 68 mdrv->kms = komeda_kms_attach(mdrv->mdev); 69 if (IS_ERR(mdrv->kms)) { 70 err = PTR_ERR(mdrv->kms); 71 goto destroy_mdev; 72 } 73 74 dev_set_drvdata(dev, mdrv); 75 drm_fbdev_generic_setup(&mdrv->kms->base, 32); 76 77 return 0; 78 79 destroy_mdev: 80 if (pm_runtime_enabled(dev)) 81 pm_runtime_disable(dev); 82 else 83 komeda_dev_suspend(mdrv->mdev); 84 85 komeda_dev_destroy(mdrv->mdev); 86 87 free_mdrv: 88 devm_kfree(dev, mdrv); 89 return err; 90 } 91 92 static const struct of_device_id komeda_of_match[] = { 93 { .compatible = "arm,mali-d71", .data = d71_identify, }, 94 { .compatible = "arm,mali-d32", .data = d71_identify, }, 95 {}, 96 }; 97 98 MODULE_DEVICE_TABLE(of, komeda_of_match); 99 100 static int __maybe_unused komeda_rt_pm_suspend(struct device *dev) 101 { 102 struct komeda_drv *mdrv = dev_get_drvdata(dev); 103 104 return komeda_dev_suspend(mdrv->mdev); 105 } 106 107 static int __maybe_unused komeda_rt_pm_resume(struct device *dev) 108 { 109 struct komeda_drv *mdrv = dev_get_drvdata(dev); 110 111 return komeda_dev_resume(mdrv->mdev); 112 } 113 114 static int __maybe_unused komeda_pm_suspend(struct device *dev) 115 { 116 struct komeda_drv *mdrv = dev_get_drvdata(dev); 117 int res; 118 119 res = drm_mode_config_helper_suspend(&mdrv->kms->base); 120 121 if (!pm_runtime_status_suspended(dev)) 122 komeda_dev_suspend(mdrv->mdev); 123 124 return res; 125 } 126 127 static int __maybe_unused komeda_pm_resume(struct device *dev) 128 { 129 struct komeda_drv *mdrv = dev_get_drvdata(dev); 130 131 if (!pm_runtime_status_suspended(dev)) 132 komeda_dev_resume(mdrv->mdev); 133 134 return drm_mode_config_helper_resume(&mdrv->kms->base); 135 } 136 137 static const struct dev_pm_ops komeda_pm_ops = { 138 SET_SYSTEM_SLEEP_PM_OPS(komeda_pm_suspend, komeda_pm_resume) 139 SET_RUNTIME_PM_OPS(komeda_rt_pm_suspend, komeda_rt_pm_resume, NULL) 140 }; 141 142 static struct platform_driver komeda_platform_driver = { 143 .probe = komeda_platform_probe, 144 .remove_new = komeda_platform_remove, 145 .driver = { 146 .name = "komeda", 147 .of_match_table = komeda_of_match, 148 .pm = &komeda_pm_ops, 149 }, 150 }; 151 152 drm_module_platform_driver(komeda_platform_driver); 153 154 MODULE_AUTHOR("James.Qian.Wang <james.qian.wang@arm.com>"); 155 MODULE_DESCRIPTION("Komeda KMS driver"); 156 MODULE_LICENSE("GPL v2"); 157