123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- /* Copyright (c) 2010, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/err.h>
- #include <linux/thermal.h>
- #include <linux/slab.h>
- #include <linux/io.h>
- #include <mach/msm_memtypes.h>
- #define POP_MEM_LPDDR1_REFRESH_MASK 0x00000700
- #define POP_MEM_LPDDR1_REFRESH_SHIFT 0x8
- #define POP_MEM_LPDDR2_REFRESH_MASK 0x00000007
- #define POP_MEM_LPDDR2_REFRESH_SHIFT 0x0
- #define POP_MEM_REFRESH_REG 0x3C
- #define POP_MEM_LOW_TEMPERATURE 25000
- #define POP_MEM_NORMAL_TEMPERATURE 50000
- #define POP_MEM_HIGH_TEMPERATURE 85000
- #define POP_MEM_TRIP_OUT_OF_SPEC 0
- #define POP_MEM_TRIP_NUM 1
- struct pop_mem_tm_device {
- unsigned long baseaddr;
- struct thermal_zone_device *tz_dev;
- unsigned long refresh_mask;
- unsigned int refresh_shift;
- };
- static int pop_mem_tm_read_refresh(struct pop_mem_tm_device *tm,
- unsigned int *ref_rate){
- unsigned int ref;
- ref = __raw_readl(tm->baseaddr + POP_MEM_REFRESH_REG);
- *ref_rate = (ref & tm->refresh_mask) >> tm->refresh_shift;
- return 0;
- }
- static int pop_mem_tm_get_temperature(struct thermal_zone_device *thermal,
- unsigned long *temperature)
- {
- struct pop_mem_tm_device *tm = thermal->devdata;
- unsigned int ref_rate;
- int rc;
- if (!tm || !temperature)
- return -EINVAL;
- rc = pop_mem_tm_read_refresh(tm, &ref_rate);
- if (rc < 0)
- return rc;
- switch (ref_rate) {
- case 0:
- case 1:
- case 2:
- *temperature = POP_MEM_LOW_TEMPERATURE;
- break;
- case 3:
- case 4:
- *temperature = POP_MEM_NORMAL_TEMPERATURE;
- break;
- case 5:
- case 6:
- case 7:
- *temperature = POP_MEM_HIGH_TEMPERATURE;
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- static int pop_mem_tm_get_trip_type(struct thermal_zone_device *thermal,
- int trip, enum thermal_trip_type *type)
- {
- struct pop_mem_tm_device *tm = thermal->devdata;
- if (!tm || trip < 0 || !type)
- return -EINVAL;
- if (trip == POP_MEM_TRIP_OUT_OF_SPEC)
- *type = THERMAL_TRIP_CRITICAL;
- else
- return -EINVAL;
- return 0;
- }
- static int pop_mem_tm_get_trip_temperature(struct thermal_zone_device *thermal,
- int trip, unsigned long *temperature)
- {
- struct pop_mem_tm_device *tm = thermal->devdata;
- if (!tm || trip < 0 || !temperature)
- return -EINVAL;
- if (trip == POP_MEM_TRIP_OUT_OF_SPEC)
- *temperature = POP_MEM_HIGH_TEMPERATURE;
- else
- return -EINVAL;
- return 0;
- }
- static int pop_mem_tm_get_crit_temperature(struct thermal_zone_device *thermal,
- unsigned long *temperature)
- {
- struct pop_mem_tm_device *tm = thermal->devdata;
- if (!tm || !temperature)
- return -EINVAL;
- *temperature = POP_MEM_HIGH_TEMPERATURE;
- return 0;
- }
- static struct thermal_zone_device_ops pop_mem_thermal_zone_ops = {
- .get_temp = pop_mem_tm_get_temperature,
- .get_trip_type = pop_mem_tm_get_trip_type,
- .get_trip_temp = pop_mem_tm_get_trip_temperature,
- .get_crit_temp = pop_mem_tm_get_crit_temperature,
- };
- static int __devinit pop_mem_tm_probe(struct platform_device *pdev)
- {
- int rc, len, numcontrollers;
- struct resource *controller_mem = NULL;
- struct resource *res_mem = NULL;
- struct pop_mem_tm_device *tmdev = NULL;
- void __iomem *base = NULL;
- rc = len = 0;
- numcontrollers = get_num_populated_chipselects();
- if (pdev->id >= numcontrollers) {
- pr_err("%s: memory controller %d does not exist", __func__,
- pdev->id);
- rc = -ENODEV;
- goto fail;
- }
- controller_mem = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "physbase");
- if (!controller_mem) {
- pr_err("%s: could not get resources for controller %d",
- __func__, pdev->id);
- rc = -EFAULT;
- goto fail;
- }
- len = controller_mem->end - controller_mem->start + 1;
- res_mem = request_mem_region(controller_mem->start, len,
- controller_mem->name);
- if (!res_mem) {
- pr_err("%s: Could not request memory region: "
- "start=%p, len=%d\n", __func__,
- (void *) controller_mem->start, len);
- rc = -EBUSY;
- goto fail;
- }
- base = ioremap(res_mem->start, len);
- if (!base) {
- pr_err("%s: Could not ioremap: start=%p, len=%d\n",
- __func__, (void *) controller_mem->start, len);
- rc = -EBUSY;
- goto fail;
- }
- tmdev = kzalloc(sizeof(*tmdev), GFP_KERNEL);
- if (tmdev == NULL) {
- pr_err("%s: kzalloc() failed.\n", __func__);
- rc = -ENOMEM;
- goto fail;
- }
- if (numcontrollers == 1) {
- tmdev->refresh_mask = POP_MEM_LPDDR1_REFRESH_MASK;
- tmdev->refresh_shift = POP_MEM_LPDDR1_REFRESH_SHIFT;
- } else {
- tmdev->refresh_mask = POP_MEM_LPDDR2_REFRESH_MASK;
- tmdev->refresh_shift = POP_MEM_LPDDR2_REFRESH_SHIFT;
- }
- tmdev->baseaddr = (unsigned long) base;
- tmdev->tz_dev = thermal_zone_device_register("msm_popmem_tz",
- POP_MEM_TRIP_NUM, tmdev,
- &pop_mem_thermal_zone_ops,
- 0, 0, 0, 0);
- if (tmdev->tz_dev == NULL) {
- pr_err("%s: thermal_zone_device_register() failed.\n",
- __func__);
- goto fail;
- }
- platform_set_drvdata(pdev, tmdev);
- pr_notice("%s: device %d probed successfully\n", __func__, pdev->id);
- return rc;
- fail:
- if (base)
- iounmap(base);
- if (res_mem)
- release_mem_region(controller_mem->start, len);
- kfree(tmdev);
- return rc;
- }
- static int __devexit pop_mem_tm_remove(struct platform_device *pdev)
- {
- int len;
- struct pop_mem_tm_device *tmdev = platform_get_drvdata(pdev);
- struct resource *controller_mem;
- iounmap((void __iomem *)tmdev->baseaddr);
- controller_mem = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "physbase");
- len = controller_mem->end - controller_mem->start + 1;
- release_mem_region(controller_mem->start, len);
- thermal_zone_device_unregister(tmdev->tz_dev);
- platform_set_drvdata(pdev, NULL);
- kfree(tmdev);
- return 0;
- }
- static struct platform_driver pop_mem_tm_driver = {
- .probe = pop_mem_tm_probe,
- .remove = pop_mem_tm_remove,
- .driver = {
- .name = "msm_popmem-tm",
- .owner = THIS_MODULE
- },
- };
- static int __init pop_mem_tm_init(void)
- {
- return platform_driver_register(&pop_mem_tm_driver);
- }
- static void __exit pop_mem_tm_exit(void)
- {
- platform_driver_unregister(&pop_mem_tm_driver);
- }
- module_init(pop_mem_tm_init);
- module_exit(pop_mem_tm_exit);
- MODULE_LICENSE("GPL v2");
- MODULE_DESCRIPTION("Pop memory thermal manager driver");
- MODULE_VERSION("1.0");
- MODULE_ALIAS("platform:popmem-tm");
|