2011-05-27 03:25:05 +04:00
/*
2016-05-03 12:54:34 +03:00
* Micro Crystal RV - 3029 / RV - 3049 rtc class driver
2011-05-27 03:25:05 +04:00
*
* Author : Gregory Hermant < gregory . hermant @ calao - systems . com >
2016-03-05 00:40:30 +03:00
* Michael Buesch < m @ bues . ch >
2011-05-27 03:25:05 +04:00
*
* based on previously existing rtc class drivers
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
*/
# include <linux/module.h>
# include <linux/i2c.h>
2016-05-03 12:54:34 +03:00
# include <linux/spi/spi.h>
2011-05-27 03:25:05 +04:00
# include <linux/bcd.h>
# include <linux/rtc.h>
2016-03-05 00:40:55 +03:00
# include <linux/delay.h>
# include <linux/of.h>
2016-03-10 20:34:46 +03:00
# include <linux/hwmon.h>
# include <linux/hwmon-sysfs.h>
2016-05-03 12:54:33 +03:00
# include <linux/regmap.h>
2011-05-27 03:25:05 +04:00
/* Register map */
/* control section */
2016-03-05 00:38:45 +03:00
# define RV3029_ONOFF_CTRL 0x00
2016-03-05 00:39:49 +03:00
# define RV3029_ONOFF_CTRL_WE BIT(0)
# define RV3029_ONOFF_CTRL_TE BIT(1)
# define RV3029_ONOFF_CTRL_TAR BIT(2)
# define RV3029_ONOFF_CTRL_EERE BIT(3)
# define RV3029_ONOFF_CTRL_SRON BIT(4)
# define RV3029_ONOFF_CTRL_TD0 BIT(5)
# define RV3029_ONOFF_CTRL_TD1 BIT(6)
# define RV3029_ONOFF_CTRL_CLKINT BIT(7)
2016-03-05 00:38:45 +03:00
# define RV3029_IRQ_CTRL 0x01
2016-03-05 00:39:49 +03:00
# define RV3029_IRQ_CTRL_AIE BIT(0)
# define RV3029_IRQ_CTRL_TIE BIT(1)
# define RV3029_IRQ_CTRL_V1IE BIT(2)
# define RV3029_IRQ_CTRL_V2IE BIT(3)
# define RV3029_IRQ_CTRL_SRIE BIT(4)
2016-03-05 00:38:45 +03:00
# define RV3029_IRQ_FLAGS 0x02
2016-03-05 00:39:49 +03:00
# define RV3029_IRQ_FLAGS_AF BIT(0)
# define RV3029_IRQ_FLAGS_TF BIT(1)
# define RV3029_IRQ_FLAGS_V1IF BIT(2)
# define RV3029_IRQ_FLAGS_V2IF BIT(3)
# define RV3029_IRQ_FLAGS_SRF BIT(4)
2016-03-05 00:38:45 +03:00
# define RV3029_STATUS 0x03
2016-03-05 00:39:49 +03:00
# define RV3029_STATUS_VLOW1 BIT(2)
# define RV3029_STATUS_VLOW2 BIT(3)
# define RV3029_STATUS_SR BIT(4)
# define RV3029_STATUS_PON BIT(5)
# define RV3029_STATUS_EEBUSY BIT(7)
2016-03-05 00:38:45 +03:00
# define RV3029_RST_CTRL 0x04
2016-03-05 00:39:49 +03:00
# define RV3029_RST_CTRL_SYSR BIT(4)
2016-03-05 00:38:45 +03:00
# define RV3029_CONTROL_SECTION_LEN 0x05
2011-05-27 03:25:05 +04:00
/* watch section */
2016-03-05 00:38:45 +03:00
# define RV3029_W_SEC 0x08
# define RV3029_W_MINUTES 0x09
# define RV3029_W_HOURS 0x0A
2016-03-05 00:39:49 +03:00
# define RV3029_REG_HR_12_24 BIT(6) /* 24h/12h mode */
# define RV3029_REG_HR_PM BIT(5) /* PM/AM bit in 12h mode */
2016-03-05 00:38:45 +03:00
# define RV3029_W_DATE 0x0B
# define RV3029_W_DAYS 0x0C
# define RV3029_W_MONTHS 0x0D
# define RV3029_W_YEARS 0x0E
# define RV3029_WATCH_SECTION_LEN 0x07
2011-05-27 03:25:05 +04:00
/* alarm section */
2016-03-05 00:38:45 +03:00
# define RV3029_A_SC 0x10
# define RV3029_A_MN 0x11
# define RV3029_A_HR 0x12
# define RV3029_A_DT 0x13
# define RV3029_A_DW 0x14
# define RV3029_A_MO 0x15
# define RV3029_A_YR 0x16
2016-05-03 12:54:36 +03:00
# define RV3029_A_AE_X BIT(7)
2016-03-05 00:38:45 +03:00
# define RV3029_ALARM_SECTION_LEN 0x07
2011-05-27 03:25:05 +04:00
/* timer section */
2016-03-05 00:38:45 +03:00
# define RV3029_TIMER_LOW 0x18
# define RV3029_TIMER_HIGH 0x19
2011-05-27 03:25:05 +04:00
/* temperature section */
2016-03-05 00:38:45 +03:00
# define RV3029_TEMP_PAGE 0x20
2011-05-27 03:25:05 +04:00
/* eeprom data section */
2016-03-05 00:38:45 +03:00
# define RV3029_E2P_EEDATA1 0x28
# define RV3029_E2P_EEDATA2 0x29
2016-03-05 00:39:49 +03:00
# define RV3029_E2PDATA_SECTION_LEN 0x02
2011-05-27 03:25:05 +04:00
/* eeprom control section */
2016-03-05 00:38:45 +03:00
# define RV3029_CONTROL_E2P_EECTRL 0x30
2016-03-05 00:39:49 +03:00
# define RV3029_EECTRL_THP BIT(0) /* temp scan interval */
# define RV3029_EECTRL_THE BIT(1) /* thermometer enable */
# define RV3029_EECTRL_FD0 BIT(2) /* CLKOUT */
# define RV3029_EECTRL_FD1 BIT(3) /* CLKOUT */
# define RV3029_TRICKLE_1K BIT(4) /* 1.5K resistance */
# define RV3029_TRICKLE_5K BIT(5) /* 5K resistance */
# define RV3029_TRICKLE_20K BIT(6) /* 20K resistance */
# define RV3029_TRICKLE_80K BIT(7) /* 80K resistance */
# define RV3029_TRICKLE_MASK (RV3029_TRICKLE_1K |\
RV3029_TRICKLE_5K | \
RV3029_TRICKLE_20K | \
RV3029_TRICKLE_80K )
# define RV3029_TRICKLE_SHIFT 4
# define RV3029_CONTROL_E2P_XOFFS 0x31 /* XTAL offset */
# define RV3029_CONTROL_E2P_XOFFS_SIGN BIT(7) /* Sign: 1->pos, 0->neg */
# define RV3029_CONTROL_E2P_QCOEF 0x32 /* XTAL temp drift coef */
# define RV3029_CONTROL_E2P_TURNOVER 0x33 /* XTAL turnover temp (in *C) */
# define RV3029_CONTROL_E2P_TOV_MASK 0x3F /* XTAL turnover temp mask */
2011-05-27 03:25:05 +04:00
/* user ram section */
2016-03-05 00:38:45 +03:00
# define RV3029_USR1_RAM_PAGE 0x38
# define RV3029_USR1_SECTION_LEN 0x04
# define RV3029_USR2_RAM_PAGE 0x3C
# define RV3029_USR2_SECTION_LEN 0x04
2011-05-27 03:25:05 +04:00
2016-05-03 12:54:33 +03:00
struct rv3029_data {
struct device * dev ;
struct rtc_device * rtc ;
struct regmap * regmap ;
int irq ;
} ;
static int rv3029_read_regs ( struct device * dev , u8 reg , u8 * buf ,
2016-05-03 12:54:35 +03:00
unsigned int len )
2011-05-27 03:25:05 +04:00
{
2016-05-03 12:54:33 +03:00
struct rv3029_data * rv3029 = dev_get_drvdata ( dev ) ;
2011-05-27 03:25:05 +04:00
2016-03-05 00:38:45 +03:00
if ( ( reg > RV3029_USR1_RAM_PAGE + 7 ) | |
2016-05-03 12:54:35 +03:00
( reg + len > RV3029_USR1_RAM_PAGE + 8 ) )
2011-05-27 03:25:05 +04:00
return - EINVAL ;
2016-05-03 12:54:33 +03:00
return regmap_bulk_read ( rv3029 - > regmap , reg , buf , len ) ;
2011-05-27 03:25:05 +04:00
}
2016-05-03 12:54:33 +03:00
static int rv3029_write_regs ( struct device * dev , u8 reg , u8 const buf [ ] ,
2016-05-03 12:54:35 +03:00
unsigned int len )
2011-05-27 03:25:05 +04:00
{
2016-05-03 12:54:33 +03:00
struct rv3029_data * rv3029 = dev_get_drvdata ( dev ) ;
2016-03-05 00:38:45 +03:00
if ( ( reg > RV3029_USR1_RAM_PAGE + 7 ) | |
2016-05-03 12:54:35 +03:00
( reg + len > RV3029_USR1_RAM_PAGE + 8 ) )
2011-05-27 03:25:05 +04:00
return - EINVAL ;
2016-05-03 12:54:33 +03:00
return regmap_bulk_write ( rv3029 - > regmap , reg , buf , len ) ;
2011-05-27 03:25:05 +04:00
}
2016-05-03 12:54:33 +03:00
static int rv3029_update_bits ( struct device * dev , u8 reg , u8 mask , u8 set )
2016-03-05 00:40:30 +03:00
{
u8 buf ;
int ret ;
2016-05-03 12:54:33 +03:00
ret = rv3029_read_regs ( dev , reg , & buf , 1 ) ;
2016-03-05 00:40:30 +03:00
if ( ret < 0 )
return ret ;
buf & = ~ mask ;
buf | = set & mask ;
2016-05-03 12:54:33 +03:00
ret = rv3029_write_regs ( dev , reg , & buf , 1 ) ;
2016-03-05 00:40:30 +03:00
if ( ret < 0 )
return ret ;
return 0 ;
}
2016-05-03 12:54:33 +03:00
static int rv3029_get_sr ( struct device * dev , u8 * buf )
2011-05-27 03:25:05 +04:00
{
2016-05-03 12:54:33 +03:00
int ret = rv3029_read_regs ( dev , RV3029_STATUS , buf , 1 ) ;
2011-05-27 03:25:05 +04:00
if ( ret < 0 )
return - EIO ;
2016-05-03 12:54:33 +03:00
dev_dbg ( dev , " status = 0x%.2x (%d) \n " , buf [ 0 ] , buf [ 0 ] ) ;
2011-05-27 03:25:05 +04:00
return 0 ;
}
2016-05-03 12:54:33 +03:00
static int rv3029_set_sr ( struct device * dev , u8 val )
2011-05-27 03:25:05 +04:00
{
u8 buf [ 1 ] ;
int sr ;
buf [ 0 ] = val ;
2016-05-03 12:54:33 +03:00
sr = rv3029_write_regs ( dev , RV3029_STATUS , buf , 1 ) ;
dev_dbg ( dev , " status = 0x%.2x (%d) \n " , buf [ 0 ] , buf [ 0 ] ) ;
2011-05-27 03:25:05 +04:00
if ( sr < 0 )
return - EIO ;
return 0 ;
}
2016-05-03 12:54:33 +03:00
static int rv3029_eeprom_busywait ( struct device * dev )
2016-03-05 00:40:55 +03:00
{
int i , ret ;
u8 sr ;
for ( i = 100 ; i > 0 ; i - - ) {
2016-05-03 12:54:33 +03:00
ret = rv3029_get_sr ( dev , & sr ) ;
2016-03-05 00:40:55 +03:00
if ( ret < 0 )
break ;
if ( ! ( sr & RV3029_STATUS_EEBUSY ) )
break ;
usleep_range ( 1000 , 10000 ) ;
}
if ( i < = 0 ) {
2016-05-03 12:54:33 +03:00
dev_err ( dev , " EEPROM busy wait timeout. \n " ) ;
2016-03-05 00:40:55 +03:00
return - ETIMEDOUT ;
}
return ret ;
}
2016-05-03 12:54:33 +03:00
static int rv3029_eeprom_exit ( struct device * dev )
2016-03-05 00:40:55 +03:00
{
/* Re-enable eeprom refresh */
2016-05-03 12:54:33 +03:00
return rv3029_update_bits ( dev , RV3029_ONOFF_CTRL ,
2016-05-03 12:54:32 +03:00
RV3029_ONOFF_CTRL_EERE ,
RV3029_ONOFF_CTRL_EERE ) ;
2016-03-05 00:40:55 +03:00
}
2016-05-03 12:54:33 +03:00
static int rv3029_eeprom_enter ( struct device * dev )
2016-03-05 00:40:55 +03:00
{
int ret ;
u8 sr ;
/* Check whether we are in the allowed voltage range. */
2016-05-03 12:54:33 +03:00
ret = rv3029_get_sr ( dev , & sr ) ;
2016-03-05 00:40:55 +03:00
if ( ret < 0 )
return ret ;
if ( sr & ( RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2 ) ) {
/* We clear the bits and retry once just in case
* we had a brown out in early startup .
*/
sr & = ~ RV3029_STATUS_VLOW1 ;
sr & = ~ RV3029_STATUS_VLOW2 ;
2016-05-03 12:54:33 +03:00
ret = rv3029_set_sr ( dev , sr ) ;
2016-03-05 00:40:55 +03:00
if ( ret < 0 )
return ret ;
usleep_range ( 1000 , 10000 ) ;
2016-05-03 12:54:33 +03:00
ret = rv3029_get_sr ( dev , & sr ) ;
2016-03-05 00:40:55 +03:00
if ( ret < 0 )
return ret ;
if ( sr & ( RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2 ) ) {
2016-05-03 12:54:33 +03:00
dev_err ( dev ,
2016-03-05 00:40:55 +03:00
" Supply voltage is too low to safely access the EEPROM. \n " ) ;
return - ENODEV ;
}
}
/* Disable eeprom refresh. */
2016-05-03 12:54:33 +03:00
ret = rv3029_update_bits ( dev , RV3029_ONOFF_CTRL , RV3029_ONOFF_CTRL_EERE ,
0 ) ;
2016-03-05 00:40:55 +03:00
if ( ret < 0 )
return ret ;
/* Wait for any previous eeprom accesses to finish. */
2016-05-03 12:54:33 +03:00
ret = rv3029_eeprom_busywait ( dev ) ;
2016-03-05 00:40:55 +03:00
if ( ret < 0 )
2016-05-03 12:54:33 +03:00
rv3029_eeprom_exit ( dev ) ;
2016-03-05 00:40:55 +03:00
return ret ;
}
2016-05-03 12:54:33 +03:00
static int rv3029_eeprom_read ( struct device * dev , u8 reg ,
2016-03-05 00:40:55 +03:00
u8 buf [ ] , size_t len )
{
int ret , err ;
2016-05-03 12:54:33 +03:00
err = rv3029_eeprom_enter ( dev ) ;
2016-03-05 00:40:55 +03:00
if ( err < 0 )
return err ;
2016-05-03 12:54:33 +03:00
ret = rv3029_read_regs ( dev , reg , buf , len ) ;
2016-03-05 00:40:55 +03:00
2016-05-03 12:54:33 +03:00
err = rv3029_eeprom_exit ( dev ) ;
2016-03-05 00:40:55 +03:00
if ( err < 0 )
return err ;
return ret ;
}
2016-05-03 12:54:33 +03:00
static int rv3029_eeprom_write ( struct device * dev , u8 reg ,
2016-03-05 00:40:55 +03:00
u8 const buf [ ] , size_t len )
{
2017-09-21 00:45:30 +03:00
int ret ;
2016-03-05 00:40:55 +03:00
size_t i ;
u8 tmp ;
2017-09-21 00:45:30 +03:00
ret = rv3029_eeprom_enter ( dev ) ;
if ( ret < 0 )
return ret ;
2016-03-05 00:40:55 +03:00
for ( i = 0 ; i < len ; i + + , reg + + ) {
2016-05-03 12:54:33 +03:00
ret = rv3029_read_regs ( dev , reg , & tmp , 1 ) ;
2016-03-05 00:40:55 +03:00
if ( ret < 0 )
break ;
if ( tmp ! = buf [ i ] ) {
2016-05-03 12:54:33 +03:00
ret = rv3029_write_regs ( dev , reg , & buf [ i ] , 1 ) ;
2016-03-05 00:40:55 +03:00
if ( ret < 0 )
break ;
}
2016-05-03 12:54:33 +03:00
ret = rv3029_eeprom_busywait ( dev ) ;
2016-03-05 00:40:55 +03:00
if ( ret < 0 )
break ;
}
2017-09-21 00:45:30 +03:00
ret = rv3029_eeprom_exit ( dev ) ;
if ( ret < 0 )
return ret ;
2016-03-05 00:40:55 +03:00
2017-09-21 00:45:30 +03:00
return 0 ;
2016-03-05 00:40:55 +03:00
}
2016-05-03 12:54:33 +03:00
static int rv3029_eeprom_update_bits ( struct device * dev ,
2016-03-10 20:34:23 +03:00
u8 reg , u8 mask , u8 set )
{
u8 buf ;
int ret ;
2016-05-03 12:54:33 +03:00
ret = rv3029_eeprom_read ( dev , reg , & buf , 1 ) ;
2016-03-10 20:34:23 +03:00
if ( ret < 0 )
return ret ;
buf & = ~ mask ;
buf | = set & mask ;
2016-05-03 12:54:33 +03:00
ret = rv3029_eeprom_write ( dev , reg , & buf , 1 ) ;
2016-03-10 20:34:23 +03:00
if ( ret < 0 )
return ret ;
return 0 ;
}
2016-05-03 12:54:38 +03:00
static irqreturn_t rv3029_handle_irq ( int irq , void * dev_id )
{
struct device * dev = dev_id ;
struct rv3029_data * rv3029 = dev_get_drvdata ( dev ) ;
struct mutex * lock = & rv3029 - > rtc - > ops_lock ;
unsigned long events = 0 ;
u8 flags , controls ;
int ret ;
mutex_lock ( lock ) ;
ret = rv3029_read_regs ( dev , RV3029_IRQ_CTRL , & controls , 1 ) ;
if ( ret ) {
dev_warn ( dev , " Read IRQ Control Register error %d \n " , ret ) ;
mutex_unlock ( lock ) ;
return IRQ_NONE ;
}
ret = rv3029_read_regs ( dev , RV3029_IRQ_FLAGS , & flags , 1 ) ;
if ( ret ) {
dev_warn ( dev , " Read IRQ Flags Register error %d \n " , ret ) ;
mutex_unlock ( lock ) ;
return IRQ_NONE ;
}
if ( flags & RV3029_IRQ_FLAGS_AF ) {
flags & = ~ RV3029_IRQ_FLAGS_AF ;
controls & = ~ RV3029_IRQ_CTRL_AIE ;
events | = RTC_AF ;
}
if ( events ) {
rtc_update_irq ( rv3029 - > rtc , 1 , events ) ;
rv3029_write_regs ( dev , RV3029_IRQ_FLAGS , & flags , 1 ) ;
rv3029_write_regs ( dev , RV3029_IRQ_CTRL , & controls , 1 ) ;
}
mutex_unlock ( lock ) ;
return IRQ_HANDLED ;
}
2016-05-03 12:54:33 +03:00
static int rv3029_read_time ( struct device * dev , struct rtc_time * tm )
2011-05-27 03:25:05 +04:00
{
u8 buf [ 1 ] ;
int ret ;
2016-03-05 00:38:45 +03:00
u8 regs [ RV3029_WATCH_SECTION_LEN ] = { 0 , } ;
2011-05-27 03:25:05 +04:00
2016-05-03 12:54:33 +03:00
ret = rv3029_get_sr ( dev , buf ) ;
2011-05-27 03:25:05 +04:00
if ( ret < 0 ) {
2016-05-03 12:54:33 +03:00
dev_err ( dev , " %s: reading SR failed \n " , __func__ ) ;
2011-05-27 03:25:05 +04:00
return - EIO ;
}
2016-05-03 12:54:33 +03:00
ret = rv3029_read_regs ( dev , RV3029_W_SEC , regs ,
2016-05-03 12:54:32 +03:00
RV3029_WATCH_SECTION_LEN ) ;
2011-05-27 03:25:05 +04:00
if ( ret < 0 ) {
2016-05-03 12:54:33 +03:00
dev_err ( dev , " %s: reading RTC section failed \n " , __func__ ) ;
2011-05-27 03:25:05 +04:00
return ret ;
}
2016-05-03 12:54:35 +03:00
tm - > tm_sec = bcd2bin ( regs [ RV3029_W_SEC - RV3029_W_SEC ] ) ;
tm - > tm_min = bcd2bin ( regs [ RV3029_W_MINUTES - RV3029_W_SEC ] ) ;
2011-05-27 03:25:05 +04:00
/* HR field has a more complex interpretation */
{
2016-05-03 12:54:35 +03:00
const u8 _hr = regs [ RV3029_W_HOURS - RV3029_W_SEC ] ;
2016-03-05 00:38:45 +03:00
if ( _hr & RV3029_REG_HR_12_24 ) {
2011-05-27 03:25:05 +04:00
/* 12h format */
tm - > tm_hour = bcd2bin ( _hr & 0x1f ) ;
2016-03-05 00:38:45 +03:00
if ( _hr & RV3029_REG_HR_PM ) /* PM flag set */
2011-05-27 03:25:05 +04:00
tm - > tm_hour + = 12 ;
} else /* 24h format */
tm - > tm_hour = bcd2bin ( _hr & 0x3f ) ;
}
2016-05-03 12:54:35 +03:00
tm - > tm_mday = bcd2bin ( regs [ RV3029_W_DATE - RV3029_W_SEC ] ) ;
tm - > tm_mon = bcd2bin ( regs [ RV3029_W_MONTHS - RV3029_W_SEC ] ) - 1 ;
tm - > tm_year = bcd2bin ( regs [ RV3029_W_YEARS - RV3029_W_SEC ] ) + 100 ;
tm - > tm_wday = bcd2bin ( regs [ RV3029_W_DAYS - RV3029_W_SEC ] ) - 1 ;
2011-05-27 03:25:05 +04:00
return 0 ;
}
2016-05-03 12:54:33 +03:00
static int rv3029_read_alarm ( struct device * dev , struct rtc_wkalrm * alarm )
2011-05-27 03:25:05 +04:00
{
struct rtc_time * const tm = & alarm - > time ;
int ret ;
2016-05-03 12:54:38 +03:00
u8 regs [ 8 ] , controls , flags ;
2011-05-27 03:25:05 +04:00
2016-05-03 12:54:33 +03:00
ret = rv3029_get_sr ( dev , regs ) ;
2011-05-27 03:25:05 +04:00
if ( ret < 0 ) {
2016-05-03 12:54:33 +03:00
dev_err ( dev , " %s: reading SR failed \n " , __func__ ) ;
2011-05-27 03:25:05 +04:00
return - EIO ;
}
2016-05-03 12:54:33 +03:00
ret = rv3029_read_regs ( dev , RV3029_A_SC , regs ,
2016-05-03 12:54:32 +03:00
RV3029_ALARM_SECTION_LEN ) ;
2011-05-27 03:25:05 +04:00
if ( ret < 0 ) {
2016-05-03 12:54:33 +03:00
dev_err ( dev , " %s: reading alarm section failed \n " , __func__ ) ;
2011-05-27 03:25:05 +04:00
return ret ;
}
2016-05-03 12:54:38 +03:00
ret = rv3029_read_regs ( dev , RV3029_IRQ_CTRL , & controls , 1 ) ;
if ( ret ) {
dev_err ( dev , " Read IRQ Control Register error %d \n " , ret ) ;
return ret ;
}
ret = rv3029_read_regs ( dev , RV3029_IRQ_FLAGS , & flags , 1 ) ;
if ( ret < 0 ) {
dev_err ( dev , " Read IRQ Flags Register error %d \n " , ret ) ;
return ret ;
}
2016-05-03 12:54:35 +03:00
tm - > tm_sec = bcd2bin ( regs [ RV3029_A_SC - RV3029_A_SC ] & 0x7f ) ;
tm - > tm_min = bcd2bin ( regs [ RV3029_A_MN - RV3029_A_SC ] & 0x7f ) ;
tm - > tm_hour = bcd2bin ( regs [ RV3029_A_HR - RV3029_A_SC ] & 0x3f ) ;
tm - > tm_mday = bcd2bin ( regs [ RV3029_A_DT - RV3029_A_SC ] & 0x3f ) ;
tm - > tm_mon = bcd2bin ( regs [ RV3029_A_MO - RV3029_A_SC ] & 0x1f ) - 1 ;
tm - > tm_year = bcd2bin ( regs [ RV3029_A_YR - RV3029_A_SC ] & 0x7f ) + 100 ;
tm - > tm_wday = bcd2bin ( regs [ RV3029_A_DW - RV3029_A_SC ] & 0x07 ) - 1 ;
2011-05-27 03:25:05 +04:00
2016-05-03 12:54:38 +03:00
alarm - > enabled = ! ! ( controls & RV3029_IRQ_CTRL_AIE ) ;
alarm - > pending = ( flags & RV3029_IRQ_FLAGS_AF ) & & alarm - > enabled ;
2011-05-27 03:25:05 +04:00
return 0 ;
}
2016-05-03 12:54:38 +03:00
static int rv3029_alarm_irq_enable ( struct device * dev , unsigned int enable )
2011-05-27 03:25:05 +04:00
{
int ret ;
2016-05-03 12:54:38 +03:00
u8 controls ;
ret = rv3029_read_regs ( dev , RV3029_IRQ_CTRL , & controls , 1 ) ;
if ( ret < 0 ) {
dev_warn ( dev , " Read IRQ Control Register error %d \n " , ret ) ;
return ret ;
}
2011-05-27 03:25:05 +04:00
2016-03-05 00:40:30 +03:00
/* enable/disable AIE irq */
2016-05-03 12:54:38 +03:00
if ( enable )
controls | = RV3029_IRQ_CTRL_AIE ;
else
controls & = ~ RV3029_IRQ_CTRL_AIE ;
ret = rv3029_write_regs ( dev , RV3029_IRQ_CTRL , & controls , 1 ) ;
2011-05-27 03:25:05 +04:00
if ( ret < 0 ) {
2016-05-03 12:54:33 +03:00
dev_err ( dev , " can't update INT reg \n " ) ;
2011-05-27 03:25:05 +04:00
return ret ;
}
return 0 ;
}
2016-05-03 12:54:33 +03:00
static int rv3029_set_alarm ( struct device * dev , struct rtc_wkalrm * alarm )
2011-05-27 03:25:05 +04:00
{
struct rtc_time * const tm = & alarm - > time ;
int ret ;
u8 regs [ 8 ] ;
/*
* The clock has an 8 bit wide bcd - coded register ( they never learn )
* for the year . tm_year is an offset from 1900 and we are interested
* in the 2000 - 2099 range , so any value less than 100 is invalid .
*/
if ( tm - > tm_year < 100 )
return - EINVAL ;
2016-05-03 12:54:33 +03:00
ret = rv3029_get_sr ( dev , regs ) ;
2011-05-27 03:25:05 +04:00
if ( ret < 0 ) {
2016-05-03 12:54:33 +03:00
dev_err ( dev , " %s: reading SR failed \n " , __func__ ) ;
2011-05-27 03:25:05 +04:00
return - EIO ;
}
2016-03-05 00:38:45 +03:00
2016-05-03 12:54:36 +03:00
/* Activate all the alarms with AE_x bit */
regs [ RV3029_A_SC - RV3029_A_SC ] = bin2bcd ( tm - > tm_sec ) | RV3029_A_AE_X ;
regs [ RV3029_A_MN - RV3029_A_SC ] = bin2bcd ( tm - > tm_min ) | RV3029_A_AE_X ;
regs [ RV3029_A_HR - RV3029_A_SC ] = ( bin2bcd ( tm - > tm_hour ) & 0x3f )
| RV3029_A_AE_X ;
regs [ RV3029_A_DT - RV3029_A_SC ] = ( bin2bcd ( tm - > tm_mday ) & 0x3f )
| RV3029_A_AE_X ;
regs [ RV3029_A_MO - RV3029_A_SC ] = ( bin2bcd ( tm - > tm_mon + 1 ) & 0x1f )
| RV3029_A_AE_X ;
regs [ RV3029_A_DW - RV3029_A_SC ] = ( bin2bcd ( tm - > tm_wday + 1 ) & 0x7 )
| RV3029_A_AE_X ;
regs [ RV3029_A_YR - RV3029_A_SC ] = ( bin2bcd ( tm - > tm_year - 100 ) )
| RV3029_A_AE_X ;
/* Write the alarm */
2016-05-03 12:54:33 +03:00
ret = rv3029_write_regs ( dev , RV3029_A_SC , regs ,
2016-05-03 12:54:32 +03:00
RV3029_ALARM_SECTION_LEN ) ;
2011-05-27 03:25:05 +04:00
if ( ret < 0 )
return ret ;
if ( alarm - > enabled ) {
/* enable AIE irq */
2016-05-03 12:54:38 +03:00
ret = rv3029_alarm_irq_enable ( dev , 1 ) ;
2011-05-27 03:25:05 +04:00
if ( ret )
return ret ;
} else {
/* disable AIE irq */
2016-05-03 12:54:38 +03:00
ret = rv3029_alarm_irq_enable ( dev , 0 ) ;
2011-05-27 03:25:05 +04:00
if ( ret )
return ret ;
}
return 0 ;
}
2016-05-03 12:54:33 +03:00
static int rv3029_set_time ( struct device * dev , struct rtc_time * tm )
2011-05-27 03:25:05 +04:00
{
u8 regs [ 8 ] ;
int ret ;
/*
* The clock has an 8 bit wide bcd - coded register ( they never learn )
* for the year . tm_year is an offset from 1900 and we are interested
* in the 2000 - 2099 range , so any value less than 100 is invalid .
*/
if ( tm - > tm_year < 100 )
return - EINVAL ;
2016-05-03 12:54:35 +03:00
regs [ RV3029_W_SEC - RV3029_W_SEC ] = bin2bcd ( tm - > tm_sec ) ;
regs [ RV3029_W_MINUTES - RV3029_W_SEC ] = bin2bcd ( tm - > tm_min ) ;
regs [ RV3029_W_HOURS - RV3029_W_SEC ] = bin2bcd ( tm - > tm_hour ) ;
regs [ RV3029_W_DATE - RV3029_W_SEC ] = bin2bcd ( tm - > tm_mday ) ;
regs [ RV3029_W_MONTHS - RV3029_W_SEC ] = bin2bcd ( tm - > tm_mon + 1 ) ;
2016-05-03 12:54:37 +03:00
regs [ RV3029_W_DAYS - RV3029_W_SEC ] = bin2bcd ( tm - > tm_wday + 1 ) & 0x7 ;
2016-05-03 12:54:35 +03:00
regs [ RV3029_W_YEARS - RV3029_W_SEC ] = bin2bcd ( tm - > tm_year - 100 ) ;
2011-05-27 03:25:05 +04:00
2016-05-03 12:54:33 +03:00
ret = rv3029_write_regs ( dev , RV3029_W_SEC , regs ,
2016-05-03 12:54:32 +03:00
RV3029_WATCH_SECTION_LEN ) ;
2011-05-27 03:25:05 +04:00
if ( ret < 0 )
return ret ;
2016-05-03 12:54:33 +03:00
ret = rv3029_get_sr ( dev , regs ) ;
2011-05-27 03:25:05 +04:00
if ( ret < 0 ) {
2016-05-03 12:54:33 +03:00
dev_err ( dev , " %s: reading SR failed \n " , __func__ ) ;
2011-05-27 03:25:05 +04:00
return ret ;
}
/* clear PON bit */
2016-05-03 12:54:33 +03:00
ret = rv3029_set_sr ( dev , ( regs [ 0 ] & ~ RV3029_STATUS_PON ) ) ;
2011-05-27 03:25:05 +04:00
if ( ret < 0 ) {
2016-05-03 12:54:33 +03:00
dev_err ( dev , " %s: reading SR failed \n " , __func__ ) ;
2011-05-27 03:25:05 +04:00
return ret ;
}
return 0 ;
}
2016-05-03 12:54:35 +03:00
2016-03-05 00:41:19 +03:00
static const struct rv3029_trickle_tab_elem {
u32 r ; /* resistance in ohms */
u8 conf ; /* trickle config bits */
} rv3029_trickle_tab [ ] = {
{
. r = 1076 ,
. conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K |
RV3029_TRICKLE_20K | RV3029_TRICKLE_80K ,
} , {
. r = 1091 ,
. conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K |
RV3029_TRICKLE_20K ,
} , {
. r = 1137 ,
. conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K |
RV3029_TRICKLE_80K ,
} , {
. r = 1154 ,
. conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_5K ,
} , {
. r = 1371 ,
. conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K |
RV3029_TRICKLE_80K ,
} , {
. r = 1395 ,
. conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_20K ,
} , {
. r = 1472 ,
. conf = RV3029_TRICKLE_1K | RV3029_TRICKLE_80K ,
} , {
. r = 1500 ,
. conf = RV3029_TRICKLE_1K ,
} , {
. r = 3810 ,
. conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K |
RV3029_TRICKLE_80K ,
} , {
. r = 4000 ,
. conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_20K ,
} , {
. r = 4706 ,
. conf = RV3029_TRICKLE_5K | RV3029_TRICKLE_80K ,
} , {
. r = 5000 ,
. conf = RV3029_TRICKLE_5K ,
} , {
. r = 16000 ,
. conf = RV3029_TRICKLE_20K | RV3029_TRICKLE_80K ,
} , {
. r = 20000 ,
. conf = RV3029_TRICKLE_20K ,
} , {
. r = 80000 ,
. conf = RV3029_TRICKLE_80K ,
} ,
} ;
2016-05-03 12:54:33 +03:00
static void rv3029_trickle_config ( struct device * dev )
2016-03-05 00:41:19 +03:00
{
2016-05-03 12:54:33 +03:00
struct device_node * of_node = dev - > of_node ;
2016-03-05 00:41:19 +03:00
const struct rv3029_trickle_tab_elem * elem ;
int i , err ;
u32 ohms ;
2016-03-10 20:34:23 +03:00
u8 trickle_set_bits ;
2016-03-05 00:41:19 +03:00
if ( ! of_node )
return ;
/* Configure the trickle charger. */
err = of_property_read_u32 ( of_node , " trickle-resistor-ohms " , & ohms ) ;
if ( err ) {
/* Disable trickle charger. */
2016-03-10 20:34:23 +03:00
trickle_set_bits = 0 ;
2016-03-05 00:41:19 +03:00
} else {
/* Enable trickle charger. */
for ( i = 0 ; i < ARRAY_SIZE ( rv3029_trickle_tab ) ; i + + ) {
elem = & rv3029_trickle_tab [ i ] ;
if ( elem - > r > = ohms )
break ;
}
2016-03-10 20:34:23 +03:00
trickle_set_bits = elem - > conf ;
2016-05-03 12:54:33 +03:00
dev_info ( dev ,
2016-03-05 00:41:19 +03:00
" Trickle charger enabled at %d ohms resistance. \n " ,
elem - > r ) ;
}
2016-05-03 12:54:33 +03:00
err = rv3029_eeprom_update_bits ( dev , RV3029_CONTROL_E2P_EECTRL ,
2016-03-10 20:34:23 +03:00
RV3029_TRICKLE_MASK ,
trickle_set_bits ) ;
2016-05-03 12:54:35 +03:00
if ( err < 0 )
2016-05-03 12:54:33 +03:00
dev_err ( dev , " Failed to update trickle charger config \n " ) ;
2016-03-05 00:41:19 +03:00
}
2016-03-10 20:34:46 +03:00
# ifdef CONFIG_RTC_DRV_RV3029_HWMON
2016-05-03 12:54:33 +03:00
static int rv3029_read_temp ( struct device * dev , int * temp_mC )
2016-03-10 20:34:46 +03:00
{
int ret ;
u8 temp ;
2016-05-03 12:54:33 +03:00
ret = rv3029_read_regs ( dev , RV3029_TEMP_PAGE , & temp , 1 ) ;
2016-03-10 20:34:46 +03:00
if ( ret < 0 )
return ret ;
* temp_mC = ( ( int ) temp - 60 ) * 1000 ;
return 0 ;
}
static ssize_t rv3029_hwmon_show_temp ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
int ret , temp_mC ;
2016-05-03 12:54:33 +03:00
ret = rv3029_read_temp ( dev , & temp_mC ) ;
2016-03-10 20:34:46 +03:00
if ( ret < 0 )
return ret ;
return sprintf ( buf , " %d \n " , temp_mC ) ;
}
static ssize_t rv3029_hwmon_set_update_interval ( struct device * dev ,
struct device_attribute * attr ,
const char * buf ,
size_t count )
{
unsigned long interval_ms ;
int ret ;
u8 th_set_bits = 0 ;
ret = kstrtoul ( buf , 10 , & interval_ms ) ;
if ( ret < 0 )
return ret ;
if ( interval_ms ! = 0 ) {
th_set_bits | = RV3029_EECTRL_THE ;
if ( interval_ms > = 16000 )
th_set_bits | = RV3029_EECTRL_THP ;
}
2016-05-03 12:54:33 +03:00
ret = rv3029_eeprom_update_bits ( dev , RV3029_CONTROL_E2P_EECTRL ,
2016-03-10 20:34:46 +03:00
RV3029_EECTRL_THE | RV3029_EECTRL_THP ,
th_set_bits ) ;
if ( ret < 0 )
return ret ;
return count ;
}
static ssize_t rv3029_hwmon_show_update_interval ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
int ret , interval_ms ;
u8 eectrl ;
2016-05-03 12:54:33 +03:00
ret = rv3029_eeprom_read ( dev , RV3029_CONTROL_E2P_EECTRL ,
2016-03-10 20:34:46 +03:00
& eectrl , 1 ) ;
if ( ret < 0 )
return ret ;
if ( eectrl & RV3029_EECTRL_THE ) {
if ( eectrl & RV3029_EECTRL_THP )
interval_ms = 16000 ;
else
interval_ms = 1000 ;
} else {
interval_ms = 0 ;
}
return sprintf ( buf , " %d \n " , interval_ms ) ;
}
static SENSOR_DEVICE_ATTR ( temp1_input , S_IRUGO , rv3029_hwmon_show_temp ,
NULL , 0 ) ;
static SENSOR_DEVICE_ATTR ( update_interval , S_IWUSR | S_IRUGO ,
rv3029_hwmon_show_update_interval ,
rv3029_hwmon_set_update_interval , 0 ) ;
static struct attribute * rv3029_hwmon_attrs [ ] = {
& sensor_dev_attr_temp1_input . dev_attr . attr ,
& sensor_dev_attr_update_interval . dev_attr . attr ,
NULL ,
} ;
ATTRIBUTE_GROUPS ( rv3029_hwmon ) ;
2016-05-03 12:54:33 +03:00
static void rv3029_hwmon_register ( struct device * dev , const char * name )
2016-03-10 20:34:46 +03:00
{
2016-05-03 12:54:33 +03:00
struct rv3029_data * rv3029 = dev_get_drvdata ( dev ) ;
2016-03-10 20:34:46 +03:00
struct device * hwmon_dev ;
2016-05-03 12:54:33 +03:00
hwmon_dev = devm_hwmon_device_register_with_groups ( dev , name , rv3029 ,
rv3029_hwmon_groups ) ;
2016-03-10 20:34:46 +03:00
if ( IS_ERR ( hwmon_dev ) ) {
2016-05-03 12:54:33 +03:00
dev_warn ( dev , " unable to register hwmon device %ld \n " ,
2016-05-03 12:54:32 +03:00
PTR_ERR ( hwmon_dev ) ) ;
2016-03-10 20:34:46 +03:00
}
}
# else /* CONFIG_RTC_DRV_RV3029_HWMON */
2016-05-03 12:54:33 +03:00
static void rv3029_hwmon_register ( struct device * dev , const char * name )
2016-03-10 20:34:46 +03:00
{
}
# endif /* CONFIG_RTC_DRV_RV3029_HWMON */
2016-05-03 12:54:38 +03:00
static struct rtc_class_ops rv3029_rtc_ops = {
2016-05-03 12:54:33 +03:00
. read_time = rv3029_read_time ,
. set_time = rv3029_set_time ,
2011-05-27 03:25:05 +04:00
} ;
2016-05-03 12:54:33 +03:00
static int rv3029_probe ( struct device * dev , struct regmap * regmap , int irq ,
const char * name )
2011-05-27 03:25:05 +04:00
{
2016-05-03 12:54:33 +03:00
struct rv3029_data * rv3029 ;
2011-05-27 03:25:05 +04:00
int rc = 0 ;
u8 buf [ 1 ] ;
2016-05-03 12:54:33 +03:00
rv3029 = devm_kzalloc ( dev , sizeof ( * rv3029 ) , GFP_KERNEL ) ;
if ( ! rv3029 )
return - ENOMEM ;
rv3029 - > regmap = regmap ;
rv3029 - > irq = irq ;
rv3029 - > dev = dev ;
dev_set_drvdata ( dev , rv3029 ) ;
2011-05-27 03:25:05 +04:00
2016-05-03 12:54:33 +03:00
rc = rv3029_get_sr ( dev , buf ) ;
2014-04-04 01:50:17 +04:00
if ( rc < 0 ) {
2016-05-03 12:54:33 +03:00
dev_err ( dev , " reading status failed \n " ) ;
2014-04-04 01:50:17 +04:00
return rc ;
}
2016-05-03 12:54:33 +03:00
rv3029_trickle_config ( dev ) ;
rv3029_hwmon_register ( dev , name ) ;
rv3029 - > rtc = devm_rtc_device_register ( dev , name , & rv3029_rtc_ops ,
THIS_MODULE ) ;
2016-05-03 12:54:38 +03:00
if ( IS_ERR ( rv3029 - > rtc ) ) {
dev_err ( dev , " unable to register the class device \n " ) ;
return PTR_ERR ( rv3029 - > rtc ) ;
}
2016-03-05 00:41:19 +03:00
2016-05-03 12:54:38 +03:00
if ( rv3029 - > irq > 0 ) {
rc = devm_request_threaded_irq ( dev , rv3029 - > irq ,
NULL , rv3029_handle_irq ,
IRQF_TRIGGER_LOW | IRQF_ONESHOT ,
" rv3029 " , dev ) ;
if ( rc ) {
dev_warn ( dev , " unable to request IRQ, alarms disabled \n " ) ;
rv3029 - > irq = 0 ;
} else {
rv3029_rtc_ops . read_alarm = rv3029_read_alarm ;
rv3029_rtc_ops . set_alarm = rv3029_set_alarm ;
rv3029_rtc_ops . alarm_irq_enable = rv3029_alarm_irq_enable ;
}
}
return 0 ;
2016-05-03 12:54:33 +03:00
}
2011-05-27 03:25:05 +04:00
2016-05-03 12:54:34 +03:00
# if IS_ENABLED(CONFIG_I2C)
2016-05-03 12:54:33 +03:00
static int rv3029_i2c_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
struct regmap * regmap ;
static const struct regmap_config config = {
. reg_bits = 8 ,
. val_bits = 8 ,
} ;
if ( ! i2c_check_functionality ( client - > adapter , I2C_FUNC_SMBUS_I2C_BLOCK |
I2C_FUNC_SMBUS_BYTE ) ) {
dev_err ( & client - > dev , " Adapter does not support SMBUS_I2C_BLOCK or SMBUS_I2C_BYTE \n " ) ;
return - ENODEV ;
}
2011-05-27 03:25:05 +04:00
2016-05-03 12:54:33 +03:00
regmap = devm_regmap_init_i2c ( client , & config ) ;
if ( IS_ERR ( regmap ) ) {
dev_err ( & client - > dev , " %s: regmap allocation failed: %ld \n " ,
__func__ , PTR_ERR ( regmap ) ) ;
return PTR_ERR ( regmap ) ;
}
2011-05-27 03:25:05 +04:00
2016-05-03 12:54:33 +03:00
return rv3029_probe ( & client - > dev , regmap , client - > irq , client - > name ) ;
2011-05-27 03:25:05 +04:00
}
2017-08-19 22:07:55 +03:00
static const struct i2c_device_id rv3029_id [ ] = {
2016-05-04 12:50:02 +03:00
{ " rv3029 " , 0 } ,
{ " rv3029c2 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , rv3029_id ) ;
2017-03-03 17:29:13 +03:00
static const struct of_device_id rv3029_of_match [ ] = {
2017-09-15 05:00:02 +03:00
{ . compatible = " microcrystal,rv3029 " } ,
/* Backward compatibility only, do not use compatibles below: */
2017-03-03 17:29:13 +03:00
{ . compatible = " rv3029 " } ,
{ . compatible = " rv3029c2 " } ,
{ . compatible = " mc,rv3029c2 " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , rv3029_of_match ) ;
2016-03-05 00:38:45 +03:00
static struct i2c_driver rv3029_driver = {
2011-05-27 03:25:05 +04:00
. driver = {
. name = " rtc-rv3029c2 " ,
2017-03-03 17:29:13 +03:00
. of_match_table = of_match_ptr ( rv3029_of_match ) ,
2011-05-27 03:25:05 +04:00
} ,
2016-05-03 12:54:33 +03:00
. probe = rv3029_i2c_probe ,
2016-03-05 00:38:45 +03:00
. id_table = rv3029_id ,
2011-05-27 03:25:05 +04:00
} ;
2016-05-03 12:54:34 +03:00
static int rv3029_register_driver ( void )
{
return i2c_add_driver ( & rv3029_driver ) ;
}
static void rv3029_unregister_driver ( void )
{
i2c_del_driver ( & rv3029_driver ) ;
}
# else
static int rv3029_register_driver ( void )
{
return 0 ;
}
static void rv3029_unregister_driver ( void )
{
}
# endif
# if IS_ENABLED(CONFIG_SPI_MASTER)
static int rv3049_probe ( struct spi_device * spi )
{
static const struct regmap_config config = {
. reg_bits = 8 ,
. val_bits = 8 ,
} ;
struct regmap * regmap ;
regmap = devm_regmap_init_spi ( spi , & config ) ;
if ( IS_ERR ( regmap ) ) {
dev_err ( & spi - > dev , " %s: regmap allocation failed: %ld \n " ,
__func__ , PTR_ERR ( regmap ) ) ;
return PTR_ERR ( regmap ) ;
}
return rv3029_probe ( & spi - > dev , regmap , spi - > irq , " rv3049 " ) ;
}
static struct spi_driver rv3049_driver = {
. driver = {
. name = " rv3049 " ,
} ,
. probe = rv3049_probe ,
} ;
static int rv3049_register_driver ( void )
{
return spi_register_driver ( & rv3049_driver ) ;
}
static void rv3049_unregister_driver ( void )
{
spi_unregister_driver ( & rv3049_driver ) ;
}
# else
static int rv3049_register_driver ( void )
{
return 0 ;
}
static void rv3049_unregister_driver ( void )
{
}
# endif
static int __init rv30x9_init ( void )
{
int ret ;
ret = rv3029_register_driver ( ) ;
if ( ret ) {
pr_err ( " Failed to register rv3029 driver: %d \n " , ret ) ;
return ret ;
}
ret = rv3049_register_driver ( ) ;
if ( ret ) {
pr_err ( " Failed to register rv3049 driver: %d \n " , ret ) ;
rv3029_unregister_driver ( ) ;
}
return ret ;
}
module_init ( rv30x9_init )
static void __exit rv30x9_exit ( void )
{
rv3049_unregister_driver ( ) ;
rv3029_unregister_driver ( ) ;
}
module_exit ( rv30x9_exit )
2011-05-27 03:25:05 +04:00
MODULE_AUTHOR ( " Gregory Hermant <gregory.hermant@calao-systems.com> " ) ;
2016-03-05 00:40:30 +03:00
MODULE_AUTHOR ( " Michael Buesch <m@bues.ch> " ) ;
2016-05-03 12:54:34 +03:00
MODULE_DESCRIPTION ( " Micro Crystal RV3029/RV3049 RTC driver " ) ;
2011-05-27 03:25:05 +04:00
MODULE_LICENSE ( " GPL " ) ;
2016-05-03 12:54:34 +03:00
MODULE_ALIAS ( " spi:rv3049 " ) ;