1 // SPDX-License-Identifier: GPL-2.0
3 * Generic serial GNSS receiver driver
5 * Copyright (C) 2018 Johan Hovold <johan@kernel.org>
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>
15 #include <linux/pm_runtime.h>
16 #include <linux/serdev.h>
17 #include <linux/slab.h>
21 static int gnss_serial_open(struct gnss_device
*gdev
)
23 struct gnss_serial
*gserial
= gnss_get_drvdata(gdev
);
24 struct serdev_device
*serdev
= gserial
->serdev
;
27 ret
= serdev_device_open(serdev
);
31 serdev_device_set_baudrate(serdev
, gserial
->speed
);
32 serdev_device_set_flow_control(serdev
, false);
34 ret
= pm_runtime_get_sync(&serdev
->dev
);
36 pm_runtime_put_noidle(&serdev
->dev
);
43 serdev_device_close(serdev
);
48 static void gnss_serial_close(struct gnss_device
*gdev
)
50 struct gnss_serial
*gserial
= gnss_get_drvdata(gdev
);
51 struct serdev_device
*serdev
= gserial
->serdev
;
53 serdev_device_close(serdev
);
55 pm_runtime_put(&serdev
->dev
);
58 static int gnss_serial_write_raw(struct gnss_device
*gdev
,
59 const unsigned char *buf
, size_t count
)
61 struct gnss_serial
*gserial
= gnss_get_drvdata(gdev
);
62 struct serdev_device
*serdev
= gserial
->serdev
;
65 /* write is only buffered synchronously */
66 ret
= serdev_device_write(serdev
, buf
, count
, 0);
70 /* FIXME: determine if interrupted? */
71 serdev_device_wait_until_sent(serdev
, 0);
76 static const struct gnss_operations gnss_serial_gnss_ops
= {
77 .open
= gnss_serial_open
,
78 .close
= gnss_serial_close
,
79 .write_raw
= gnss_serial_write_raw
,
82 static int gnss_serial_receive_buf(struct serdev_device
*serdev
,
83 const unsigned char *buf
, size_t count
)
85 struct gnss_serial
*gserial
= serdev_device_get_drvdata(serdev
);
86 struct gnss_device
*gdev
= gserial
->gdev
;
88 return gnss_insert_raw(gdev
, buf
, count
);
91 static const struct serdev_device_ops gnss_serial_serdev_ops
= {
92 .receive_buf
= gnss_serial_receive_buf
,
93 .write_wakeup
= serdev_device_write_wakeup
,
96 static int gnss_serial_set_power(struct gnss_serial
*gserial
,
97 enum gnss_serial_pm_state state
)
99 if (!gserial
->ops
|| !gserial
->ops
->set_power
)
102 return gserial
->ops
->set_power(gserial
, state
);
106 * FIXME: need to provide subdriver defaults or separate dt parsing from
109 static int gnss_serial_parse_dt(struct serdev_device
*serdev
)
111 struct gnss_serial
*gserial
= serdev_device_get_drvdata(serdev
);
112 struct device_node
*node
= serdev
->dev
.of_node
;
115 of_property_read_u32(node
, "current-speed", &speed
);
117 gserial
->speed
= speed
;
122 struct gnss_serial
*gnss_serial_allocate(struct serdev_device
*serdev
,
125 struct gnss_serial
*gserial
;
126 struct gnss_device
*gdev
;
129 gserial
= kzalloc(sizeof(*gserial
) + data_size
, GFP_KERNEL
);
131 return ERR_PTR(-ENOMEM
);
133 gdev
= gnss_allocate_device(&serdev
->dev
);
136 goto err_free_gserial
;
139 gdev
->ops
= &gnss_serial_gnss_ops
;
140 gnss_set_drvdata(gdev
, gserial
);
142 gserial
->serdev
= serdev
;
143 gserial
->gdev
= gdev
;
145 serdev_device_set_drvdata(serdev
, gserial
);
146 serdev_device_set_client_ops(serdev
, &gnss_serial_serdev_ops
);
148 ret
= gnss_serial_parse_dt(serdev
);
155 gnss_put_device(gserial
->gdev
);
161 EXPORT_SYMBOL_GPL(gnss_serial_allocate
);
163 void gnss_serial_free(struct gnss_serial
*gserial
)
165 gnss_put_device(gserial
->gdev
);
168 EXPORT_SYMBOL_GPL(gnss_serial_free
);
170 int gnss_serial_register(struct gnss_serial
*gserial
)
172 struct serdev_device
*serdev
= gserial
->serdev
;
175 if (IS_ENABLED(CONFIG_PM
)) {
176 pm_runtime_enable(&serdev
->dev
);
178 ret
= gnss_serial_set_power(gserial
, GNSS_SERIAL_ACTIVE
);
183 ret
= gnss_register_device(gserial
->gdev
);
185 goto err_disable_rpm
;
190 if (IS_ENABLED(CONFIG_PM
))
191 pm_runtime_disable(&serdev
->dev
);
193 gnss_serial_set_power(gserial
, GNSS_SERIAL_OFF
);
197 EXPORT_SYMBOL_GPL(gnss_serial_register
);
199 void gnss_serial_deregister(struct gnss_serial
*gserial
)
201 struct serdev_device
*serdev
= gserial
->serdev
;
203 gnss_deregister_device(gserial
->gdev
);
205 if (IS_ENABLED(CONFIG_PM
))
206 pm_runtime_disable(&serdev
->dev
);
208 gnss_serial_set_power(gserial
, GNSS_SERIAL_OFF
);
210 EXPORT_SYMBOL_GPL(gnss_serial_deregister
);
213 static int gnss_serial_runtime_suspend(struct device
*dev
)
215 struct gnss_serial
*gserial
= dev_get_drvdata(dev
);
217 return gnss_serial_set_power(gserial
, GNSS_SERIAL_STANDBY
);
220 static int gnss_serial_runtime_resume(struct device
*dev
)
222 struct gnss_serial
*gserial
= dev_get_drvdata(dev
);
224 return gnss_serial_set_power(gserial
, GNSS_SERIAL_ACTIVE
);
226 #endif /* CONFIG_PM */
228 static int gnss_serial_prepare(struct device
*dev
)
230 if (pm_runtime_suspended(dev
))
236 #ifdef CONFIG_PM_SLEEP
237 static int gnss_serial_suspend(struct device
*dev
)
239 struct gnss_serial
*gserial
= dev_get_drvdata(dev
);
243 * FIXME: serdev currently lacks support for managing the underlying
244 * device's wakeup settings. A workaround would be to close the serdev
245 * device here if it is open.
248 if (!pm_runtime_suspended(dev
))
249 ret
= gnss_serial_set_power(gserial
, GNSS_SERIAL_STANDBY
);
254 static int gnss_serial_resume(struct device
*dev
)
256 struct gnss_serial
*gserial
= dev_get_drvdata(dev
);
259 if (!pm_runtime_suspended(dev
))
260 ret
= gnss_serial_set_power(gserial
, GNSS_SERIAL_ACTIVE
);
264 #endif /* CONFIG_PM_SLEEP */
266 const struct dev_pm_ops gnss_serial_pm_ops
= {
267 .prepare
= gnss_serial_prepare
,
268 SET_SYSTEM_SLEEP_PM_OPS(gnss_serial_suspend
, gnss_serial_resume
)
269 SET_RUNTIME_PM_OPS(gnss_serial_runtime_suspend
, gnss_serial_runtime_resume
, NULL
)
271 EXPORT_SYMBOL_GPL(gnss_serial_pm_ops
);
273 MODULE_AUTHOR("Johan Hovold <johan@kernel.org>");
274 MODULE_DESCRIPTION("Generic serial GNSS receiver driver");
275 MODULE_LICENSE("GPL v2");