diff options
author | Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 2013-01-31 04:03:33 -0500 |
---|---|---|
committer | Zhang Rui <rui.zhang@intel.com> | 2013-02-06 01:13:58 -0500 |
commit | 3676d1dd3d3069ca70b8075c0e86482cbaa01c2f (patch) | |
tree | 425b072f4e6122da75182681005accb6e9243ee0 /drivers/thermal | |
parent | b2bbc6a2ace78eaca2f6482b58b984519aa783ac (diff) |
thermal: rcar: multi channel support
R-Car thermal sensor will be multi channel sensor in next generation.
But "IRQ controlling method" and "register mapping" are
different between old/new chip.
This patch adds multi sensor support.
Then, this driver assumes there is common register
if platform has IRQ resource.
The IRQ will be supported soon.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Diffstat (limited to 'drivers/thermal')
-rw-r--r-- | drivers/thermal/rcar_thermal.c | 128 |
1 files changed, 94 insertions, 34 deletions
diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c index e19b267f76d6..1ba02770153a 100644 --- a/drivers/thermal/rcar_thermal.c +++ b/drivers/thermal/rcar_thermal.c | |||
@@ -38,16 +38,27 @@ | |||
38 | /* THSSR */ | 38 | /* THSSR */ |
39 | #define CTEMP 0x3f | 39 | #define CTEMP 0x3f |
40 | 40 | ||
41 | struct rcar_thermal_common { | ||
42 | void __iomem *base; | ||
43 | struct device *dev; | ||
44 | struct list_head head; | ||
45 | }; | ||
41 | 46 | ||
42 | struct rcar_thermal_priv { | 47 | struct rcar_thermal_priv { |
43 | void __iomem *base; | 48 | void __iomem *base; |
44 | struct device *dev; | 49 | struct rcar_thermal_common *common; |
50 | struct thermal_zone_device *zone; | ||
45 | struct mutex lock; | 51 | struct mutex lock; |
52 | struct list_head list; | ||
46 | }; | 53 | }; |
47 | 54 | ||
55 | #define rcar_thermal_for_each_priv(pos, common) \ | ||
56 | list_for_each_entry(pos, &common->head, list) | ||
57 | |||
48 | #define MCELSIUS(temp) ((temp) * 1000) | 58 | #define MCELSIUS(temp) ((temp) * 1000) |
49 | #define rcar_zone_to_priv(zone) ((zone)->devdata) | 59 | #define rcar_zone_to_priv(zone) ((zone)->devdata) |
50 | #define rcar_priv_to_dev(priv) ((priv)->dev) | 60 | #define rcar_priv_to_dev(priv) ((priv)->common->dev) |
61 | #define rcar_has_irq_support(priv) ((priv)->common->base) | ||
51 | 62 | ||
52 | /* | 63 | /* |
53 | * basic functions | 64 | * basic functions |
@@ -129,6 +140,7 @@ static int rcar_thermal_get_trip_type(struct thermal_zone_device *zone, | |||
129 | int trip, enum thermal_trip_type *type) | 140 | int trip, enum thermal_trip_type *type) |
130 | { | 141 | { |
131 | struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone); | 142 | struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone); |
143 | struct device *dev = rcar_priv_to_dev(priv); | ||
132 | 144 | ||
133 | /* see rcar_thermal_get_temp() */ | 145 | /* see rcar_thermal_get_temp() */ |
134 | switch (trip) { | 146 | switch (trip) { |
@@ -136,7 +148,7 @@ static int rcar_thermal_get_trip_type(struct thermal_zone_device *zone, | |||
136 | *type = THERMAL_TRIP_CRITICAL; | 148 | *type = THERMAL_TRIP_CRITICAL; |
137 | break; | 149 | break; |
138 | default: | 150 | default: |
139 | dev_err(priv->dev, "rcar driver trip error\n"); | 151 | dev_err(dev, "rcar driver trip error\n"); |
140 | return -EINVAL; | 152 | return -EINVAL; |
141 | } | 153 | } |
142 | 154 | ||
@@ -147,6 +159,7 @@ static int rcar_thermal_get_trip_temp(struct thermal_zone_device *zone, | |||
147 | int trip, unsigned long *temp) | 159 | int trip, unsigned long *temp) |
148 | { | 160 | { |
149 | struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone); | 161 | struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone); |
162 | struct device *dev = rcar_priv_to_dev(priv); | ||
150 | 163 | ||
151 | /* see rcar_thermal_get_temp() */ | 164 | /* see rcar_thermal_get_temp() */ |
152 | switch (trip) { | 165 | switch (trip) { |
@@ -154,7 +167,7 @@ static int rcar_thermal_get_trip_temp(struct thermal_zone_device *zone, | |||
154 | *temp = MCELSIUS(90); | 167 | *temp = MCELSIUS(90); |
155 | break; | 168 | break; |
156 | default: | 169 | default: |
157 | dev_err(priv->dev, "rcar driver trip error\n"); | 170 | dev_err(dev, "rcar driver trip error\n"); |
158 | return -EINVAL; | 171 | return -EINVAL; |
159 | } | 172 | } |
160 | 173 | ||
@@ -165,12 +178,12 @@ static int rcar_thermal_notify(struct thermal_zone_device *zone, | |||
165 | int trip, enum thermal_trip_type type) | 178 | int trip, enum thermal_trip_type type) |
166 | { | 179 | { |
167 | struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone); | 180 | struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone); |
181 | struct device *dev = rcar_priv_to_dev(priv); | ||
168 | 182 | ||
169 | switch (type) { | 183 | switch (type) { |
170 | case THERMAL_TRIP_CRITICAL: | 184 | case THERMAL_TRIP_CRITICAL: |
171 | /* FIXME */ | 185 | /* FIXME */ |
172 | dev_warn(priv->dev, | 186 | dev_warn(dev, "Thermal reached to critical temperature\n"); |
173 | "Thermal reached to critical temperature\n"); | ||
174 | machine_power_off(); | 187 | machine_power_off(); |
175 | break; | 188 | break; |
176 | default: | 189 | default: |
@@ -192,51 +205,98 @@ static struct thermal_zone_device_ops rcar_thermal_zone_ops = { | |||
192 | */ | 205 | */ |
193 | static int rcar_thermal_probe(struct platform_device *pdev) | 206 | static int rcar_thermal_probe(struct platform_device *pdev) |
194 | { | 207 | { |
195 | struct thermal_zone_device *zone; | 208 | struct rcar_thermal_common *common; |
196 | struct rcar_thermal_priv *priv; | 209 | struct rcar_thermal_priv *priv; |
197 | struct resource *res; | 210 | struct device *dev = &pdev->dev; |
198 | 211 | struct resource *res, *irq; | |
199 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 212 | int mres = 0; |
200 | if (!res) { | 213 | int i; |
201 | dev_err(&pdev->dev, "Could not get platform resource\n"); | ||
202 | return -ENODEV; | ||
203 | } | ||
204 | 214 | ||
205 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | 215 | common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL); |
206 | if (!priv) { | 216 | if (!common) { |
207 | dev_err(&pdev->dev, "Could not allocate priv\n"); | 217 | dev_err(dev, "Could not allocate common\n"); |
208 | return -ENOMEM; | 218 | return -ENOMEM; |
209 | } | 219 | } |
210 | 220 | ||
211 | priv->dev = &pdev->dev; | 221 | INIT_LIST_HEAD(&common->head); |
212 | mutex_init(&priv->lock); | 222 | common->dev = dev; |
213 | priv->base = devm_ioremap_nocache(&pdev->dev, | 223 | |
214 | res->start, resource_size(res)); | 224 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
215 | if (!priv->base) { | 225 | if (irq) { |
216 | dev_err(&pdev->dev, "Unable to ioremap thermal register\n"); | 226 | /* |
217 | return -ENOMEM; | 227 | * platform has IRQ support. |
228 | * Then, drier use common register | ||
229 | */ | ||
230 | res = platform_get_resource(pdev, IORESOURCE_MEM, mres++); | ||
231 | if (!res) { | ||
232 | dev_err(dev, "Could not get platform resource\n"); | ||
233 | return -ENODEV; | ||
234 | } | ||
235 | |||
236 | /* | ||
237 | * rcar_has_irq_support() will be enabled | ||
238 | */ | ||
239 | common->base = devm_request_and_ioremap(dev, res); | ||
240 | if (!common->base) { | ||
241 | dev_err(dev, "Unable to ioremap thermal register\n"); | ||
242 | return -ENOMEM; | ||
243 | } | ||
218 | } | 244 | } |
219 | 245 | ||
220 | zone = thermal_zone_device_register("rcar_thermal", 1, 0, priv, | 246 | for (i = 0;; i++) { |
221 | &rcar_thermal_zone_ops, NULL, 0, | 247 | res = platform_get_resource(pdev, IORESOURCE_MEM, mres++); |
222 | IDLE_INTERVAL); | 248 | if (!res) |
223 | if (IS_ERR(zone)) { | 249 | break; |
224 | dev_err(&pdev->dev, "thermal zone device is NULL\n"); | 250 | |
225 | return PTR_ERR(zone); | 251 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
252 | if (!priv) { | ||
253 | dev_err(dev, "Could not allocate priv\n"); | ||
254 | return -ENOMEM; | ||
255 | } | ||
256 | |||
257 | priv->base = devm_request_and_ioremap(dev, res); | ||
258 | if (!priv->base) { | ||
259 | dev_err(dev, "Unable to ioremap priv register\n"); | ||
260 | return -ENOMEM; | ||
261 | } | ||
262 | |||
263 | priv->common = common; | ||
264 | mutex_init(&priv->lock); | ||
265 | INIT_LIST_HEAD(&priv->list); | ||
266 | |||
267 | priv->zone = thermal_zone_device_register("rcar_thermal", | ||
268 | 1, 0, priv, | ||
269 | &rcar_thermal_zone_ops, NULL, 0, | ||
270 | IDLE_INTERVAL); | ||
271 | if (IS_ERR(priv->zone)) { | ||
272 | dev_err(dev, "can't register thermal zone\n"); | ||
273 | goto error_unregister; | ||
274 | } | ||
275 | |||
276 | list_move_tail(&priv->list, &common->head); | ||
226 | } | 277 | } |
227 | 278 | ||
228 | platform_set_drvdata(pdev, zone); | 279 | platform_set_drvdata(pdev, common); |
229 | 280 | ||
230 | dev_info(&pdev->dev, "proved\n"); | 281 | dev_info(dev, "%d sensor proved\n", i); |
231 | 282 | ||
232 | return 0; | 283 | return 0; |
284 | |||
285 | error_unregister: | ||
286 | rcar_thermal_for_each_priv(priv, common) | ||
287 | thermal_zone_device_unregister(priv->zone); | ||
288 | |||
289 | return -ENODEV; | ||
233 | } | 290 | } |
234 | 291 | ||
235 | static int rcar_thermal_remove(struct platform_device *pdev) | 292 | static int rcar_thermal_remove(struct platform_device *pdev) |
236 | { | 293 | { |
237 | struct thermal_zone_device *zone = platform_get_drvdata(pdev); | 294 | struct rcar_thermal_common *common = platform_get_drvdata(pdev); |
295 | struct rcar_thermal_priv *priv; | ||
296 | |||
297 | rcar_thermal_for_each_priv(priv, common) | ||
298 | thermal_zone_device_unregister(priv->zone); | ||
238 | 299 | ||
239 | thermal_zone_device_unregister(zone); | ||
240 | platform_set_drvdata(pdev, NULL); | 300 | platform_set_drvdata(pdev, NULL); |
241 | 301 | ||
242 | return 0; | 302 | return 0; |