2020-10-13 17:41:10 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* RTC driver for the Micro Crystal RV3032
*
* Copyright ( C ) 2020 Micro Crystal SA
*
* Alexandre Belloni < alexandre . belloni @ bootlin . com >
*
*/
# include <linux/clk.h>
# include <linux/clk-provider.h>
# include <linux/bcd.h>
# include <linux/bitfield.h>
# include <linux/bitops.h>
# include <linux/hwmon.h>
# include <linux/i2c.h>
# include <linux/interrupt.h>
# include <linux/kernel.h>
# include <linux/log2.h>
# include <linux/module.h>
# include <linux/of_device.h>
# include <linux/regmap.h>
# include <linux/rtc.h>
# define RV3032_SEC 0x01
# define RV3032_MIN 0x02
# define RV3032_HOUR 0x03
# define RV3032_WDAY 0x04
# define RV3032_DAY 0x05
# define RV3032_MONTH 0x06
# define RV3032_YEAR 0x07
# define RV3032_ALARM_MIN 0x08
# define RV3032_ALARM_HOUR 0x09
# define RV3032_ALARM_DAY 0x0A
# define RV3032_STATUS 0x0D
# define RV3032_TLSB 0x0E
# define RV3032_TMSB 0x0F
# define RV3032_CTRL1 0x10
# define RV3032_CTRL2 0x11
# define RV3032_CTRL3 0x12
# define RV3032_TS_CTRL 0x13
# define RV3032_CLK_IRQ 0x14
# define RV3032_EEPROM_ADDR 0x3D
# define RV3032_EEPROM_DATA 0x3E
# define RV3032_EEPROM_CMD 0x3F
# define RV3032_RAM1 0x40
# define RV3032_PMU 0xC0
# define RV3032_OFFSET 0xC1
# define RV3032_CLKOUT1 0xC2
# define RV3032_CLKOUT2 0xC3
# define RV3032_TREF0 0xC4
# define RV3032_TREF1 0xC5
# define RV3032_STATUS_VLF BIT(0)
# define RV3032_STATUS_PORF BIT(1)
# define RV3032_STATUS_EVF BIT(2)
# define RV3032_STATUS_AF BIT(3)
# define RV3032_STATUS_TF BIT(4)
# define RV3032_STATUS_UF BIT(5)
# define RV3032_STATUS_TLF BIT(6)
# define RV3032_STATUS_THF BIT(7)
# define RV3032_TLSB_CLKF BIT(1)
# define RV3032_TLSB_EEBUSY BIT(2)
# define RV3032_TLSB_TEMP GENMASK(7, 4)
# define RV3032_CLKOUT2_HFD_MSK GENMASK(4, 0)
# define RV3032_CLKOUT2_FD_MSK GENMASK(6, 5)
# define RV3032_CLKOUT2_OS BIT(7)
# define RV3032_CTRL1_EERD BIT(3)
# define RV3032_CTRL1_WADA BIT(5)
# define RV3032_CTRL2_STOP BIT(0)
# define RV3032_CTRL2_EIE BIT(2)
# define RV3032_CTRL2_AIE BIT(3)
# define RV3032_CTRL2_TIE BIT(4)
# define RV3032_CTRL2_UIE BIT(5)
# define RV3032_CTRL2_CLKIE BIT(6)
# define RV3032_CTRL2_TSE BIT(7)
# define RV3032_PMU_TCM GENMASK(1, 0)
# define RV3032_PMU_TCR GENMASK(3, 2)
# define RV3032_PMU_BSM GENMASK(5, 4)
# define RV3032_PMU_NCLKE BIT(6)
# define RV3032_PMU_BSM_DSM 1
# define RV3032_PMU_BSM_LSM 2
# define RV3032_OFFSET_MSK GENMASK(5, 0)
# define RV3032_EVT_CTRL_TSR BIT(2)
# define RV3032_EEPROM_CMD_UPDATE 0x11
# define RV3032_EEPROM_CMD_WRITE 0x21
# define RV3032_EEPROM_CMD_READ 0x22
# define RV3032_EEPROM_USER 0xCB
# define RV3032_EEBUSY_POLL 10000
# define RV3032_EEBUSY_TIMEOUT 100000
# define OFFSET_STEP_PPT 238419
struct rv3032_data {
struct regmap * regmap ;
struct rtc_device * rtc ;
2021-10-18 18:19:33 +03:00
bool trickle_charger_set ;
2020-10-13 17:41:10 +03:00
# ifdef CONFIG_COMMON_CLK
struct clk_hw clkout_hw ;
# endif
} ;
static u16 rv3032_trickle_resistors [ ] = { 1000 , 2000 , 7000 , 11000 } ;
static u16 rv3032_trickle_voltages [ ] = { 0 , 1750 , 3000 , 4400 } ;
static int rv3032_exit_eerd ( struct rv3032_data * rv3032 , u32 eerd )
{
if ( eerd )
return 0 ;
return regmap_update_bits ( rv3032 - > regmap , RV3032_CTRL1 , RV3032_CTRL1_EERD , 0 ) ;
}
static int rv3032_enter_eerd ( struct rv3032_data * rv3032 , u32 * eerd )
{
u32 ctrl1 , status ;
int ret ;
ret = regmap_read ( rv3032 - > regmap , RV3032_CTRL1 , & ctrl1 ) ;
if ( ret )
return ret ;
* eerd = ctrl1 & RV3032_CTRL1_EERD ;
if ( * eerd )
return 0 ;
ret = regmap_update_bits ( rv3032 - > regmap , RV3032_CTRL1 ,
RV3032_CTRL1_EERD , RV3032_CTRL1_EERD ) ;
if ( ret )
return ret ;
ret = regmap_read_poll_timeout ( rv3032 - > regmap , RV3032_TLSB , status ,
! ( status & RV3032_TLSB_EEBUSY ) ,
RV3032_EEBUSY_POLL , RV3032_EEBUSY_TIMEOUT ) ;
if ( ret ) {
rv3032_exit_eerd ( rv3032 , * eerd ) ;
return ret ;
}
return 0 ;
}
static int rv3032_update_cfg ( struct rv3032_data * rv3032 , unsigned int reg ,
unsigned int mask , unsigned int val )
{
u32 status , eerd ;
int ret ;
ret = rv3032_enter_eerd ( rv3032 , & eerd ) ;
if ( ret )
return ret ;
ret = regmap_update_bits ( rv3032 - > regmap , reg , mask , val ) ;
if ( ret )
goto exit_eerd ;
ret = regmap_write ( rv3032 - > regmap , RV3032_EEPROM_CMD , RV3032_EEPROM_CMD_UPDATE ) ;
if ( ret )
goto exit_eerd ;
usleep_range ( 46000 , RV3032_EEBUSY_TIMEOUT ) ;
ret = regmap_read_poll_timeout ( rv3032 - > regmap , RV3032_TLSB , status ,
! ( status & RV3032_TLSB_EEBUSY ) ,
RV3032_EEBUSY_POLL , RV3032_EEBUSY_TIMEOUT ) ;
exit_eerd :
rv3032_exit_eerd ( rv3032 , eerd ) ;
return ret ;
}
static irqreturn_t rv3032_handle_irq ( int irq , void * dev_id )
{
struct rv3032_data * rv3032 = dev_id ;
unsigned long events = 0 ;
u32 status = 0 , ctrl = 0 ;
if ( regmap_read ( rv3032 - > regmap , RV3032_STATUS , & status ) < 0 | |
status = = 0 ) {
return IRQ_NONE ;
}
if ( status & RV3032_STATUS_TF ) {
status | = RV3032_STATUS_TF ;
ctrl | = RV3032_CTRL2_TIE ;
events | = RTC_PF ;
}
if ( status & RV3032_STATUS_AF ) {
status | = RV3032_STATUS_AF ;
ctrl | = RV3032_CTRL2_AIE ;
events | = RTC_AF ;
}
if ( status & RV3032_STATUS_UF ) {
status | = RV3032_STATUS_UF ;
ctrl | = RV3032_CTRL2_UIE ;
events | = RTC_UF ;
}
if ( events ) {
rtc_update_irq ( rv3032 - > rtc , 1 , events ) ;
regmap_update_bits ( rv3032 - > regmap , RV3032_STATUS , status , 0 ) ;
regmap_update_bits ( rv3032 - > regmap , RV3032_CTRL2 , ctrl , 0 ) ;
}
return IRQ_HANDLED ;
}
static int rv3032_get_time ( struct device * dev , struct rtc_time * tm )
{
struct rv3032_data * rv3032 = dev_get_drvdata ( dev ) ;
u8 date [ 7 ] ;
int ret , status ;
ret = regmap_read ( rv3032 - > regmap , RV3032_STATUS , & status ) ;
if ( ret < 0 )
return ret ;
if ( status & ( RV3032_STATUS_PORF | RV3032_STATUS_VLF ) )
return - EINVAL ;
ret = regmap_bulk_read ( rv3032 - > regmap , RV3032_SEC , date , sizeof ( date ) ) ;
if ( ret )
return ret ;
tm - > tm_sec = bcd2bin ( date [ 0 ] & 0x7f ) ;
tm - > tm_min = bcd2bin ( date [ 1 ] & 0x7f ) ;
tm - > tm_hour = bcd2bin ( date [ 2 ] & 0x3f ) ;
tm - > tm_wday = date [ 3 ] & 0x7 ;
tm - > tm_mday = bcd2bin ( date [ 4 ] & 0x3f ) ;
tm - > tm_mon = bcd2bin ( date [ 5 ] & 0x1f ) - 1 ;
tm - > tm_year = bcd2bin ( date [ 6 ] ) + 100 ;
return 0 ;
}
static int rv3032_set_time ( struct device * dev , struct rtc_time * tm )
{
struct rv3032_data * rv3032 = dev_get_drvdata ( dev ) ;
u8 date [ 7 ] ;
int ret ;
date [ 0 ] = bin2bcd ( tm - > tm_sec ) ;
date [ 1 ] = bin2bcd ( tm - > tm_min ) ;
date [ 2 ] = bin2bcd ( tm - > tm_hour ) ;
date [ 3 ] = tm - > tm_wday ;
date [ 4 ] = bin2bcd ( tm - > tm_mday ) ;
date [ 5 ] = bin2bcd ( tm - > tm_mon + 1 ) ;
date [ 6 ] = bin2bcd ( tm - > tm_year - 100 ) ;
ret = regmap_bulk_write ( rv3032 - > regmap , RV3032_SEC , date ,
sizeof ( date ) ) ;
if ( ret )
return ret ;
ret = regmap_update_bits ( rv3032 - > regmap , RV3032_STATUS ,
RV3032_STATUS_PORF | RV3032_STATUS_VLF , 0 ) ;
return ret ;
}
static int rv3032_get_alarm ( struct device * dev , struct rtc_wkalrm * alrm )
{
struct rv3032_data * rv3032 = dev_get_drvdata ( dev ) ;
u8 alarmvals [ 3 ] ;
int status , ctrl , ret ;
ret = regmap_bulk_read ( rv3032 - > regmap , RV3032_ALARM_MIN , alarmvals ,
sizeof ( alarmvals ) ) ;
if ( ret )
return ret ;
ret = regmap_read ( rv3032 - > regmap , RV3032_STATUS , & status ) ;
if ( ret < 0 )
return ret ;
ret = regmap_read ( rv3032 - > regmap , RV3032_CTRL2 , & ctrl ) ;
if ( ret < 0 )
return ret ;
alrm - > time . tm_sec = 0 ;
alrm - > time . tm_min = bcd2bin ( alarmvals [ 0 ] & 0x7f ) ;
alrm - > time . tm_hour = bcd2bin ( alarmvals [ 1 ] & 0x3f ) ;
alrm - > time . tm_mday = bcd2bin ( alarmvals [ 2 ] & 0x3f ) ;
alrm - > enabled = ! ! ( ctrl & RV3032_CTRL2_AIE ) ;
alrm - > pending = ( status & RV3032_STATUS_AF ) & & alrm - > enabled ;
return 0 ;
}
static int rv3032_set_alarm ( struct device * dev , struct rtc_wkalrm * alrm )
{
struct rv3032_data * rv3032 = dev_get_drvdata ( dev ) ;
u8 alarmvals [ 3 ] ;
u8 ctrl = 0 ;
int ret ;
ret = regmap_update_bits ( rv3032 - > regmap , RV3032_CTRL2 ,
RV3032_CTRL2_AIE | RV3032_CTRL2_UIE , 0 ) ;
if ( ret )
return ret ;
alarmvals [ 0 ] = bin2bcd ( alrm - > time . tm_min ) ;
alarmvals [ 1 ] = bin2bcd ( alrm - > time . tm_hour ) ;
alarmvals [ 2 ] = bin2bcd ( alrm - > time . tm_mday ) ;
ret = regmap_update_bits ( rv3032 - > regmap , RV3032_STATUS ,
RV3032_STATUS_AF , 0 ) ;
if ( ret )
return ret ;
ret = regmap_bulk_write ( rv3032 - > regmap , RV3032_ALARM_MIN , alarmvals ,
sizeof ( alarmvals ) ) ;
if ( ret )
return ret ;
if ( alrm - > enabled ) {
if ( rv3032 - > rtc - > uie_rtctimer . enabled )
ctrl | = RV3032_CTRL2_UIE ;
if ( rv3032 - > rtc - > aie_timer . enabled )
ctrl | = RV3032_CTRL2_AIE ;
}
ret = regmap_update_bits ( rv3032 - > regmap , RV3032_CTRL2 ,
RV3032_CTRL2_UIE | RV3032_CTRL2_AIE , ctrl ) ;
return ret ;
}
static int rv3032_alarm_irq_enable ( struct device * dev , unsigned int enabled )
{
struct rv3032_data * rv3032 = dev_get_drvdata ( dev ) ;
int ctrl = 0 , ret ;
if ( enabled ) {
if ( rv3032 - > rtc - > uie_rtctimer . enabled )
ctrl | = RV3032_CTRL2_UIE ;
if ( rv3032 - > rtc - > aie_timer . enabled )
ctrl | = RV3032_CTRL2_AIE ;
}
ret = regmap_update_bits ( rv3032 - > regmap , RV3032_STATUS ,
RV3032_STATUS_AF | RV3032_STATUS_UF , 0 ) ;
if ( ret )
return ret ;
ret = regmap_update_bits ( rv3032 - > regmap , RV3032_CTRL2 ,
RV3032_CTRL2_UIE | RV3032_CTRL2_AIE , ctrl ) ;
if ( ret )
return ret ;
return 0 ;
}
static int rv3032_read_offset ( struct device * dev , long * offset )
{
struct rv3032_data * rv3032 = dev_get_drvdata ( dev ) ;
int ret , value , steps ;
ret = regmap_read ( rv3032 - > regmap , RV3032_OFFSET , & value ) ;
if ( ret < 0 )
return ret ;
steps = sign_extend32 ( FIELD_GET ( RV3032_OFFSET_MSK , value ) , 5 ) ;
* offset = DIV_ROUND_CLOSEST ( steps * OFFSET_STEP_PPT , 1000 ) ;
return 0 ;
}
static int rv3032_set_offset ( struct device * dev , long offset )
{
struct rv3032_data * rv3032 = dev_get_drvdata ( dev ) ;
offset = clamp ( offset , - 7629L , 7391L ) * 1000 ;
offset = DIV_ROUND_CLOSEST ( offset , OFFSET_STEP_PPT ) ;
return rv3032_update_cfg ( rv3032 , RV3032_OFFSET , RV3032_OFFSET_MSK ,
FIELD_PREP ( RV3032_OFFSET_MSK , offset ) ) ;
}
2021-10-18 18:19:33 +03:00
static int rv3032_param_get ( struct device * dev , struct rtc_param * param )
{
struct rv3032_data * rv3032 = dev_get_drvdata ( dev ) ;
int ret ;
switch ( param - > param ) {
u32 value ;
case RTC_PARAM_BACKUP_SWITCH_MODE :
ret = regmap_read ( rv3032 - > regmap , RV3032_PMU , & value ) ;
if ( ret < 0 )
return ret ;
value = FIELD_GET ( RV3032_PMU_BSM , value ) ;
switch ( value ) {
case RV3032_PMU_BSM_DSM :
param - > uvalue = RTC_BSM_DIRECT ;
break ;
case RV3032_PMU_BSM_LSM :
param - > uvalue = RTC_BSM_LEVEL ;
break ;
default :
param - > uvalue = RTC_BSM_DISABLED ;
}
break ;
default :
return - EINVAL ;
}
return 0 ;
}
static int rv3032_param_set ( struct device * dev , struct rtc_param * param )
{
struct rv3032_data * rv3032 = dev_get_drvdata ( dev ) ;
switch ( param - > param ) {
u8 mode ;
case RTC_PARAM_BACKUP_SWITCH_MODE :
if ( rv3032 - > trickle_charger_set )
return - EINVAL ;
switch ( param - > uvalue ) {
case RTC_BSM_DISABLED :
mode = 0 ;
break ;
case RTC_BSM_DIRECT :
mode = RV3032_PMU_BSM_DSM ;
break ;
case RTC_BSM_LEVEL :
mode = RV3032_PMU_BSM_LSM ;
break ;
default :
return - EINVAL ;
}
return rv3032_update_cfg ( rv3032 , RV3032_PMU , RV3032_PMU_BSM ,
FIELD_PREP ( RV3032_PMU_BSM , mode ) ) ;
default :
return - EINVAL ;
}
return 0 ;
}
2020-10-13 17:41:10 +03:00
static int rv3032_ioctl ( struct device * dev , unsigned int cmd , unsigned long arg )
{
struct rv3032_data * rv3032 = dev_get_drvdata ( dev ) ;
int status , val = 0 , ret = 0 ;
switch ( cmd ) {
case RTC_VL_READ :
ret = regmap_read ( rv3032 - > regmap , RV3032_STATUS , & status ) ;
if ( ret < 0 )
return ret ;
if ( status & ( RV3032_STATUS_PORF | RV3032_STATUS_VLF ) )
val = RTC_VL_DATA_INVALID ;
return put_user ( val , ( unsigned int __user * ) arg ) ;
default :
return - ENOIOCTLCMD ;
}
}
static int rv3032_nvram_write ( void * priv , unsigned int offset , void * val , size_t bytes )
{
return regmap_bulk_write ( priv , RV3032_RAM1 + offset , val , bytes ) ;
}
static int rv3032_nvram_read ( void * priv , unsigned int offset , void * val , size_t bytes )
{
return regmap_bulk_read ( priv , RV3032_RAM1 + offset , val , bytes ) ;
}
static int rv3032_eeprom_write ( void * priv , unsigned int offset , void * val , size_t bytes )
{
struct rv3032_data * rv3032 = priv ;
u32 status , eerd ;
int i , ret ;
u8 * buf = val ;
ret = rv3032_enter_eerd ( rv3032 , & eerd ) ;
if ( ret )
return ret ;
for ( i = 0 ; i < bytes ; i + + ) {
ret = regmap_write ( rv3032 - > regmap , RV3032_EEPROM_ADDR ,
RV3032_EEPROM_USER + offset + i ) ;
if ( ret )
goto exit_eerd ;
ret = regmap_write ( rv3032 - > regmap , RV3032_EEPROM_DATA , buf [ i ] ) ;
if ( ret )
goto exit_eerd ;
ret = regmap_write ( rv3032 - > regmap , RV3032_EEPROM_CMD ,
RV3032_EEPROM_CMD_WRITE ) ;
if ( ret )
goto exit_eerd ;
usleep_range ( RV3032_EEBUSY_POLL , RV3032_EEBUSY_TIMEOUT ) ;
ret = regmap_read_poll_timeout ( rv3032 - > regmap , RV3032_TLSB , status ,
! ( status & RV3032_TLSB_EEBUSY ) ,
RV3032_EEBUSY_POLL , RV3032_EEBUSY_TIMEOUT ) ;
if ( ret )
goto exit_eerd ;
}
exit_eerd :
rv3032_exit_eerd ( rv3032 , eerd ) ;
return ret ;
}
static int rv3032_eeprom_read ( void * priv , unsigned int offset , void * val , size_t bytes )
{
struct rv3032_data * rv3032 = priv ;
u32 status , eerd , data ;
int i , ret ;
u8 * buf = val ;
ret = rv3032_enter_eerd ( rv3032 , & eerd ) ;
if ( ret )
return ret ;
for ( i = 0 ; i < bytes ; i + + ) {
ret = regmap_write ( rv3032 - > regmap , RV3032_EEPROM_ADDR ,
RV3032_EEPROM_USER + offset + i ) ;
if ( ret )
goto exit_eerd ;
ret = regmap_write ( rv3032 - > regmap , RV3032_EEPROM_CMD ,
RV3032_EEPROM_CMD_READ ) ;
if ( ret )
goto exit_eerd ;
ret = regmap_read_poll_timeout ( rv3032 - > regmap , RV3032_TLSB , status ,
! ( status & RV3032_TLSB_EEBUSY ) ,
RV3032_EEBUSY_POLL , RV3032_EEBUSY_TIMEOUT ) ;
if ( ret )
goto exit_eerd ;
ret = regmap_read ( rv3032 - > regmap , RV3032_EEPROM_DATA , & data ) ;
if ( ret )
goto exit_eerd ;
buf [ i ] = data ;
}
exit_eerd :
rv3032_exit_eerd ( rv3032 , eerd ) ;
return ret ;
}
static int rv3032_trickle_charger_setup ( struct device * dev , struct rv3032_data * rv3032 )
{
u32 val , ohms , voltage ;
int i ;
val = FIELD_PREP ( RV3032_PMU_TCM , 1 ) | FIELD_PREP ( RV3032_PMU_BSM , RV3032_PMU_BSM_DSM ) ;
if ( ! device_property_read_u32 ( dev , " trickle-voltage-millivolt " , & voltage ) ) {
for ( i = 0 ; i < ARRAY_SIZE ( rv3032_trickle_voltages ) ; i + + )
if ( voltage = = rv3032_trickle_voltages [ i ] )
break ;
if ( i < ARRAY_SIZE ( rv3032_trickle_voltages ) )
val = FIELD_PREP ( RV3032_PMU_TCM , i ) |
FIELD_PREP ( RV3032_PMU_BSM , RV3032_PMU_BSM_LSM ) ;
}
if ( device_property_read_u32 ( dev , " trickle-resistor-ohms " , & ohms ) )
return 0 ;
for ( i = 0 ; i < ARRAY_SIZE ( rv3032_trickle_resistors ) ; i + + )
if ( ohms = = rv3032_trickle_resistors [ i ] )
break ;
if ( i > = ARRAY_SIZE ( rv3032_trickle_resistors ) ) {
dev_warn ( dev , " invalid trickle resistor value \n " ) ;
return 0 ;
}
2021-10-18 18:19:33 +03:00
rv3032 - > trickle_charger_set = true ;
2020-10-13 17:41:10 +03:00
return rv3032_update_cfg ( rv3032 , RV3032_PMU ,
RV3032_PMU_TCR | RV3032_PMU_TCM | RV3032_PMU_BSM ,
val | FIELD_PREP ( RV3032_PMU_TCR , i ) ) ;
}
# ifdef CONFIG_COMMON_CLK
# define clkout_hw_to_rv3032(hw) container_of(hw, struct rv3032_data, clkout_hw)
static int clkout_xtal_rates [ ] = {
32768 ,
1024 ,
64 ,
1 ,
} ;
# define RV3032_HFD_STEP 8192
static unsigned long rv3032_clkout_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
int clkout , ret ;
struct rv3032_data * rv3032 = clkout_hw_to_rv3032 ( hw ) ;
ret = regmap_read ( rv3032 - > regmap , RV3032_CLKOUT2 , & clkout ) ;
if ( ret < 0 )
return 0 ;
if ( clkout & RV3032_CLKOUT2_OS ) {
unsigned long rate = FIELD_GET ( RV3032_CLKOUT2_HFD_MSK , clkout ) < < 8 ;
ret = regmap_read ( rv3032 - > regmap , RV3032_CLKOUT1 , & clkout ) ;
if ( ret < 0 )
return 0 ;
rate + = clkout + 1 ;
return rate * RV3032_HFD_STEP ;
}
return clkout_xtal_rates [ FIELD_GET ( RV3032_CLKOUT2_FD_MSK , clkout ) ] ;
}
static long rv3032_clkout_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
int i , hfd ;
if ( rate < RV3032_HFD_STEP )
for ( i = 0 ; i < ARRAY_SIZE ( clkout_xtal_rates ) ; i + + )
if ( clkout_xtal_rates [ i ] < = rate )
return clkout_xtal_rates [ i ] ;
hfd = DIV_ROUND_CLOSEST ( rate , RV3032_HFD_STEP ) ;
return RV3032_HFD_STEP * clamp ( hfd , 0 , 8192 ) ;
}
static int rv3032_clkout_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
struct rv3032_data * rv3032 = clkout_hw_to_rv3032 ( hw ) ;
u32 status , eerd ;
int i , hfd , ret ;
for ( i = 0 ; i < ARRAY_SIZE ( clkout_xtal_rates ) ; i + + ) {
if ( clkout_xtal_rates [ i ] = = rate ) {
return rv3032_update_cfg ( rv3032 , RV3032_CLKOUT2 , 0xff ,
FIELD_PREP ( RV3032_CLKOUT2_FD_MSK , i ) ) ;
}
}
hfd = DIV_ROUND_CLOSEST ( rate , RV3032_HFD_STEP ) ;
hfd = clamp ( hfd , 1 , 8192 ) - 1 ;
ret = rv3032_enter_eerd ( rv3032 , & eerd ) ;
if ( ret )
2021-10-12 13:10:28 +03:00
return ret ;
2020-10-13 17:41:10 +03:00
ret = regmap_write ( rv3032 - > regmap , RV3032_CLKOUT1 , hfd & 0xff ) ;
if ( ret )
2021-10-12 13:10:28 +03:00
goto exit_eerd ;
2020-10-13 17:41:10 +03:00
ret = regmap_write ( rv3032 - > regmap , RV3032_CLKOUT2 , RV3032_CLKOUT2_OS |
FIELD_PREP ( RV3032_CLKOUT2_HFD_MSK , hfd > > 8 ) ) ;
if ( ret )
goto exit_eerd ;
ret = regmap_write ( rv3032 - > regmap , RV3032_EEPROM_CMD , RV3032_EEPROM_CMD_UPDATE ) ;
if ( ret )
goto exit_eerd ;
usleep_range ( 46000 , RV3032_EEBUSY_TIMEOUT ) ;
ret = regmap_read_poll_timeout ( rv3032 - > regmap , RV3032_TLSB , status ,
! ( status & RV3032_TLSB_EEBUSY ) ,
RV3032_EEBUSY_POLL , RV3032_EEBUSY_TIMEOUT ) ;
exit_eerd :
rv3032_exit_eerd ( rv3032 , eerd ) ;
return ret ;
}
static int rv3032_clkout_prepare ( struct clk_hw * hw )
{
struct rv3032_data * rv3032 = clkout_hw_to_rv3032 ( hw ) ;
return rv3032_update_cfg ( rv3032 , RV3032_PMU , RV3032_PMU_NCLKE , 0 ) ;
}
static void rv3032_clkout_unprepare ( struct clk_hw * hw )
{
struct rv3032_data * rv3032 = clkout_hw_to_rv3032 ( hw ) ;
rv3032_update_cfg ( rv3032 , RV3032_PMU , RV3032_PMU_NCLKE , RV3032_PMU_NCLKE ) ;
}
static int rv3032_clkout_is_prepared ( struct clk_hw * hw )
{
int val , ret ;
struct rv3032_data * rv3032 = clkout_hw_to_rv3032 ( hw ) ;
ret = regmap_read ( rv3032 - > regmap , RV3032_PMU , & val ) ;
if ( ret < 0 )
return ret ;
return ! ( val & RV3032_PMU_NCLKE ) ;
}
static const struct clk_ops rv3032_clkout_ops = {
. prepare = rv3032_clkout_prepare ,
. unprepare = rv3032_clkout_unprepare ,
. is_prepared = rv3032_clkout_is_prepared ,
. recalc_rate = rv3032_clkout_recalc_rate ,
. round_rate = rv3032_clkout_round_rate ,
. set_rate = rv3032_clkout_set_rate ,
} ;
static int rv3032_clkout_register_clk ( struct rv3032_data * rv3032 ,
struct i2c_client * client )
{
int ret ;
struct clk * clk ;
struct clk_init_data init ;
struct device_node * node = client - > dev . of_node ;
ret = regmap_update_bits ( rv3032 - > regmap , RV3032_TLSB , RV3032_TLSB_CLKF , 0 ) ;
if ( ret < 0 )
return ret ;
ret = regmap_update_bits ( rv3032 - > regmap , RV3032_CTRL2 , RV3032_CTRL2_CLKIE , 0 ) ;
if ( ret < 0 )
return ret ;
ret = regmap_write ( rv3032 - > regmap , RV3032_CLK_IRQ , 0 ) ;
if ( ret < 0 )
return ret ;
init . name = " rv3032-clkout " ;
init . ops = & rv3032_clkout_ops ;
init . flags = 0 ;
init . parent_names = NULL ;
init . num_parents = 0 ;
rv3032 - > clkout_hw . init = & init ;
of_property_read_string ( node , " clock-output-names " , & init . name ) ;
clk = devm_clk_register ( & client - > dev , & rv3032 - > clkout_hw ) ;
if ( ! IS_ERR ( clk ) )
of_clk_add_provider ( node , of_clk_src_simple_get , clk ) ;
return 0 ;
}
# endif
static int rv3032_hwmon_read_temp ( struct device * dev , long * mC )
{
struct rv3032_data * rv3032 = dev_get_drvdata ( dev ) ;
u8 buf [ 2 ] ;
int temp , prev = 0 ;
int ret ;
ret = regmap_bulk_read ( rv3032 - > regmap , RV3032_TLSB , buf , sizeof ( buf ) ) ;
if ( ret )
return ret ;
temp = sign_extend32 ( buf [ 1 ] , 7 ) < < 4 ;
temp | = FIELD_GET ( RV3032_TLSB_TEMP , buf [ 0 ] ) ;
/* No blocking or shadowing on RV3032_TLSB and RV3032_TMSB */
do {
prev = temp ;
ret = regmap_bulk_read ( rv3032 - > regmap , RV3032_TLSB , buf , sizeof ( buf ) ) ;
if ( ret )
return ret ;
temp = sign_extend32 ( buf [ 1 ] , 7 ) < < 4 ;
temp | = FIELD_GET ( RV3032_TLSB_TEMP , buf [ 0 ] ) ;
} while ( temp ! = prev ) ;
* mC = ( temp * 1000 ) / 16 ;
return 0 ;
}
static umode_t rv3032_hwmon_is_visible ( const void * data , enum hwmon_sensor_types type ,
u32 attr , int channel )
{
if ( type ! = hwmon_temp )
return 0 ;
switch ( attr ) {
case hwmon_temp_input :
return 0444 ;
default :
return 0 ;
}
}
static int rv3032_hwmon_read ( struct device * dev , enum hwmon_sensor_types type ,
u32 attr , int channel , long * temp )
{
int err ;
switch ( attr ) {
case hwmon_temp_input :
err = rv3032_hwmon_read_temp ( dev , temp ) ;
break ;
default :
err = - EOPNOTSUPP ;
break ;
}
return err ;
}
static const struct hwmon_channel_info * rv3032_hwmon_info [ ] = {
HWMON_CHANNEL_INFO ( chip , HWMON_C_REGISTER_TZ ) ,
HWMON_CHANNEL_INFO ( temp , HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST ) ,
NULL
} ;
static const struct hwmon_ops rv3032_hwmon_hwmon_ops = {
. is_visible = rv3032_hwmon_is_visible ,
. read = rv3032_hwmon_read ,
} ;
static const struct hwmon_chip_info rv3032_hwmon_chip_info = {
. ops = & rv3032_hwmon_hwmon_ops ,
. info = rv3032_hwmon_info ,
} ;
static void rv3032_hwmon_register ( struct device * dev )
{
struct rv3032_data * rv3032 = dev_get_drvdata ( dev ) ;
if ( ! IS_REACHABLE ( CONFIG_HWMON ) )
return ;
devm_hwmon_device_register_with_info ( dev , " rv3032 " , rv3032 , & rv3032_hwmon_chip_info , NULL ) ;
}
2021-01-11 02:17:50 +03:00
static const struct rtc_class_ops rv3032_rtc_ops = {
2020-10-13 17:41:10 +03:00
. read_time = rv3032_get_time ,
. set_time = rv3032_set_time ,
. read_offset = rv3032_read_offset ,
. set_offset = rv3032_set_offset ,
. ioctl = rv3032_ioctl ,
2021-01-11 02:17:50 +03:00
. read_alarm = rv3032_get_alarm ,
. set_alarm = rv3032_set_alarm ,
. alarm_irq_enable = rv3032_alarm_irq_enable ,
2021-10-18 18:19:33 +03:00
. param_get = rv3032_param_get ,
. param_set = rv3032_param_set ,
2020-10-13 17:41:10 +03:00
} ;
static const struct regmap_config regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
. max_register = 0xCA ,
} ;
static int rv3032_probe ( struct i2c_client * client )
{
struct rv3032_data * rv3032 ;
int ret , status ;
struct nvmem_config nvmem_cfg = {
. name = " rv3032_nvram " ,
. word_size = 1 ,
. stride = 1 ,
. size = 16 ,
. type = NVMEM_TYPE_BATTERY_BACKED ,
. reg_read = rv3032_nvram_read ,
. reg_write = rv3032_nvram_write ,
} ;
struct nvmem_config eeprom_cfg = {
. name = " rv3032_eeprom " ,
. word_size = 1 ,
. stride = 1 ,
. size = 32 ,
. type = NVMEM_TYPE_EEPROM ,
. reg_read = rv3032_eeprom_read ,
. reg_write = rv3032_eeprom_write ,
} ;
rv3032 = devm_kzalloc ( & client - > dev , sizeof ( struct rv3032_data ) ,
GFP_KERNEL ) ;
if ( ! rv3032 )
return - ENOMEM ;
rv3032 - > regmap = devm_regmap_init_i2c ( client , & regmap_config ) ;
if ( IS_ERR ( rv3032 - > regmap ) )
return PTR_ERR ( rv3032 - > regmap ) ;
i2c_set_clientdata ( client , rv3032 ) ;
ret = regmap_read ( rv3032 - > regmap , RV3032_STATUS , & status ) ;
if ( ret < 0 )
return ret ;
rv3032 - > rtc = devm_rtc_allocate_device ( & client - > dev ) ;
if ( IS_ERR ( rv3032 - > rtc ) )
return PTR_ERR ( rv3032 - > rtc ) ;
if ( client - > irq > 0 ) {
ret = devm_request_threaded_irq ( & client - > dev , client - > irq ,
NULL , rv3032_handle_irq ,
IRQF_TRIGGER_LOW | IRQF_ONESHOT ,
" rv3032 " , rv3032 ) ;
if ( ret ) {
dev_warn ( & client - > dev , " unable to request IRQ, alarms disabled \n " ) ;
client - > irq = 0 ;
}
}
2021-01-11 02:17:50 +03:00
if ( ! client - > irq )
clear_bit ( RTC_FEATURE_ALARM , rv3032 - > rtc - > features ) ;
2020-10-13 17:41:10 +03:00
ret = regmap_update_bits ( rv3032 - > regmap , RV3032_CTRL1 ,
RV3032_CTRL1_WADA , RV3032_CTRL1_WADA ) ;
if ( ret )
return ret ;
rv3032_trickle_charger_setup ( & client - > dev , rv3032 ) ;
2021-10-18 18:19:33 +03:00
set_bit ( RTC_FEATURE_BACKUP_SWITCH_MODE , rv3032 - > rtc - > features ) ;
2021-11-08 01:54:48 +03:00
set_bit ( RTC_FEATURE_ALARM_RES_MINUTE , rv3032 - > rtc - > features ) ;
2021-10-18 18:19:33 +03:00
2020-10-13 17:41:10 +03:00
rv3032 - > rtc - > range_min = RTC_TIMESTAMP_BEGIN_2000 ;
rv3032 - > rtc - > range_max = RTC_TIMESTAMP_END_2099 ;
rv3032 - > rtc - > ops = & rv3032_rtc_ops ;
2020-11-09 19:34:08 +03:00
ret = devm_rtc_register_device ( rv3032 - > rtc ) ;
2020-10-13 17:41:10 +03:00
if ( ret )
return ret ;
2020-11-09 01:37:10 +03:00
nvmem_cfg . priv = rv3032 - > regmap ;
2020-11-09 19:34:06 +03:00
devm_rtc_nvmem_register ( rv3032 - > rtc , & nvmem_cfg ) ;
2020-10-13 17:41:10 +03:00
eeprom_cfg . priv = rv3032 ;
2020-11-09 19:34:06 +03:00
devm_rtc_nvmem_register ( rv3032 - > rtc , & eeprom_cfg ) ;
2020-10-13 17:41:10 +03:00
rv3032 - > rtc - > max_user_freq = 1 ;
# ifdef CONFIG_COMMON_CLK
rv3032_clkout_register_clk ( rv3032 , client ) ;
# endif
rv3032_hwmon_register ( & client - > dev ) ;
return 0 ;
}
2021-02-02 14:22:13 +03:00
static const __maybe_unused struct of_device_id rv3032_of_match [ ] = {
2020-10-13 17:41:10 +03:00
{ . compatible = " microcrystal,rv3032 " , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , rv3032_of_match ) ;
static struct i2c_driver rv3032_driver = {
. driver = {
. name = " rtc-rv3032 " ,
. of_match_table = of_match_ptr ( rv3032_of_match ) ,
} ,
. probe_new = rv3032_probe ,
} ;
module_i2c_driver ( rv3032_driver ) ;
MODULE_AUTHOR ( " Alexandre Belloni <alexandre.belloni@bootlin.com> " ) ;
MODULE_DESCRIPTION ( " Micro Crystal RV3032 RTC driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;