summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2013-01-31 09:03:33 +0000
committerZhang Rui <rui.zhang@intel.com>2013-02-06 14:13:58 +0800
commit3676d1dd3d3069ca70b8075c0e86482cbaa01c2f (patch)
tree425b072f4e6122da75182681005accb6e9243ee0
parentb2bbc6a2ace78eaca2f6482b58b984519aa783ac (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>
-rw-r--r--drivers/thermal/rcar_thermal.c128
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 @@
/* THSSR */
#define CTEMP 0x3f
+struct rcar_thermal_common {
+ void __iomem *base;
+ struct device *dev;
+ struct list_head head;
+};
struct rcar_thermal_priv {
void __iomem *base;
- struct device *dev;
+ struct rcar_thermal_common *common;
+ struct thermal_zone_device *zone;
struct mutex lock;
+ struct list_head list;
};
+#define rcar_thermal_for_each_priv(pos, common) \
+ list_for_each_entry(pos, &common->head, list)
+
#define MCELSIUS(temp) ((temp) * 1000)
#define rcar_zone_to_priv(zone) ((zone)->devdata)
-#define rcar_priv_to_dev(priv) ((priv)->dev)
+#define rcar_priv_to_dev(priv) ((priv)->common->dev)
+#define rcar_has_irq_support(priv) ((priv)->common->base)
/*
* basic functions
@@ -129,6 +140,7 @@ static int rcar_thermal_get_trip_type(struct thermal_zone_device *zone,
int trip, enum thermal_trip_type *type)
{
struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
+ struct device *dev = rcar_priv_to_dev(priv);
/* see rcar_thermal_get_temp() */
switch (trip) {
@@ -136,7 +148,7 @@ static int rcar_thermal_get_trip_type(struct thermal_zone_device *zone,
*type = THERMAL_TRIP_CRITICAL;
break;
default:
- dev_err(priv->dev, "rcar driver trip error\n");
+ dev_err(dev, "rcar driver trip error\n");
return -EINVAL;
}
@@ -147,6 +159,7 @@ static int rcar_thermal_get_trip_temp(struct thermal_zone_device *zone,
int trip, unsigned long *temp)
{
struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
+ struct device *dev = rcar_priv_to_dev(priv);
/* see rcar_thermal_get_temp() */
switch (trip) {
@@ -154,7 +167,7 @@ static int rcar_thermal_get_trip_temp(struct thermal_zone_device *zone,
*temp = MCELSIUS(90);
break;
default:
- dev_err(priv->dev, "rcar driver trip error\n");
+ dev_err(dev, "rcar driver trip error\n");
return -EINVAL;
}
@@ -165,12 +178,12 @@ static int rcar_thermal_notify(struct thermal_zone_device *zone,
int trip, enum thermal_trip_type type)
{
struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
+ struct device *dev = rcar_priv_to_dev(priv);
switch (type) {
case THERMAL_TRIP_CRITICAL:
/* FIXME */
- dev_warn(priv->dev,
- "Thermal reached to critical temperature\n");
+ dev_warn(dev, "Thermal reached to critical temperature\n");
machine_power_off();
break;
default:
@@ -192,51 +205,98 @@ static struct thermal_zone_device_ops rcar_thermal_zone_ops = {
*/
static int rcar_thermal_probe(struct platform_device *pdev)
{
- struct thermal_zone_device *zone;
+ struct rcar_thermal_common *common;
struct rcar_thermal_priv *priv;
- struct resource *res;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Could not get platform resource\n");
- return -ENODEV;
- }
+ struct device *dev = &pdev->dev;
+ struct resource *res, *irq;
+ int mres = 0;
+ int i;
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- dev_err(&pdev->dev, "Could not allocate priv\n");
+ common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL);
+ if (!common) {
+ dev_err(dev, "Could not allocate common\n");
return -ENOMEM;
}
- priv->dev = &pdev->dev;
- mutex_init(&priv->lock);
- priv->base = devm_ioremap_nocache(&pdev->dev,
- res->start, resource_size(res));
- if (!priv->base) {
- dev_err(&pdev->dev, "Unable to ioremap thermal register\n");
- return -ENOMEM;
+ INIT_LIST_HEAD(&common->head);
+ common->dev = dev;
+
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (irq) {
+ /*
+ * platform has IRQ support.
+ * Then, drier use common register
+ */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
+ if (!res) {
+ dev_err(dev, "Could not get platform resource\n");
+ return -ENODEV;
+ }
+
+ /*
+ * rcar_has_irq_support() will be enabled
+ */
+ common->base = devm_request_and_ioremap(dev, res);
+ if (!common->base) {
+ dev_err(dev, "Unable to ioremap thermal register\n");
+ return -ENOMEM;
+ }
}
- zone = thermal_zone_device_register("rcar_thermal", 1, 0, priv,
- &rcar_thermal_zone_ops, NULL, 0,
- IDLE_INTERVAL);
- if (IS_ERR(zone)) {
- dev_err(&pdev->dev, "thermal zone device is NULL\n");
- return PTR_ERR(zone);
+ for (i = 0;; i++) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
+ if (!res)
+ break;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(dev, "Could not allocate priv\n");
+ return -ENOMEM;
+ }
+
+ priv->base = devm_request_and_ioremap(dev, res);
+ if (!priv->base) {
+ dev_err(dev, "Unable to ioremap priv register\n");
+ return -ENOMEM;
+ }
+
+ priv->common = common;
+ mutex_init(&priv->lock);
+ INIT_LIST_HEAD(&priv->list);
+
+ priv->zone = thermal_zone_device_register("rcar_thermal",
+ 1, 0, priv,
+ &rcar_thermal_zone_ops, NULL, 0,
+ IDLE_INTERVAL);
+ if (IS_ERR(priv->zone)) {
+ dev_err(dev, "can't register thermal zone\n");
+ goto error_unregister;
+ }
+
+ list_move_tail(&priv->list, &common->head);
}
- platform_set_drvdata(pdev, zone);
+ platform_set_drvdata(pdev, common);
- dev_info(&pdev->dev, "proved\n");
+ dev_info(dev, "%d sensor proved\n", i);
return 0;
+
+error_unregister:
+ rcar_thermal_for_each_priv(priv, common)
+ thermal_zone_device_unregister(priv->zone);
+
+ return -ENODEV;
}
static int rcar_thermal_remove(struct platform_device *pdev)
{
- struct thermal_zone_device *zone = platform_get_drvdata(pdev);
+ struct rcar_thermal_common *common = platform_get_drvdata(pdev);
+ struct rcar_thermal_priv *priv;
+
+ rcar_thermal_for_each_priv(priv, common)
+ thermal_zone_device_unregister(priv->zone);
- thermal_zone_device_unregister(zone);
platform_set_drvdata(pdev, NULL);
return 0;