root/drivers/gnss/serial.c

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

DEFINITIONS

This source file includes following definitions.
  1. gnss_serial_open
  2. gnss_serial_close
  3. gnss_serial_write_raw
  4. gnss_serial_receive_buf
  5. gnss_serial_set_power
  6. gnss_serial_parse_dt
  7. gnss_serial_allocate
  8. gnss_serial_free
  9. gnss_serial_register
  10. gnss_serial_deregister
  11. gnss_serial_runtime_suspend
  12. gnss_serial_runtime_resume
  13. gnss_serial_prepare
  14. gnss_serial_suspend
  15. gnss_serial_resume

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Generic serial GNSS receiver driver
   4  *
   5  * Copyright (C) 2018 Johan Hovold <johan@kernel.org>
   6  */
   7 
   8 #include <linux/errno.h>
   9 #include <linux/gnss.h>
  10 #include <linux/init.h>
  11 #include <linux/kernel.h>
  12 #include <linux/module.h>
  13 #include <linux/of.h>
  14 #include <linux/pm.h>
  15 #include <linux/pm_runtime.h>
  16 #include <linux/sched.h>
  17 #include <linux/serdev.h>
  18 #include <linux/slab.h>
  19 
  20 #include "serial.h"
  21 
  22 static int gnss_serial_open(struct gnss_device *gdev)
  23 {
  24         struct gnss_serial *gserial = gnss_get_drvdata(gdev);
  25         struct serdev_device *serdev = gserial->serdev;
  26         int ret;
  27 
  28         ret = serdev_device_open(serdev);
  29         if (ret)
  30                 return ret;
  31 
  32         serdev_device_set_baudrate(serdev, gserial->speed);
  33         serdev_device_set_flow_control(serdev, false);
  34 
  35         ret = pm_runtime_get_sync(&serdev->dev);
  36         if (ret < 0) {
  37                 pm_runtime_put_noidle(&serdev->dev);
  38                 goto err_close;
  39         }
  40 
  41         return 0;
  42 
  43 err_close:
  44         serdev_device_close(serdev);
  45 
  46         return ret;
  47 }
  48 
  49 static void gnss_serial_close(struct gnss_device *gdev)
  50 {
  51         struct gnss_serial *gserial = gnss_get_drvdata(gdev);
  52         struct serdev_device *serdev = gserial->serdev;
  53 
  54         serdev_device_close(serdev);
  55 
  56         pm_runtime_put(&serdev->dev);
  57 }
  58 
  59 static int gnss_serial_write_raw(struct gnss_device *gdev,
  60                 const unsigned char *buf, size_t count)
  61 {
  62         struct gnss_serial *gserial = gnss_get_drvdata(gdev);
  63         struct serdev_device *serdev = gserial->serdev;
  64         int ret;
  65 
  66         /* write is only buffered synchronously */
  67         ret = serdev_device_write(serdev, buf, count, MAX_SCHEDULE_TIMEOUT);
  68         if (ret < 0 || ret < count)
  69                 return ret;
  70 
  71         /* FIXME: determine if interrupted? */
  72         serdev_device_wait_until_sent(serdev, 0);
  73 
  74         return count;
  75 }
  76 
  77 static const struct gnss_operations gnss_serial_gnss_ops = {
  78         .open           = gnss_serial_open,
  79         .close          = gnss_serial_close,
  80         .write_raw      = gnss_serial_write_raw,
  81 };
  82 
  83 static int gnss_serial_receive_buf(struct serdev_device *serdev,
  84                                         const unsigned char *buf, size_t count)
  85 {
  86         struct gnss_serial *gserial = serdev_device_get_drvdata(serdev);
  87         struct gnss_device *gdev = gserial->gdev;
  88 
  89         return gnss_insert_raw(gdev, buf, count);
  90 }
  91 
  92 static const struct serdev_device_ops gnss_serial_serdev_ops = {
  93         .receive_buf    = gnss_serial_receive_buf,
  94         .write_wakeup   = serdev_device_write_wakeup,
  95 };
  96 
  97 static int gnss_serial_set_power(struct gnss_serial *gserial,
  98                                         enum gnss_serial_pm_state state)
  99 {
 100         if (!gserial->ops || !gserial->ops->set_power)
 101                 return 0;
 102 
 103         return gserial->ops->set_power(gserial, state);
 104 }
 105 
 106 /*
 107  * FIXME: need to provide subdriver defaults or separate dt parsing from
 108  * allocation.
 109  */
 110 static int gnss_serial_parse_dt(struct serdev_device *serdev)
 111 {
 112         struct gnss_serial *gserial = serdev_device_get_drvdata(serdev);
 113         struct device_node *node = serdev->dev.of_node;
 114         u32 speed = 4800;
 115 
 116         of_property_read_u32(node, "current-speed", &speed);
 117 
 118         gserial->speed = speed;
 119 
 120         return 0;
 121 }
 122 
 123 struct gnss_serial *gnss_serial_allocate(struct serdev_device *serdev,
 124                                                 size_t data_size)
 125 {
 126         struct gnss_serial *gserial;
 127         struct gnss_device *gdev;
 128         int ret;
 129 
 130         gserial = kzalloc(sizeof(*gserial) + data_size, GFP_KERNEL);
 131         if (!gserial)
 132                 return ERR_PTR(-ENOMEM);
 133 
 134         gdev = gnss_allocate_device(&serdev->dev);
 135         if (!gdev) {
 136                 ret = -ENOMEM;
 137                 goto err_free_gserial;
 138         }
 139 
 140         gdev->ops = &gnss_serial_gnss_ops;
 141         gnss_set_drvdata(gdev, gserial);
 142 
 143         gserial->serdev = serdev;
 144         gserial->gdev = gdev;
 145 
 146         serdev_device_set_drvdata(serdev, gserial);
 147         serdev_device_set_client_ops(serdev, &gnss_serial_serdev_ops);
 148 
 149         ret = gnss_serial_parse_dt(serdev);
 150         if (ret)
 151                 goto err_put_device;
 152 
 153         return gserial;
 154 
 155 err_put_device:
 156         gnss_put_device(gserial->gdev);
 157 err_free_gserial:
 158         kfree(gserial);
 159 
 160         return ERR_PTR(ret);
 161 }
 162 EXPORT_SYMBOL_GPL(gnss_serial_allocate);
 163 
 164 void gnss_serial_free(struct gnss_serial *gserial)
 165 {
 166         gnss_put_device(gserial->gdev);
 167         kfree(gserial);
 168 };
 169 EXPORT_SYMBOL_GPL(gnss_serial_free);
 170 
 171 int gnss_serial_register(struct gnss_serial *gserial)
 172 {
 173         struct serdev_device *serdev = gserial->serdev;
 174         int ret;
 175 
 176         if (IS_ENABLED(CONFIG_PM)) {
 177                 pm_runtime_enable(&serdev->dev);
 178         } else {
 179                 ret = gnss_serial_set_power(gserial, GNSS_SERIAL_ACTIVE);
 180                 if (ret < 0)
 181                         return ret;
 182         }
 183 
 184         ret = gnss_register_device(gserial->gdev);
 185         if (ret)
 186                 goto err_disable_rpm;
 187 
 188         return 0;
 189 
 190 err_disable_rpm:
 191         if (IS_ENABLED(CONFIG_PM))
 192                 pm_runtime_disable(&serdev->dev);
 193         else
 194                 gnss_serial_set_power(gserial, GNSS_SERIAL_OFF);
 195 
 196         return ret;
 197 }
 198 EXPORT_SYMBOL_GPL(gnss_serial_register);
 199 
 200 void gnss_serial_deregister(struct gnss_serial *gserial)
 201 {
 202         struct serdev_device *serdev = gserial->serdev;
 203 
 204         gnss_deregister_device(gserial->gdev);
 205 
 206         if (IS_ENABLED(CONFIG_PM))
 207                 pm_runtime_disable(&serdev->dev);
 208         else
 209                 gnss_serial_set_power(gserial, GNSS_SERIAL_OFF);
 210 }
 211 EXPORT_SYMBOL_GPL(gnss_serial_deregister);
 212 
 213 #ifdef CONFIG_PM
 214 static int gnss_serial_runtime_suspend(struct device *dev)
 215 {
 216         struct gnss_serial *gserial = dev_get_drvdata(dev);
 217 
 218         return gnss_serial_set_power(gserial, GNSS_SERIAL_STANDBY);
 219 }
 220 
 221 static int gnss_serial_runtime_resume(struct device *dev)
 222 {
 223         struct gnss_serial *gserial = dev_get_drvdata(dev);
 224 
 225         return gnss_serial_set_power(gserial, GNSS_SERIAL_ACTIVE);
 226 }
 227 #endif /* CONFIG_PM */
 228 
 229 static int gnss_serial_prepare(struct device *dev)
 230 {
 231         if (pm_runtime_suspended(dev))
 232                 return 1;
 233 
 234         return 0;
 235 }
 236 
 237 #ifdef CONFIG_PM_SLEEP
 238 static int gnss_serial_suspend(struct device *dev)
 239 {
 240         struct gnss_serial *gserial = dev_get_drvdata(dev);
 241         int ret = 0;
 242 
 243         /*
 244          * FIXME: serdev currently lacks support for managing the underlying
 245          * device's wakeup settings. A workaround would be to close the serdev
 246          * device here if it is open.
 247          */
 248 
 249         if (!pm_runtime_suspended(dev))
 250                 ret = gnss_serial_set_power(gserial, GNSS_SERIAL_STANDBY);
 251 
 252         return ret;
 253 }
 254 
 255 static int gnss_serial_resume(struct device *dev)
 256 {
 257         struct gnss_serial *gserial = dev_get_drvdata(dev);
 258         int ret = 0;
 259 
 260         if (!pm_runtime_suspended(dev))
 261                 ret = gnss_serial_set_power(gserial, GNSS_SERIAL_ACTIVE);
 262 
 263         return ret;
 264 }
 265 #endif /* CONFIG_PM_SLEEP */
 266 
 267 const struct dev_pm_ops gnss_serial_pm_ops = {
 268         .prepare        = gnss_serial_prepare,
 269         SET_SYSTEM_SLEEP_PM_OPS(gnss_serial_suspend, gnss_serial_resume)
 270         SET_RUNTIME_PM_OPS(gnss_serial_runtime_suspend, gnss_serial_runtime_resume, NULL)
 271 };
 272 EXPORT_SYMBOL_GPL(gnss_serial_pm_ops);
 273 
 274 MODULE_AUTHOR("Johan Hovold <johan@kernel.org>");
 275 MODULE_DESCRIPTION("Generic serial GNSS receiver driver");
 276 MODULE_LICENSE("GPL v2");

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