1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 */ 5 6 #include <linux/module.h> 7 #include <linux/of_address.h> 8 #include <linux/platform_device.h> 9 #include <linux/thermal.h> 10 11 struct thermal_mmio { 12 void __iomem *mmio_base; 13 u32 (*read_mmio)(void __iomem *mmio_base); 14 u32 mask; 15 int factor; 16 }; 17 18 static u32 thermal_mmio_readb(void __iomem *mmio_base) 19 { 20 return readb(mmio_base); 21 } 22 23 static int thermal_mmio_get_temperature(void *private, int *temp) 24 { 25 int t; 26 struct thermal_mmio *sensor = 27 (struct thermal_mmio *)private; 28 29 t = sensor->read_mmio(sensor->mmio_base) & sensor->mask; 30 t *= sensor->factor; 31 32 *temp = t; 33 34 return 0; 35 } 36 37 static struct thermal_zone_of_device_ops thermal_mmio_ops = { 38 .get_temp = thermal_mmio_get_temperature, 39 }; 40 41 static int thermal_mmio_probe(struct platform_device *pdev) 42 { 43 struct resource *resource; 44 struct thermal_mmio *sensor; 45 int (*sensor_init_func)(struct platform_device *pdev, 46 struct thermal_mmio *sensor); 47 struct thermal_zone_device *thermal_zone; 48 int ret; 49 int temperature; 50 51 sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL); 52 if (!sensor) 53 return -ENOMEM; 54 55 resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); 56 if (IS_ERR(resource)) { 57 dev_err(&pdev->dev, 58 "fail to get platform memory resource (%ld)\n", 59 PTR_ERR(resource)); 60 return PTR_ERR(resource); 61 } 62 63 sensor->mmio_base = devm_ioremap_resource(&pdev->dev, resource); 64 if (IS_ERR(sensor->mmio_base)) { 65 dev_err(&pdev->dev, "failed to ioremap memory (%ld)\n", 66 PTR_ERR(sensor->mmio_base)); 67 return PTR_ERR(sensor->mmio_base); 68 } 69 70 sensor_init_func = device_get_match_data(&pdev->dev); 71 if (sensor_init_func) { 72 ret = sensor_init_func(pdev, sensor); 73 if (ret) { 74 dev_err(&pdev->dev, 75 "failed to initialize sensor (%d)\n", 76 ret); 77 return ret; 78 } 79 } 80 81 thermal_zone = devm_thermal_zone_of_sensor_register(&pdev->dev, 82 0, 83 sensor, 84 &thermal_mmio_ops); 85 if (IS_ERR(thermal_zone)) { 86 dev_err(&pdev->dev, 87 "failed to register sensor (%ld)\n", 88 PTR_ERR(thermal_zone)); 89 return PTR_ERR(thermal_zone); 90 } 91 92 thermal_mmio_get_temperature(sensor, &temperature); 93 dev_info(&pdev->dev, 94 "thermal mmio sensor %s registered, current temperature: %d\n", 95 pdev->name, temperature); 96 97 return 0; 98 } 99 100 static int al_thermal_init(struct platform_device *pdev, 101 struct thermal_mmio *sensor) 102 { 103 sensor->read_mmio = thermal_mmio_readb; 104 sensor->mask = 0xff; 105 sensor->factor = 1000; 106 107 return 0; 108 } 109 110 static const struct of_device_id thermal_mmio_id_table[] = { 111 { .compatible = "amazon,al-thermal", .data = al_thermal_init}, 112 {} 113 }; 114 MODULE_DEVICE_TABLE(of, thermal_mmio_id_table); 115 116 static struct platform_driver thermal_mmio_driver = { 117 .probe = thermal_mmio_probe, 118 .driver = { 119 .name = "thermal-mmio", 120 .owner = THIS_MODULE, 121 .of_match_table = of_match_ptr(thermal_mmio_id_table), 122 }, 123 }; 124 125 module_platform_driver(thermal_mmio_driver); 126 127 MODULE_AUTHOR("Talel Shenhar <talel@amazon.com>"); 128 MODULE_DESCRIPTION("Thermal MMIO Driver"); 129 MODULE_LICENSE("GPL v2"); 130