2016-02-12 13:44:44 +02:00
/*
* Copyright ( C ) 2012 Invensense , Inc .
*
* This software is licensed under the terms of the GNU General Public
* License version 2 , as published by the Free Software Foundation , and
* may be copied , distributed , and modified under those terms .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/acpi.h>
# include <linux/delay.h>
# include <linux/err.h>
# include <linux/i2c.h>
# include <linux/iio/iio.h>
# include <linux/module.h>
2017-03-15 01:44:56 -03:00
# include <linux/of_device.h>
2016-02-12 13:44:44 +02:00
# include "inv_mpu_iio.h"
static const struct regmap_config inv_mpu_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
} ;
2016-04-20 08:40:49 +02:00
static int inv_mpu6050_select_bypass ( struct i2c_mux_core * muxc , u32 chan_id )
2016-02-12 13:44:44 +02:00
{
2016-05-04 22:15:31 +02:00
struct iio_dev * indio_dev = i2c_mux_priv ( muxc ) ;
2016-02-12 13:44:44 +02:00
struct inv_mpu6050_state * st = iio_priv ( indio_dev ) ;
int ret = 0 ;
/* Use the same mutex which was used everywhere to protect power-op */
2017-06-07 13:41:42 +00:00
mutex_lock ( & st - > lock ) ;
2016-02-12 13:44:44 +02:00
if ( ! st - > powerup_count ) {
2016-05-04 22:15:31 +02:00
ret = regmap_write ( st - > map , st - > reg - > pwr_mgmt_1 , 0 ) ;
2016-02-12 13:44:44 +02:00
if ( ret )
goto write_error ;
2016-02-22 13:39:08 -08:00
usleep_range ( INV_MPU6050_REG_UP_TIME_MIN ,
INV_MPU6050_REG_UP_TIME_MAX ) ;
2016-02-12 13:44:44 +02:00
}
if ( ! ret ) {
st - > powerup_count + + ;
2016-05-04 22:15:31 +02:00
ret = regmap_write ( st - > map , st - > reg - > int_pin_cfg ,
INV_MPU6050_INT_PIN_CFG |
INV_MPU6050_BIT_BYPASS_EN ) ;
2016-02-12 13:44:44 +02:00
}
write_error :
2017-06-07 13:41:42 +00:00
mutex_unlock ( & st - > lock ) ;
2016-02-12 13:44:44 +02:00
return ret ;
}
2016-04-20 08:40:49 +02:00
static int inv_mpu6050_deselect_bypass ( struct i2c_mux_core * muxc , u32 chan_id )
2016-02-12 13:44:44 +02:00
{
2016-05-04 22:15:31 +02:00
struct iio_dev * indio_dev = i2c_mux_priv ( muxc ) ;
2016-02-12 13:44:44 +02:00
struct inv_mpu6050_state * st = iio_priv ( indio_dev ) ;
2017-06-07 13:41:42 +00:00
mutex_lock ( & st - > lock ) ;
2016-02-12 13:44:44 +02:00
/* It doesn't really mattter, if any of the calls fails */
2016-05-04 22:15:31 +02:00
regmap_write ( st - > map , st - > reg - > int_pin_cfg , INV_MPU6050_INT_PIN_CFG ) ;
2016-02-12 13:44:44 +02:00
st - > powerup_count - - ;
if ( ! st - > powerup_count )
2016-05-04 22:15:31 +02:00
regmap_write ( st - > map , st - > reg - > pwr_mgmt_1 ,
INV_MPU6050_BIT_SLEEP ) ;
2017-06-07 13:41:42 +00:00
mutex_unlock ( & st - > lock ) ;
2016-02-12 13:44:44 +02:00
return 0 ;
}
2017-03-15 01:44:56 -03:00
static const char * inv_mpu_match_acpi_device ( struct device * dev ,
enum inv_devices * chip_id )
2016-03-17 18:32:44 +02:00
{
const struct acpi_device_id * id ;
id = acpi_match_device ( dev - > driver - > acpi_match_table , dev ) ;
if ( ! id )
return NULL ;
* chip_id = ( int ) id - > driver_data ;
return dev_name ( dev ) ;
}
2016-02-12 13:44:44 +02:00
/**
* inv_mpu_probe ( ) - probe function .
* @ client : i2c client .
* @ id : i2c device id .
*
* Returns 0 on success , a negative error code otherwise .
*/
static int inv_mpu_probe ( struct i2c_client * client ,
2016-02-18 17:53:12 +02:00
const struct i2c_device_id * id )
2016-02-12 13:44:44 +02:00
{
struct inv_mpu6050_state * st ;
2017-03-15 01:44:56 -03:00
int result ;
enum inv_devices chip_type ;
2016-02-12 13:44:44 +02:00
struct regmap * regmap ;
2016-03-17 18:32:44 +02:00
const char * name ;
2016-02-12 13:44:44 +02:00
if ( ! i2c_check_functionality ( client - > adapter ,
I2C_FUNC_SMBUS_I2C_BLOCK ) )
2016-02-26 22:13:49 -08:00
return - EOPNOTSUPP ;
2016-02-12 13:44:44 +02:00
2017-03-15 01:44:56 -03:00
if ( client - > dev . of_node ) {
chip_type = ( enum inv_devices )
of_device_get_match_data ( & client - > dev ) ;
name = client - > name ;
} else if ( id ) {
chip_type = ( enum inv_devices )
id - > driver_data ;
2016-03-17 18:32:44 +02:00
name = id - > name ;
} else if ( ACPI_HANDLE ( & client - > dev ) ) {
name = inv_mpu_match_acpi_device ( & client - > dev , & chip_type ) ;
if ( ! name )
return - ENODEV ;
} else {
return - ENOSYS ;
}
2016-02-12 13:44:44 +02:00
regmap = devm_regmap_init_i2c ( client , & inv_mpu_regmap_config ) ;
if ( IS_ERR ( regmap ) ) {
dev_err ( & client - > dev , " Failed to register i2c regmap %d \n " ,
( int ) PTR_ERR ( regmap ) ) ;
return PTR_ERR ( regmap ) ;
}
2016-02-22 13:39:11 -08:00
result = inv_mpu_core_probe ( regmap , client - > irq , name ,
2016-03-02 19:18:12 -08:00
NULL , chip_type ) ;
2016-02-12 13:44:44 +02:00
if ( result < 0 )
return result ;
st = iio_priv ( dev_get_drvdata ( & client - > dev ) ) ;
2016-04-20 08:40:49 +02:00
st - > muxc = i2c_mux_alloc ( client - > adapter , & client - > dev ,
2016-08-31 10:02:40 +02:00
1 , 0 , I2C_MUX_LOCKED | I2C_MUX_GATE ,
2016-04-20 08:40:49 +02:00
inv_mpu6050_select_bypass ,
inv_mpu6050_deselect_bypass ) ;
if ( ! st - > muxc ) {
result = - ENOMEM ;
2016-02-12 13:44:44 +02:00
goto out_unreg_device ;
}
2016-04-20 08:40:49 +02:00
st - > muxc - > priv = dev_get_drvdata ( & client - > dev ) ;
result = i2c_mux_add_adapter ( st - > muxc , 0 , 0 , 0 ) ;
if ( result )
goto out_unreg_device ;
2016-02-12 13:44:44 +02:00
result = inv_mpu_acpi_create_mux_client ( client ) ;
if ( result )
goto out_del_mux ;
return 0 ;
out_del_mux :
2016-04-20 08:40:49 +02:00
i2c_mux_del_adapters ( st - > muxc ) ;
2016-02-12 13:44:44 +02:00
out_unreg_device :
inv_mpu_core_remove ( & client - > dev ) ;
return result ;
}
static int inv_mpu_remove ( struct i2c_client * client )
{
struct iio_dev * indio_dev = i2c_get_clientdata ( client ) ;
struct inv_mpu6050_state * st = iio_priv ( indio_dev ) ;
inv_mpu_acpi_delete_mux_client ( client ) ;
2016-04-20 08:40:49 +02:00
i2c_mux_del_adapters ( st - > muxc ) ;
2016-02-12 13:44:44 +02:00
return inv_mpu_core_remove ( & client - > dev ) ;
}
/*
* device id table is used to identify what device can be
* supported by this driver
*/
static const struct i2c_device_id inv_mpu_id [ ] = {
{ " mpu6050 " , INV_MPU6050 } ,
{ " mpu6500 " , INV_MPU6500 } ,
2016-04-20 16:15:13 +03:00
{ " mpu9150 " , INV_MPU9150 } ,
2017-03-26 12:11:00 +01:00
{ " mpu9250 " , INV_MPU9250 } ,
2016-06-30 19:06:34 +02:00
{ " icm20608 " , INV_ICM20608 } ,
2016-02-12 13:44:44 +02:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , inv_mpu_id ) ;
2017-03-15 01:44:56 -03:00
static const struct of_device_id inv_of_match [ ] = {
{
. compatible = " invensense,mpu6050 " ,
. data = ( void * ) INV_MPU6050
} ,
{
. compatible = " invensense,mpu6500 " ,
. data = ( void * ) INV_MPU6500
} ,
{
. compatible = " invensense,mpu9150 " ,
. data = ( void * ) INV_MPU9150
} ,
2017-03-26 12:11:00 +01:00
{
. compatible = " invensense,mpu9250 " ,
. data = ( void * ) INV_MPU9250
} ,
2017-03-15 01:44:56 -03:00
{
. compatible = " invensense,icm20608 " ,
. data = ( void * ) INV_ICM20608
} ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , inv_of_match ) ;
2016-02-12 13:44:44 +02:00
static const struct acpi_device_id inv_acpi_match [ ] = {
2016-04-20 16:15:09 +03:00
{ " INVN6500 " , INV_MPU6500 } ,
2016-02-12 13:44:44 +02:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( acpi , inv_acpi_match ) ;
static struct i2c_driver inv_mpu_driver = {
. probe = inv_mpu_probe ,
. remove = inv_mpu_remove ,
. id_table = inv_mpu_id ,
. driver = {
2017-03-15 01:44:56 -03:00
. of_match_table = inv_of_match ,
2016-02-12 13:44:44 +02:00
. acpi_match_table = ACPI_PTR ( inv_acpi_match ) ,
. name = " inv-mpu6050-i2c " ,
. pm = & inv_mpu_pmops ,
} ,
} ;
module_i2c_driver ( inv_mpu_driver ) ;
MODULE_AUTHOR ( " Invensense Corporation " ) ;
MODULE_DESCRIPTION ( " Invensense device MPU6050 driver " ) ;
MODULE_LICENSE ( " GPL " ) ;