2018-06-01 11:22:56 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* u - blox GNSS receiver driver
*
* Copyright ( C ) 2018 Johan Hovold < johan @ kernel . org >
*/
# include <linux/errno.h>
# include <linux/gnss.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/regulator/consumer.h>
# include <linux/serdev.h>
# include "serial.h"
struct ubx_data {
struct regulator * v_bckp ;
struct regulator * vcc ;
} ;
static int ubx_set_active ( struct gnss_serial * gserial )
{
struct ubx_data * data = gnss_serial_get_drvdata ( gserial ) ;
int ret ;
ret = regulator_enable ( data - > vcc ) ;
if ( ret )
return ret ;
return 0 ;
}
static int ubx_set_standby ( struct gnss_serial * gserial )
{
struct ubx_data * data = gnss_serial_get_drvdata ( gserial ) ;
int ret ;
ret = regulator_disable ( data - > vcc ) ;
if ( ret )
return ret ;
return 0 ;
}
static int ubx_set_power ( struct gnss_serial * gserial ,
enum gnss_serial_pm_state state )
{
switch ( state ) {
case GNSS_SERIAL_ACTIVE :
return ubx_set_active ( gserial ) ;
case GNSS_SERIAL_OFF :
case GNSS_SERIAL_STANDBY :
return ubx_set_standby ( gserial ) ;
}
return - EINVAL ;
}
2018-07-16 13:42:02 +03:00
static const struct gnss_serial_ops ubx_gserial_ops = {
2018-06-01 11:22:56 +03:00
. set_power = ubx_set_power ,
} ;
static int ubx_probe ( struct serdev_device * serdev )
{
struct gnss_serial * gserial ;
struct ubx_data * data ;
int ret ;
gserial = gnss_serial_allocate ( serdev , sizeof ( * data ) ) ;
if ( IS_ERR ( gserial ) ) {
ret = PTR_ERR ( gserial ) ;
return ret ;
}
gserial - > ops = & ubx_gserial_ops ;
2018-06-01 11:22:59 +03:00
gserial - > gdev - > type = GNSS_TYPE_UBX ;
2018-06-01 11:22:56 +03:00
data = gnss_serial_get_drvdata ( gserial ) ;
data - > vcc = devm_regulator_get ( & serdev - > dev , " vcc " ) ;
if ( IS_ERR ( data - > vcc ) ) {
ret = PTR_ERR ( data - > vcc ) ;
goto err_free_gserial ;
}
data - > v_bckp = devm_regulator_get_optional ( & serdev - > dev , " v-bckp " ) ;
if ( IS_ERR ( data - > v_bckp ) ) {
ret = PTR_ERR ( data - > v_bckp ) ;
if ( ret = = - ENODEV )
data - > v_bckp = NULL ;
else
goto err_free_gserial ;
}
if ( data - > v_bckp ) {
ret = regulator_enable ( data - > v_bckp ) ;
if ( ret )
goto err_free_gserial ;
}
ret = gnss_serial_register ( gserial ) ;
if ( ret )
goto err_disable_v_bckp ;
return 0 ;
err_disable_v_bckp :
if ( data - > v_bckp )
regulator_disable ( data - > v_bckp ) ;
err_free_gserial :
gnss_serial_free ( gserial ) ;
return ret ;
}
static void ubx_remove ( struct serdev_device * serdev )
{
struct gnss_serial * gserial = serdev_device_get_drvdata ( serdev ) ;
struct ubx_data * data = gnss_serial_get_drvdata ( gserial ) ;
gnss_serial_deregister ( gserial ) ;
if ( data - > v_bckp )
regulator_disable ( data - > v_bckp ) ;
gnss_serial_free ( gserial ) ;
} ;
# ifdef CONFIG_OF
static const struct of_device_id ubx_of_match [ ] = {
{ . compatible = " u-blox,neo-8 " } ,
{ . compatible = " u-blox,neo-m8 " } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , ubx_of_match ) ;
# endif
static struct serdev_device_driver ubx_driver = {
. driver = {
. name = " gnss-ubx " ,
. of_match_table = of_match_ptr ( ubx_of_match ) ,
. pm = & gnss_serial_pm_ops ,
} ,
. probe = ubx_probe ,
. remove = ubx_remove ,
} ;
module_serdev_device_driver ( ubx_driver ) ;
MODULE_AUTHOR ( " Johan Hovold <johan@kernel.org> " ) ;
MODULE_DESCRIPTION ( " u-blox GNSS receiver driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;