171aa3693STalel Shenhar // SPDX-License-Identifier: GPL-2.0 271aa3693STalel Shenhar /* 371aa3693STalel Shenhar * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 471aa3693STalel Shenhar */ 571aa3693STalel Shenhar 671aa3693STalel Shenhar #include <linux/module.h> 771aa3693STalel Shenhar #include <linux/of_address.h> 871aa3693STalel Shenhar #include <linux/platform_device.h> 971aa3693STalel Shenhar #include <linux/thermal.h> 1071aa3693STalel Shenhar 1171aa3693STalel Shenhar struct thermal_mmio { 1271aa3693STalel Shenhar void __iomem *mmio_base; 1371aa3693STalel Shenhar u32 (*read_mmio)(void __iomem *mmio_base); 1471aa3693STalel Shenhar u32 mask; 1571aa3693STalel Shenhar int factor; 1671aa3693STalel Shenhar }; 1771aa3693STalel Shenhar 1871aa3693STalel Shenhar static u32 thermal_mmio_readb(void __iomem *mmio_base) 1971aa3693STalel Shenhar { 2071aa3693STalel Shenhar return readb(mmio_base); 2171aa3693STalel Shenhar } 2271aa3693STalel Shenhar 2371aa3693STalel Shenhar static int thermal_mmio_get_temperature(void *private, int *temp) 2471aa3693STalel Shenhar { 2571aa3693STalel Shenhar int t; 2671aa3693STalel Shenhar struct thermal_mmio *sensor = 2771aa3693STalel Shenhar (struct thermal_mmio *)private; 2871aa3693STalel Shenhar 2971aa3693STalel Shenhar t = sensor->read_mmio(sensor->mmio_base) & sensor->mask; 3071aa3693STalel Shenhar t *= sensor->factor; 3171aa3693STalel Shenhar 3271aa3693STalel Shenhar *temp = t; 3371aa3693STalel Shenhar 3471aa3693STalel Shenhar return 0; 3571aa3693STalel Shenhar } 3671aa3693STalel Shenhar 3771aa3693STalel Shenhar static struct thermal_zone_of_device_ops thermal_mmio_ops = { 3871aa3693STalel Shenhar .get_temp = thermal_mmio_get_temperature, 3971aa3693STalel Shenhar }; 4071aa3693STalel Shenhar 4171aa3693STalel Shenhar static int thermal_mmio_probe(struct platform_device *pdev) 4271aa3693STalel Shenhar { 4371aa3693STalel Shenhar struct resource *resource; 4471aa3693STalel Shenhar struct thermal_mmio *sensor; 4571aa3693STalel Shenhar int (*sensor_init_func)(struct platform_device *pdev, 4671aa3693STalel Shenhar struct thermal_mmio *sensor); 4771aa3693STalel Shenhar struct thermal_zone_device *thermal_zone; 4871aa3693STalel Shenhar int ret; 4971aa3693STalel Shenhar int temperature; 5071aa3693STalel Shenhar 5171aa3693STalel Shenhar sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL); 5271aa3693STalel Shenhar if (!sensor) 5371aa3693STalel Shenhar return -ENOMEM; 5471aa3693STalel Shenhar 5571aa3693STalel Shenhar resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); 5671aa3693STalel Shenhar sensor->mmio_base = devm_ioremap_resource(&pdev->dev, resource); 57*8cd7ab2aSRuiqi Gong if (IS_ERR(sensor->mmio_base)) 5871aa3693STalel Shenhar return PTR_ERR(sensor->mmio_base); 5971aa3693STalel Shenhar 6071aa3693STalel Shenhar sensor_init_func = device_get_match_data(&pdev->dev); 6171aa3693STalel Shenhar if (sensor_init_func) { 6271aa3693STalel Shenhar ret = sensor_init_func(pdev, sensor); 6371aa3693STalel Shenhar if (ret) { 6471aa3693STalel Shenhar dev_err(&pdev->dev, 6571aa3693STalel Shenhar "failed to initialize sensor (%d)\n", 6671aa3693STalel Shenhar ret); 6771aa3693STalel Shenhar return ret; 6871aa3693STalel Shenhar } 6971aa3693STalel Shenhar } 7071aa3693STalel Shenhar 7171aa3693STalel Shenhar thermal_zone = devm_thermal_zone_of_sensor_register(&pdev->dev, 7271aa3693STalel Shenhar 0, 7371aa3693STalel Shenhar sensor, 7471aa3693STalel Shenhar &thermal_mmio_ops); 7571aa3693STalel Shenhar if (IS_ERR(thermal_zone)) { 7671aa3693STalel Shenhar dev_err(&pdev->dev, 7771aa3693STalel Shenhar "failed to register sensor (%ld)\n", 7871aa3693STalel Shenhar PTR_ERR(thermal_zone)); 7971aa3693STalel Shenhar return PTR_ERR(thermal_zone); 8071aa3693STalel Shenhar } 8171aa3693STalel Shenhar 8271aa3693STalel Shenhar thermal_mmio_get_temperature(sensor, &temperature); 8371aa3693STalel Shenhar dev_info(&pdev->dev, 8471aa3693STalel Shenhar "thermal mmio sensor %s registered, current temperature: %d\n", 8571aa3693STalel Shenhar pdev->name, temperature); 8671aa3693STalel Shenhar 8771aa3693STalel Shenhar return 0; 8871aa3693STalel Shenhar } 8971aa3693STalel Shenhar 9071aa3693STalel Shenhar static int al_thermal_init(struct platform_device *pdev, 9171aa3693STalel Shenhar struct thermal_mmio *sensor) 9271aa3693STalel Shenhar { 9371aa3693STalel Shenhar sensor->read_mmio = thermal_mmio_readb; 9471aa3693STalel Shenhar sensor->mask = 0xff; 9571aa3693STalel Shenhar sensor->factor = 1000; 9671aa3693STalel Shenhar 9771aa3693STalel Shenhar return 0; 9871aa3693STalel Shenhar } 9971aa3693STalel Shenhar 10071aa3693STalel Shenhar static const struct of_device_id thermal_mmio_id_table[] = { 10171aa3693STalel Shenhar { .compatible = "amazon,al-thermal", .data = al_thermal_init}, 10271aa3693STalel Shenhar {} 10371aa3693STalel Shenhar }; 10471aa3693STalel Shenhar MODULE_DEVICE_TABLE(of, thermal_mmio_id_table); 10571aa3693STalel Shenhar 10671aa3693STalel Shenhar static struct platform_driver thermal_mmio_driver = { 10771aa3693STalel Shenhar .probe = thermal_mmio_probe, 10871aa3693STalel Shenhar .driver = { 10971aa3693STalel Shenhar .name = "thermal-mmio", 11071aa3693STalel Shenhar .of_match_table = of_match_ptr(thermal_mmio_id_table), 11171aa3693STalel Shenhar }, 11271aa3693STalel Shenhar }; 11371aa3693STalel Shenhar 11471aa3693STalel Shenhar module_platform_driver(thermal_mmio_driver); 11571aa3693STalel Shenhar 11671aa3693STalel Shenhar MODULE_AUTHOR("Talel Shenhar <talel@amazon.com>"); 11771aa3693STalel Shenhar MODULE_DESCRIPTION("Thermal MMIO Driver"); 11871aa3693STalel Shenhar MODULE_LICENSE("GPL v2"); 119