2018-07-26 17:05:10 +05:30
// SPDX-License-Identifier: GPL-2.0
/*
* BME680 - SPI Driver
*
* Copyright ( C ) 2018 Himanshu Jha < himanshujha199640 @ gmail . com >
*/
# include <linux/acpi.h>
# include <linux/module.h>
2019-01-14 15:19:13 -05:00
# include <linux/of.h>
2018-07-26 17:05:10 +05:30
# include <linux/regmap.h>
# include <linux/spi/spi.h>
# include "bme680.h"
2019-03-06 08:31:48 +01:00
struct bme680_spi_bus_context {
struct spi_device * spi ;
u8 current_page ;
} ;
/*
* In SPI mode there are only 7 address bits , a " page " register determines
* which part of the 8 - bit range is active . This function looks at the address
* and writes the page selection bit if needed
*/
static int bme680_regmap_spi_select_page (
struct bme680_spi_bus_context * ctx , u8 reg )
{
struct spi_device * spi = ctx - > spi ;
int ret ;
u8 buf [ 2 ] ;
u8 page = ( reg & 0x80 ) ? 0 : 1 ; /* Page "1" is low range */
if ( page = = ctx - > current_page )
return 0 ;
/*
* Data sheet claims we ' re only allowed to change bit 4 , so we must do
* a read - modify - write on each and every page select
*/
buf [ 0 ] = BME680_REG_STATUS ;
ret = spi_write_then_read ( spi , buf , 1 , buf + 1 , 1 ) ;
if ( ret < 0 ) {
dev_err ( & spi - > dev , " failed to set page %u \n " , page ) ;
return ret ;
}
buf [ 0 ] = BME680_REG_STATUS ;
if ( page )
buf [ 1 ] | = BME680_SPI_MEM_PAGE_BIT ;
else
buf [ 1 ] & = ~ BME680_SPI_MEM_PAGE_BIT ;
ret = spi_write ( spi , buf , 2 ) ;
if ( ret < 0 ) {
dev_err ( & spi - > dev , " failed to set page %u \n " , page ) ;
return ret ;
}
ctx - > current_page = page ;
return 0 ;
}
2018-07-26 17:05:10 +05:30
static int bme680_regmap_spi_write ( void * context , const void * data ,
size_t count )
{
2019-03-06 08:31:48 +01:00
struct bme680_spi_bus_context * ctx = context ;
struct spi_device * spi = ctx - > spi ;
int ret ;
2018-07-26 17:05:10 +05:30
u8 buf [ 2 ] ;
memcpy ( buf , data , 2 ) ;
2019-03-06 08:31:48 +01:00
ret = bme680_regmap_spi_select_page ( ctx , buf [ 0 ] ) ;
if ( ret )
return ret ;
2018-07-26 17:05:10 +05:30
/*
* The SPI register address ( = full register address without bit 7 )
* and the write command ( bit7 = RW = ' 0 ' )
*/
buf [ 0 ] & = ~ 0x80 ;
2019-03-06 08:31:48 +01:00
return spi_write ( spi , buf , 2 ) ;
2018-07-26 17:05:10 +05:30
}
static int bme680_regmap_spi_read ( void * context , const void * reg ,
size_t reg_size , void * val , size_t val_size )
{
2019-03-06 08:31:48 +01:00
struct bme680_spi_bus_context * ctx = context ;
struct spi_device * spi = ctx - > spi ;
int ret ;
u8 addr = * ( const u8 * ) reg ;
ret = bme680_regmap_spi_select_page ( ctx , addr ) ;
if ( ret )
return ret ;
2018-07-26 17:05:10 +05:30
2019-03-06 08:31:48 +01:00
addr | = 0x80 ; /* bit7 = RW = '1' */
return spi_write_then_read ( spi , & addr , 1 , val , val_size ) ;
2018-07-26 17:05:10 +05:30
}
static struct regmap_bus bme680_regmap_bus = {
. write = bme680_regmap_spi_write ,
. read = bme680_regmap_spi_read ,
. reg_format_endian_default = REGMAP_ENDIAN_BIG ,
. val_format_endian_default = REGMAP_ENDIAN_BIG ,
} ;
static int bme680_spi_probe ( struct spi_device * spi )
{
const struct spi_device_id * id = spi_get_device_id ( spi ) ;
2019-03-06 08:31:48 +01:00
struct bme680_spi_bus_context * bus_context ;
2018-07-26 17:05:10 +05:30
struct regmap * regmap ;
int ret ;
spi - > bits_per_word = 8 ;
ret = spi_setup ( spi ) ;
if ( ret < 0 ) {
dev_err ( & spi - > dev , " spi_setup failed! \n " ) ;
return ret ;
}
2019-03-06 08:31:48 +01:00
bus_context = devm_kzalloc ( & spi - > dev , sizeof ( * bus_context ) , GFP_KERNEL ) ;
if ( ! bus_context )
return - ENOMEM ;
bus_context - > spi = spi ;
bus_context - > current_page = 0xff ; /* Undefined on warm boot */
2018-07-26 17:05:10 +05:30
regmap = devm_regmap_init ( & spi - > dev , & bme680_regmap_bus ,
2019-03-06 08:31:48 +01:00
bus_context , & bme680_regmap_config ) ;
2018-07-26 17:05:10 +05:30
if ( IS_ERR ( regmap ) ) {
dev_err ( & spi - > dev , " Failed to register spi regmap %d \n " ,
( int ) PTR_ERR ( regmap ) ) ;
return PTR_ERR ( regmap ) ;
}
return bme680_core_probe ( & spi - > dev , regmap , id - > name ) ;
}
static const struct spi_device_id bme680_spi_id [ ] = {
{ " bme680 " , 0 } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( spi , bme680_spi_id ) ;
static const struct acpi_device_id bme680_acpi_match [ ] = {
{ " BME0680 " , 0 } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( acpi , bme680_acpi_match ) ;
2019-01-14 15:19:13 -05:00
static const struct of_device_id bme680_of_spi_match [ ] = {
{ . compatible = " bosch,bme680 " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , bme680_of_spi_match ) ;
2018-07-26 17:05:10 +05:30
static struct spi_driver bme680_spi_driver = {
. driver = {
. name = " bme680_spi " ,
. acpi_match_table = ACPI_PTR ( bme680_acpi_match ) ,
2019-01-14 15:19:13 -05:00
. of_match_table = bme680_of_spi_match ,
2018-07-26 17:05:10 +05:30
} ,
. probe = bme680_spi_probe ,
. id_table = bme680_spi_id ,
} ;
module_spi_driver ( bme680_spi_driver ) ;
MODULE_AUTHOR ( " Himanshu Jha <himanshujha199640@gmail.com> " ) ;
MODULE_DESCRIPTION ( " Bosch BME680 SPI driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;