root/drivers/thermal/tegra/tegra-bpmp-thermal.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tegra_bpmp_thermal_get_temp
  2. tegra_bpmp_thermal_set_trips
  3. tz_device_update_work_fn
  4. bpmp_mrq_thermal
  5. tegra_bpmp_thermal_get_num_zones
  6. tegra_bpmp_thermal_probe
  7. tegra_bpmp_thermal_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (c) 2015-2017, NVIDIA CORPORATION.  All rights reserved.
   4  *
   5  * Author:
   6  *      Mikko Perttunen <mperttunen@nvidia.com>
   7  *      Aapo Vienamo    <avienamo@nvidia.com>
   8  */
   9 
  10 #include <linux/err.h>
  11 #include <linux/module.h>
  12 #include <linux/platform_device.h>
  13 #include <linux/thermal.h>
  14 #include <linux/workqueue.h>
  15 
  16 #include <soc/tegra/bpmp.h>
  17 #include <soc/tegra/bpmp-abi.h>
  18 
  19 struct tegra_bpmp_thermal_zone {
  20         struct tegra_bpmp_thermal *tegra;
  21         struct thermal_zone_device *tzd;
  22         struct work_struct tz_device_update_work;
  23         unsigned int idx;
  24 };
  25 
  26 struct tegra_bpmp_thermal {
  27         struct device *dev;
  28         struct tegra_bpmp *bpmp;
  29         unsigned int num_zones;
  30         struct tegra_bpmp_thermal_zone **zones;
  31 };
  32 
  33 static int tegra_bpmp_thermal_get_temp(void *data, int *out_temp)
  34 {
  35         struct tegra_bpmp_thermal_zone *zone = data;
  36         struct mrq_thermal_host_to_bpmp_request req;
  37         union mrq_thermal_bpmp_to_host_response reply;
  38         struct tegra_bpmp_message msg;
  39         int err;
  40 
  41         memset(&req, 0, sizeof(req));
  42         req.type = CMD_THERMAL_GET_TEMP;
  43         req.get_temp.zone = zone->idx;
  44 
  45         memset(&msg, 0, sizeof(msg));
  46         msg.mrq = MRQ_THERMAL;
  47         msg.tx.data = &req;
  48         msg.tx.size = sizeof(req);
  49         msg.rx.data = &reply;
  50         msg.rx.size = sizeof(reply);
  51 
  52         err = tegra_bpmp_transfer(zone->tegra->bpmp, &msg);
  53         if (err)
  54                 return err;
  55 
  56         *out_temp = reply.get_temp.temp;
  57 
  58         return 0;
  59 }
  60 
  61 static int tegra_bpmp_thermal_set_trips(void *data, int low, int high)
  62 {
  63         struct tegra_bpmp_thermal_zone *zone = data;
  64         struct mrq_thermal_host_to_bpmp_request req;
  65         struct tegra_bpmp_message msg;
  66 
  67         memset(&req, 0, sizeof(req));
  68         req.type = CMD_THERMAL_SET_TRIP;
  69         req.set_trip.zone = zone->idx;
  70         req.set_trip.enabled = true;
  71         req.set_trip.low = low;
  72         req.set_trip.high = high;
  73 
  74         memset(&msg, 0, sizeof(msg));
  75         msg.mrq = MRQ_THERMAL;
  76         msg.tx.data = &req;
  77         msg.tx.size = sizeof(req);
  78 
  79         return tegra_bpmp_transfer(zone->tegra->bpmp, &msg);
  80 }
  81 
  82 static void tz_device_update_work_fn(struct work_struct *work)
  83 {
  84         struct tegra_bpmp_thermal_zone *zone;
  85 
  86         zone = container_of(work, struct tegra_bpmp_thermal_zone,
  87                             tz_device_update_work);
  88 
  89         thermal_zone_device_update(zone->tzd, THERMAL_TRIP_VIOLATED);
  90 }
  91 
  92 static void bpmp_mrq_thermal(unsigned int mrq, struct tegra_bpmp_channel *ch,
  93                              void *data)
  94 {
  95         struct mrq_thermal_bpmp_to_host_request *req;
  96         struct tegra_bpmp_thermal *tegra = data;
  97         int i;
  98 
  99         req = (struct mrq_thermal_bpmp_to_host_request *)ch->ib->data;
 100 
 101         if (req->type != CMD_THERMAL_HOST_TRIP_REACHED) {
 102                 dev_err(tegra->dev, "%s: invalid request type: %d\n",
 103                         __func__, req->type);
 104                 tegra_bpmp_mrq_return(ch, -EINVAL, NULL, 0);
 105                 return;
 106         }
 107 
 108         for (i = 0; i < tegra->num_zones; ++i) {
 109                 if (tegra->zones[i]->idx != req->host_trip_reached.zone)
 110                         continue;
 111 
 112                 schedule_work(&tegra->zones[i]->tz_device_update_work);
 113                 tegra_bpmp_mrq_return(ch, 0, NULL, 0);
 114                 return;
 115         }
 116 
 117         dev_err(tegra->dev, "%s: invalid thermal zone: %d\n", __func__,
 118                 req->host_trip_reached.zone);
 119         tegra_bpmp_mrq_return(ch, -EINVAL, NULL, 0);
 120 }
 121 
 122 static int tegra_bpmp_thermal_get_num_zones(struct tegra_bpmp *bpmp,
 123                                             int *num_zones)
 124 {
 125         struct mrq_thermal_host_to_bpmp_request req;
 126         union mrq_thermal_bpmp_to_host_response reply;
 127         struct tegra_bpmp_message msg;
 128         int err;
 129 
 130         memset(&req, 0, sizeof(req));
 131         req.type = CMD_THERMAL_GET_NUM_ZONES;
 132 
 133         memset(&msg, 0, sizeof(msg));
 134         msg.mrq = MRQ_THERMAL;
 135         msg.tx.data = &req;
 136         msg.tx.size = sizeof(req);
 137         msg.rx.data = &reply;
 138         msg.rx.size = sizeof(reply);
 139 
 140         err = tegra_bpmp_transfer(bpmp, &msg);
 141         if (err)
 142                 return err;
 143 
 144         *num_zones = reply.get_num_zones.num;
 145 
 146         return 0;
 147 }
 148 
 149 static const struct thermal_zone_of_device_ops tegra_bpmp_of_thermal_ops = {
 150         .get_temp = tegra_bpmp_thermal_get_temp,
 151         .set_trips = tegra_bpmp_thermal_set_trips,
 152 };
 153 
 154 static int tegra_bpmp_thermal_probe(struct platform_device *pdev)
 155 {
 156         struct tegra_bpmp *bpmp = dev_get_drvdata(pdev->dev.parent);
 157         struct tegra_bpmp_thermal *tegra;
 158         struct thermal_zone_device *tzd;
 159         unsigned int i, max_num_zones;
 160         int err;
 161 
 162         tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
 163         if (!tegra)
 164                 return -ENOMEM;
 165 
 166         tegra->dev = &pdev->dev;
 167         tegra->bpmp = bpmp;
 168 
 169         err = tegra_bpmp_thermal_get_num_zones(bpmp, &max_num_zones);
 170         if (err) {
 171                 dev_err(&pdev->dev, "failed to get the number of zones: %d\n",
 172                         err);
 173                 return err;
 174         }
 175 
 176         tegra->zones = devm_kcalloc(&pdev->dev, max_num_zones,
 177                                     sizeof(*tegra->zones), GFP_KERNEL);
 178         if (!tegra->zones)
 179                 return -ENOMEM;
 180 
 181         for (i = 0; i < max_num_zones; ++i) {
 182                 struct tegra_bpmp_thermal_zone *zone;
 183                 int temp;
 184 
 185                 zone = devm_kzalloc(&pdev->dev, sizeof(*zone), GFP_KERNEL);
 186                 if (!zone)
 187                         return -ENOMEM;
 188 
 189                 zone->idx = i;
 190                 zone->tegra = tegra;
 191 
 192                 err = tegra_bpmp_thermal_get_temp(zone, &temp);
 193                 if (err < 0) {
 194                         devm_kfree(&pdev->dev, zone);
 195                         continue;
 196                 }
 197 
 198                 tzd = devm_thermal_zone_of_sensor_register(
 199                         &pdev->dev, i, zone, &tegra_bpmp_of_thermal_ops);
 200                 if (IS_ERR(tzd)) {
 201                         if (PTR_ERR(tzd) == -EPROBE_DEFER)
 202                                 return -EPROBE_DEFER;
 203                         devm_kfree(&pdev->dev, zone);
 204                         continue;
 205                 }
 206 
 207                 zone->tzd = tzd;
 208                 INIT_WORK(&zone->tz_device_update_work,
 209                           tz_device_update_work_fn);
 210 
 211                 tegra->zones[tegra->num_zones++] = zone;
 212         }
 213 
 214         err = tegra_bpmp_request_mrq(bpmp, MRQ_THERMAL, bpmp_mrq_thermal,
 215                                      tegra);
 216         if (err) {
 217                 dev_err(&pdev->dev, "failed to register mrq handler: %d\n",
 218                         err);
 219                 return err;
 220         }
 221 
 222         platform_set_drvdata(pdev, tegra);
 223 
 224         return 0;
 225 }
 226 
 227 static int tegra_bpmp_thermal_remove(struct platform_device *pdev)
 228 {
 229         struct tegra_bpmp_thermal *tegra = platform_get_drvdata(pdev);
 230 
 231         tegra_bpmp_free_mrq(tegra->bpmp, MRQ_THERMAL, tegra);
 232 
 233         return 0;
 234 }
 235 
 236 static const struct of_device_id tegra_bpmp_thermal_of_match[] = {
 237         { .compatible = "nvidia,tegra186-bpmp-thermal" },
 238         { },
 239 };
 240 MODULE_DEVICE_TABLE(of, tegra_bpmp_thermal_of_match);
 241 
 242 static struct platform_driver tegra_bpmp_thermal_driver = {
 243         .probe = tegra_bpmp_thermal_probe,
 244         .remove = tegra_bpmp_thermal_remove,
 245         .driver = {
 246                 .name = "tegra-bpmp-thermal",
 247                 .of_match_table = tegra_bpmp_thermal_of_match,
 248         },
 249 };
 250 module_platform_driver(tegra_bpmp_thermal_driver);
 251 
 252 MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");
 253 MODULE_DESCRIPTION("NVIDIA Tegra BPMP thermal sensor driver");
 254 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */