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 23*44b5554dSDaniel Lezcano static int thermal_mmio_get_temperature(struct thermal_zone_device *tz, int *temp) 2471aa3693STalel Shenhar { 2571aa3693STalel Shenhar int t; 26*44b5554dSDaniel Lezcano struct thermal_mmio *sensor = tz->devdata; 2771aa3693STalel Shenhar 2871aa3693STalel Shenhar t = sensor->read_mmio(sensor->mmio_base) & sensor->mask; 2971aa3693STalel Shenhar t *= sensor->factor; 3071aa3693STalel Shenhar 3171aa3693STalel Shenhar *temp = t; 3271aa3693STalel Shenhar 3371aa3693STalel Shenhar return 0; 3471aa3693STalel Shenhar } 3571aa3693STalel Shenhar 36*44b5554dSDaniel Lezcano static const struct thermal_zone_device_ops thermal_mmio_ops = { 3771aa3693STalel Shenhar .get_temp = thermal_mmio_get_temperature, 3871aa3693STalel Shenhar }; 3971aa3693STalel Shenhar 4071aa3693STalel Shenhar static int thermal_mmio_probe(struct platform_device *pdev) 4171aa3693STalel Shenhar { 4271aa3693STalel Shenhar struct resource *resource; 4371aa3693STalel Shenhar struct thermal_mmio *sensor; 4471aa3693STalel Shenhar int (*sensor_init_func)(struct platform_device *pdev, 4571aa3693STalel Shenhar struct thermal_mmio *sensor); 4671aa3693STalel Shenhar struct thermal_zone_device *thermal_zone; 4771aa3693STalel Shenhar int ret; 4871aa3693STalel Shenhar int temperature; 4971aa3693STalel Shenhar 5071aa3693STalel Shenhar sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL); 5171aa3693STalel Shenhar if (!sensor) 5271aa3693STalel Shenhar return -ENOMEM; 5371aa3693STalel Shenhar 5471aa3693STalel Shenhar resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); 5571aa3693STalel Shenhar sensor->mmio_base = devm_ioremap_resource(&pdev->dev, resource); 568cd7ab2aSRuiqi Gong if (IS_ERR(sensor->mmio_base)) 5771aa3693STalel Shenhar return PTR_ERR(sensor->mmio_base); 5871aa3693STalel Shenhar 5971aa3693STalel Shenhar sensor_init_func = device_get_match_data(&pdev->dev); 6071aa3693STalel Shenhar if (sensor_init_func) { 6171aa3693STalel Shenhar ret = sensor_init_func(pdev, sensor); 6271aa3693STalel Shenhar if (ret) { 6371aa3693STalel Shenhar dev_err(&pdev->dev, 6471aa3693STalel Shenhar "failed to initialize sensor (%d)\n", 6571aa3693STalel Shenhar ret); 6671aa3693STalel Shenhar return ret; 6771aa3693STalel Shenhar } 6871aa3693STalel Shenhar } 6971aa3693STalel Shenhar 70*44b5554dSDaniel Lezcano thermal_zone = devm_thermal_of_zone_register(&pdev->dev, 7171aa3693STalel Shenhar 0, 7271aa3693STalel Shenhar sensor, 7371aa3693STalel Shenhar &thermal_mmio_ops); 7471aa3693STalel Shenhar if (IS_ERR(thermal_zone)) { 7571aa3693STalel Shenhar dev_err(&pdev->dev, 7671aa3693STalel Shenhar "failed to register sensor (%ld)\n", 7771aa3693STalel Shenhar PTR_ERR(thermal_zone)); 7871aa3693STalel Shenhar return PTR_ERR(thermal_zone); 7971aa3693STalel Shenhar } 8071aa3693STalel Shenhar 81*44b5554dSDaniel Lezcano thermal_mmio_get_temperature(thermal_zone, &temperature); 8271aa3693STalel Shenhar dev_info(&pdev->dev, 8371aa3693STalel Shenhar "thermal mmio sensor %s registered, current temperature: %d\n", 8471aa3693STalel Shenhar pdev->name, temperature); 8571aa3693STalel Shenhar 8671aa3693STalel Shenhar return 0; 8771aa3693STalel Shenhar } 8871aa3693STalel Shenhar 8971aa3693STalel Shenhar static int al_thermal_init(struct platform_device *pdev, 9071aa3693STalel Shenhar struct thermal_mmio *sensor) 9171aa3693STalel Shenhar { 9271aa3693STalel Shenhar sensor->read_mmio = thermal_mmio_readb; 9371aa3693STalel Shenhar sensor->mask = 0xff; 9471aa3693STalel Shenhar sensor->factor = 1000; 9571aa3693STalel Shenhar 9671aa3693STalel Shenhar return 0; 9771aa3693STalel Shenhar } 9871aa3693STalel Shenhar 9971aa3693STalel Shenhar static const struct of_device_id thermal_mmio_id_table[] = { 10071aa3693STalel Shenhar { .compatible = "amazon,al-thermal", .data = al_thermal_init}, 10171aa3693STalel Shenhar {} 10271aa3693STalel Shenhar }; 10371aa3693STalel Shenhar MODULE_DEVICE_TABLE(of, thermal_mmio_id_table); 10471aa3693STalel Shenhar 10571aa3693STalel Shenhar static struct platform_driver thermal_mmio_driver = { 10671aa3693STalel Shenhar .probe = thermal_mmio_probe, 10771aa3693STalel Shenhar .driver = { 10871aa3693STalel Shenhar .name = "thermal-mmio", 10971aa3693STalel Shenhar .of_match_table = of_match_ptr(thermal_mmio_id_table), 11071aa3693STalel Shenhar }, 11171aa3693STalel Shenhar }; 11271aa3693STalel Shenhar 11371aa3693STalel Shenhar module_platform_driver(thermal_mmio_driver); 11471aa3693STalel Shenhar 11571aa3693STalel Shenhar MODULE_AUTHOR("Talel Shenhar <talel@amazon.com>"); 11671aa3693STalel Shenhar MODULE_DESCRIPTION("Thermal MMIO Driver"); 11771aa3693STalel Shenhar MODULE_LICENSE("GPL v2"); 118