arm: tegra: thermal: Low temp to therm algorithm
[linux-3.10.git] / arch / arm / mach-tegra / tegra3_tsensor.c
1 /*
2  * arch/arm/mach-tegra/tegra3_tsensor.c
3  *
4  * Copyright (C) 2011 NVIDIA Corporation.
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17 #include <linux/kernel.h>
18 #include <linux/init.h>
19
20 #ifdef CONFIG_SENSORS_TEGRA_TSENSOR
21 #include <mach/tsensor.h>
22 #include <mach/tegra_fuse.h>
23 #include <devices.h>
24 #include <mach/iomap.h>
25 #include <mach/thermal.h>
26 #include <linux/io.h>
27 #include <linux/ioport.h>
28 #include <linux/slab.h>
29
30 /* fuse revision constants used for tsensor */
31 #define TSENSOR_FUSE_REVISION_DECIMAL 8
32 #define TSENSOR_FUSE_REVISION_INTEGER 0
33
34 /* scratch register offsets needed for powering off PMU */
35 #define SCRATCH54_OFFSET                        0x258
36 #define SCRATCH55_OFFSET                        0x25C
37
38 /* scratch 54 register bit field offsets */
39 #define PMU_OFF_DATA_OFFSET                     8
40
41 /* scratch 55 register bit field offsets */
42 #define RESET_TEGRA_OFFSET                      31
43 #define CONTROLLER_TYPE_OFFSET                  30
44 #define I2C_CONTROLLER_ID_OFFSET                27
45 #define PINMUX_OFFSET                           24
46 #define CHECKSUM_OFFSET                         16
47 #define PMU_16BIT_SUPPORT_OFFSET                15
48 /* scratch 55 register bit field masks */
49 #define RESET_TEGRA_MASK                        0x1
50 #define CONTROLLER_TYPE_MASK                    0x1
51 #define I2C_CONTROLLER_ID_MASK                  0x7
52 #define PINMUX_MASK                             0x7
53 #define CHECKSUM_MASK                           0xff
54 #define PMU_16BIT_SUPPORT_MASK                  0x1
55
56 #define TSENSOR_OFFSET  (4000 + 5000)
57
58 #ifdef CONFIG_TEGRA_INTERNAL_TSENSOR_EDP_SUPPORT
59 static int tsensor_get_temp(void *vdata, long *milli_temp)
60 {
61         struct tegra_tsensor_data *data = vdata;
62         return tsensor_thermal_get_temp(data, milli_temp);
63 }
64
65 static int tsensor_get_temp_low(void *vdata, long *milli_temp)
66 {
67         struct tegra_tsensor_data *data = vdata;
68         return tsensor_thermal_get_temp_low(data, milli_temp);
69 }
70
71 static int tsensor_set_limits(void *vdata,
72                         long lo_limit_milli,
73                         long hi_limit_milli)
74 {
75         struct tegra_tsensor_data *data = vdata;
76         return tsensor_thermal_set_limits(data,
77                                         lo_limit_milli,
78                                         hi_limit_milli);
79 }
80
81 static int tsensor_set_alert(void *vdata,
82                         void (*alert_func)(void *),
83                         void *alert_data)
84 {
85         struct tegra_tsensor_data *data = vdata;
86         return tsensor_thermal_set_alert(data, alert_func, alert_data);
87 }
88
89 static int tsensor_set_shutdown_temp(void *vdata, long shutdown_temp_milli)
90 {
91         struct tegra_tsensor_data *data = vdata;
92         return tsensor_thermal_set_shutdown_temp(data, shutdown_temp_milli);
93 }
94
95 static void tegra3_tsensor_probe_callback(struct tegra_tsensor_data *data)
96 {
97         struct tegra_thermal_device *thermal_device;
98
99         thermal_device = kzalloc(sizeof(struct tegra_thermal_device),
100                                         GFP_KERNEL);
101
102         if (!thermal_device) {
103                 pr_err("unable to allocate thermal device\n");
104                 return;
105         }
106
107         thermal_device->name = "tsensor";
108         thermal_device->data = data;
109         thermal_device->offset = TSENSOR_OFFSET;
110         thermal_device->get_temp = tsensor_get_temp;
111         thermal_device->get_temp_low = tsensor_get_temp_low;
112         thermal_device->set_limits = tsensor_set_limits;
113         thermal_device->set_alert = tsensor_set_alert;
114         thermal_device->set_shutdown_temp = tsensor_set_shutdown_temp;
115
116         if (tegra_thermal_set_device(thermal_device)) /* This should not fail */
117                 BUG();
118 }
119 #endif
120
121 static struct tegra_tsensor_platform_data tsensor_data = {
122 #ifdef CONFIG_TEGRA_INTERNAL_TSENSOR_EDP_SUPPORT
123         .probe_callback = tegra3_tsensor_probe_callback,
124 #endif
125 };
126
127 void __init tegra3_tsensor_init(struct tegra_tsensor_pmu_data *data)
128 {
129         unsigned int reg;
130         int err;
131         u32 val, checksum;
132         void __iomem *pMem = NULL;
133         /* tsensor driver is instantiated based on fuse revision */
134         err = tegra_fuse_get_revision(&reg);
135         if (err)
136                 goto labelEnd;
137         pr_info("\nTegra3 fuse revision %d ", reg);
138         if (reg < TSENSOR_FUSE_REVISION_DECIMAL)
139                 goto labelEnd;
140
141         if (!data)
142                 goto labelSkipPowerOff;
143
144         if (!request_mem_region(TEGRA_PMC_BASE +
145                 SCRATCH54_OFFSET, 8, "tegra-tsensor"))
146                 pr_err(" [%s, line=%d]: Error mem busy\n",
147                         __func__, __LINE__);
148
149         pMem = ioremap(TEGRA_PMC_BASE + SCRATCH54_OFFSET, 8);
150         if (!pMem) {
151                 pr_err(" [%s, line=%d]: can't ioremap "
152                         "pmc iomem\n", __FILE__, __LINE__);
153                 goto labelEnd;
154         }
155
156         /*
157          * Fill scratch registers to power off the device
158          * in case if temperature crosses threshold TH3
159          */
160         val = (data->poweroff_reg_data << PMU_OFF_DATA_OFFSET) |
161                 data->poweroff_reg_addr;
162         writel(val, pMem);
163
164         val = ((data->reset_tegra & RESET_TEGRA_MASK) << RESET_TEGRA_OFFSET) |
165                 ((data->controller_type & CONTROLLER_TYPE_MASK) <<
166                 CONTROLLER_TYPE_OFFSET) |
167                 ((data->i2c_controller_id & I2C_CONTROLLER_ID_MASK) <<
168                 I2C_CONTROLLER_ID_OFFSET) |
169                 ((data->pinmux & PINMUX_MASK) << PINMUX_OFFSET) |
170                 ((data->pmu_16bit_ops & PMU_16BIT_SUPPORT_MASK) <<
171                 PMU_16BIT_SUPPORT_OFFSET) | data->pmu_i2c_addr;
172
173         checksum = data->poweroff_reg_addr +
174                 data->poweroff_reg_data + (val & 0xFF) +
175                 ((val >> 8) & 0xFF) + ((val >> 24) & 0xFF);
176         checksum &= 0xFF;
177         checksum = 0x100 - checksum;
178
179         val |= (checksum << CHECKSUM_OFFSET);
180         writel(val, pMem + 4);
181
182 labelSkipPowerOff:
183         /* set platform data for device before register */
184         tegra_tsensor_device.dev.platform_data = &tsensor_data;
185         platform_device_register(&tegra_tsensor_device);
186
187 labelEnd:
188         return;
189 }
190
191 #else
192 void __init tegra3_tsensor_init(void) { }
193 #endif
194