2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2006-03-27 13:16:42 +04:00
/*
* An i2c driver for the Xicor / Intersil X1205 RTC
* Copyright 2004 Karen Spearel
* Copyright 2005 Alessandro Zummo
*
* please send all reports to :
2013-07-04 02:06:07 +04:00
* Karen Spearel < kas111 at gmail dot com >
2006-03-27 13:16:42 +04:00
* Alessandro Zummo < a . zummo @ towertech . it >
*
* based on a lot of other RTC drivers .
*
2007-07-12 16:12:28 +04:00
* Information and datasheet :
* http : //www.intersil.com/cda/deviceinfo/0,1477,X1205,00.html
2006-03-27 13:16:42 +04:00
*/
# include <linux/i2c.h>
# include <linux/bcd.h>
# include <linux/rtc.h>
# include <linux/delay.h>
2011-05-27 17:57:25 +04:00
# include <linux/module.h>
2015-04-16 22:45:09 +03:00
# include <linux/bitops.h>
2006-03-27 13:16:42 +04:00
/* offsets into CCR area */
# define CCR_SEC 0
# define CCR_MIN 1
# define CCR_HOUR 2
# define CCR_MDAY 3
# define CCR_MONTH 4
# define CCR_YEAR 5
# define CCR_WDAY 6
# define CCR_Y2K 7
# define X1205_REG_SR 0x3F /* status register */
# define X1205_REG_Y2K 0x37
# define X1205_REG_DW 0x36
# define X1205_REG_YR 0x35
# define X1205_REG_MO 0x34
# define X1205_REG_DT 0x33
# define X1205_REG_HR 0x32
# define X1205_REG_MN 0x31
# define X1205_REG_SC 0x30
# define X1205_REG_DTR 0x13
# define X1205_REG_ATR 0x12
# define X1205_REG_INT 0x11
# define X1205_REG_0 0x10
# define X1205_REG_Y2K1 0x0F
# define X1205_REG_DWA1 0x0E
# define X1205_REG_YRA1 0x0D
# define X1205_REG_MOA1 0x0C
# define X1205_REG_DTA1 0x0B
# define X1205_REG_HRA1 0x0A
# define X1205_REG_MNA1 0x09
# define X1205_REG_SCA1 0x08
# define X1205_REG_Y2K0 0x07
# define X1205_REG_DWA0 0x06
# define X1205_REG_YRA0 0x05
# define X1205_REG_MOA0 0x04
# define X1205_REG_DTA0 0x03
# define X1205_REG_HRA0 0x02
# define X1205_REG_MNA0 0x01
# define X1205_REG_SCA0 0x00
# define X1205_CCR_BASE 0x30 /* Base address of CCR */
# define X1205_ALM0_BASE 0x00 /* Base address of ALARM0 */
# define X1205_SR_RTCF 0x01 /* Clock failure */
# define X1205_SR_WEL 0x02 /* Write Enable Latch */
# define X1205_SR_RWEL 0x04 /* Register Write Enable */
2008-07-04 20:59:30 +04:00
# define X1205_SR_AL0 0x20 /* Alarm 0 match */
2006-03-27 13:16:42 +04:00
# define X1205_DTR_DTR0 0x01
# define X1205_DTR_DTR1 0x02
# define X1205_DTR_DTR2 0x04
# define X1205_HR_MIL 0x80 /* Set in ccr.hour for 24 hr mode */
2008-07-04 20:59:30 +04:00
# define X1205_INT_AL0E 0x20 /* Alarm 0 enable */
2008-04-28 13:11:54 +04:00
static struct i2c_driver x1205_driver ;
2006-03-27 13:16:42 +04:00
/*
* In the routines that deal directly with the x1205 hardware , we use
* rtc_time - - month 0 - 11 , hour 0 - 23 , yr = calendar year - epoch
* Epoch is initialized as 2000. Time is set to UTC .
*/
static int x1205_get_datetime ( struct i2c_client * client , struct rtc_time * tm ,
unsigned char reg_base )
{
unsigned char dt_addr [ 2 ] = { 0 , reg_base } ;
unsigned char buf [ 8 ] ;
2008-07-04 20:59:30 +04:00
int i ;
2006-03-27 13:16:42 +04:00
struct i2c_msg msgs [ ] = {
2012-10-05 04:14:18 +04:00
{ /* setup read ptr */
. addr = client - > addr ,
. len = 2 ,
. buf = dt_addr
} ,
{ /* read date */
. addr = client - > addr ,
. flags = I2C_M_RD ,
. len = 8 ,
. buf = buf
} ,
2006-03-27 13:16:42 +04:00
} ;
/* read date registers */
2008-07-04 20:59:30 +04:00
if ( i2c_transfer ( client - > adapter , & msgs [ 0 ] , 2 ) ! = 2 ) {
2008-04-28 13:12:00 +04:00
dev_err ( & client - > dev , " %s: read error \n " , __func__ ) ;
2006-03-27 13:16:42 +04:00
return - EIO ;
}
dev_dbg ( & client - > dev ,
" %s: raw read data - sec=%02x, min=%02x, hr=%02x, "
" mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x \n " ,
2008-04-28 13:12:00 +04:00
__func__ ,
2006-03-27 13:16:42 +04:00
buf [ 0 ] , buf [ 1 ] , buf [ 2 ] , buf [ 3 ] ,
buf [ 4 ] , buf [ 5 ] , buf [ 6 ] , buf [ 7 ] ) ;
2008-07-04 20:59:30 +04:00
/* Mask out the enable bits if these are alarm registers */
if ( reg_base < X1205_CCR_BASE )
for ( i = 0 ; i < = 4 ; i + + )
buf [ i ] & = 0x7F ;
2008-10-19 07:28:41 +04:00
tm - > tm_sec = bcd2bin ( buf [ CCR_SEC ] ) ;
tm - > tm_min = bcd2bin ( buf [ CCR_MIN ] ) ;
tm - > tm_hour = bcd2bin ( buf [ CCR_HOUR ] & 0x3F ) ; /* hr is 0-23 */
tm - > tm_mday = bcd2bin ( buf [ CCR_MDAY ] ) ;
tm - > tm_mon = bcd2bin ( buf [ CCR_MONTH ] ) - 1 ; /* mon is 0-11 */
tm - > tm_year = bcd2bin ( buf [ CCR_YEAR ] )
+ ( bcd2bin ( buf [ CCR_Y2K ] ) * 100 ) - 1900 ;
2006-03-27 13:16:42 +04:00
tm - > tm_wday = buf [ CCR_WDAY ] ;
dev_dbg ( & client - > dev , " %s: tm is secs=%d, mins=%d, hours=%d, "
" mday=%d, mon=%d, year=%d, wday=%d \n " ,
2008-04-28 13:12:00 +04:00
__func__ ,
2006-03-27 13:16:42 +04:00
tm - > tm_sec , tm - > tm_min , tm - > tm_hour ,
tm - > tm_mday , tm - > tm_mon , tm - > tm_year , tm - > tm_wday ) ;
return 0 ;
}
static int x1205_get_status ( struct i2c_client * client , unsigned char * sr )
{
static unsigned char sr_addr [ 2 ] = { 0 , X1205_REG_SR } ;
struct i2c_msg msgs [ ] = {
2012-10-05 04:14:18 +04:00
{ /* setup read ptr */
. addr = client - > addr ,
. len = 2 ,
. buf = sr_addr
} ,
{ /* read status */
. addr = client - > addr ,
. flags = I2C_M_RD ,
. len = 1 ,
. buf = sr
} ,
2006-03-27 13:16:42 +04:00
} ;
/* read status register */
2008-07-04 20:59:30 +04:00
if ( i2c_transfer ( client - > adapter , & msgs [ 0 ] , 2 ) ! = 2 ) {
2008-04-28 13:12:00 +04:00
dev_err ( & client - > dev , " %s: read error \n " , __func__ ) ;
2006-03-27 13:16:42 +04:00
return - EIO ;
}
return 0 ;
}
static int x1205_set_datetime ( struct i2c_client * client , struct rtc_time * tm ,
2009-12-16 03:46:16 +03:00
u8 reg_base , unsigned char alm_enable )
2006-03-27 13:16:42 +04:00
{
2009-12-16 03:46:16 +03:00
int i , xfer ;
2008-07-04 20:59:30 +04:00
unsigned char rdata [ 10 ] = { 0 , reg_base } ;
2009-12-16 03:46:16 +03:00
unsigned char * buf = rdata + 2 ;
2006-03-27 13:16:42 +04:00
static const unsigned char wel [ 3 ] = { 0 , X1205_REG_SR ,
X1205_SR_WEL } ;
static const unsigned char rwel [ 3 ] = { 0 , X1205_REG_SR ,
X1205_SR_WEL | X1205_SR_RWEL } ;
static const unsigned char diswe [ 3 ] = { 0 , X1205_REG_SR , 0 } ;
dev_dbg ( & client - > dev ,
2009-12-16 03:46:16 +03:00
" %s: sec=%d min=%d hour=%d mday=%d mon=%d year=%d wday=%d \n " ,
__func__ , tm - > tm_sec , tm - > tm_min , tm - > tm_hour , tm - > tm_mday ,
tm - > tm_mon , tm - > tm_year , tm - > tm_wday ) ;
2006-03-27 13:16:42 +04:00
2008-10-19 07:28:41 +04:00
buf [ CCR_SEC ] = bin2bcd ( tm - > tm_sec ) ;
buf [ CCR_MIN ] = bin2bcd ( tm - > tm_min ) ;
2006-03-27 13:16:42 +04:00
/* set hour and 24hr bit */
2008-10-19 07:28:41 +04:00
buf [ CCR_HOUR ] = bin2bcd ( tm - > tm_hour ) | X1205_HR_MIL ;
2006-03-27 13:16:42 +04:00
2009-12-16 03:46:16 +03:00
buf [ CCR_MDAY ] = bin2bcd ( tm - > tm_mday ) ;
2006-03-27 13:16:42 +04:00
2009-12-16 03:46:16 +03:00
/* month, 1 - 12 */
buf [ CCR_MONTH ] = bin2bcd ( tm - > tm_mon + 1 ) ;
2006-03-27 13:16:42 +04:00
2009-12-16 03:46:16 +03:00
/* year, since the rtc epoch*/
buf [ CCR_YEAR ] = bin2bcd ( tm - > tm_year % 100 ) ;
buf [ CCR_WDAY ] = tm - > tm_wday & 0x07 ;
buf [ CCR_Y2K ] = bin2bcd ( ( tm - > tm_year + 1900 ) / 100 ) ;
2006-03-27 13:16:42 +04:00
2008-07-04 20:59:30 +04:00
/* If writing alarm registers, set compare bits on registers 0-4 */
if ( reg_base < X1205_CCR_BASE )
for ( i = 0 ; i < = 4 ; i + + )
buf [ i ] | = 0x80 ;
2006-03-27 13:16:42 +04:00
/* this sequence is required to unlock the chip */
2013-07-04 02:06:07 +04:00
xfer = i2c_master_send ( client , wel , 3 ) ;
if ( xfer ! = 3 ) {
2008-04-28 13:12:00 +04:00
dev_err ( & client - > dev , " %s: wel - %d \n " , __func__ , xfer ) ;
2006-03-27 13:16:42 +04:00
return - EIO ;
}
2013-07-04 02:06:07 +04:00
xfer = i2c_master_send ( client , rwel , 3 ) ;
if ( xfer ! = 3 ) {
2008-04-28 13:12:00 +04:00
dev_err ( & client - > dev , " %s: rwel - %d \n " , __func__ , xfer ) ;
2006-03-27 13:16:42 +04:00
return - EIO ;
}
2009-12-16 03:46:16 +03:00
xfer = i2c_master_send ( client , rdata , sizeof ( rdata ) ) ;
if ( xfer ! = sizeof ( rdata ) ) {
2008-07-04 20:59:30 +04:00
dev_err ( & client - > dev ,
" %s: result=%d addr=%02x, data=%02x \n " ,
__func__ ,
xfer , rdata [ 1 ] , rdata [ 2 ] ) ;
return - EIO ;
}
/* If we wrote to the nonvolatile region, wait 10msec for write cycle*/
if ( reg_base < X1205_CCR_BASE ) {
unsigned char al0e [ 3 ] = { 0 , X1205_REG_INT , 0 } ;
msleep ( 10 ) ;
/* ...and set or clear the AL0E bit in the INT register */
2006-03-27 13:16:42 +04:00
2008-07-04 20:59:30 +04:00
/* Need to set RWEL again as the write has cleared it */
xfer = i2c_master_send ( client , rwel , 3 ) ;
2006-03-27 13:16:42 +04:00
if ( xfer ! = 3 ) {
dev_err ( & client - > dev ,
2008-07-04 20:59:30 +04:00
" %s: aloe rwel - %d \n " ,
2008-04-28 13:12:00 +04:00
__func__ ,
2008-07-04 20:59:30 +04:00
xfer ) ;
return - EIO ;
}
if ( alm_enable )
al0e [ 2 ] = X1205_INT_AL0E ;
xfer = i2c_master_send ( client , al0e , 3 ) ;
if ( xfer ! = 3 ) {
dev_err ( & client - > dev ,
" %s: al0e - %d \n " ,
__func__ ,
xfer ) ;
2006-03-27 13:16:42 +04:00
return - EIO ;
}
2008-07-04 20:59:30 +04:00
/* and wait 10msec again for this write to complete */
msleep ( 10 ) ;
}
2006-03-27 13:16:42 +04:00
/* disable further writes */
2013-07-04 02:06:07 +04:00
xfer = i2c_master_send ( client , diswe , 3 ) ;
if ( xfer ! = 3 ) {
2008-04-28 13:12:00 +04:00
dev_err ( & client - > dev , " %s: diswe - %d \n " , __func__ , xfer ) ;
2006-03-27 13:16:42 +04:00
return - EIO ;
}
return 0 ;
}
static int x1205_fix_osc ( struct i2c_client * client )
{
int err ;
struct rtc_time tm ;
2009-12-02 00:17:49 +03:00
memset ( & tm , 0 , sizeof ( tm ) ) ;
2006-03-27 13:16:42 +04:00
2009-12-16 03:46:16 +03:00
err = x1205_set_datetime ( client , & tm , X1205_CCR_BASE , 0 ) ;
2008-07-04 20:59:30 +04:00
if ( err < 0 )
dev_err ( & client - > dev , " unable to restart the oscillator \n " ) ;
2006-03-27 13:16:42 +04:00
return err ;
}
static int x1205_get_dtrim ( struct i2c_client * client , int * trim )
{
unsigned char dtr ;
static unsigned char dtr_addr [ 2 ] = { 0 , X1205_REG_DTR } ;
struct i2c_msg msgs [ ] = {
2012-10-05 04:14:18 +04:00
{ /* setup read ptr */
. addr = client - > addr ,
. len = 2 ,
. buf = dtr_addr
} ,
{ /* read dtr */
. addr = client - > addr ,
. flags = I2C_M_RD ,
. len = 1 ,
. buf = & dtr
} ,
2006-03-27 13:16:42 +04:00
} ;
/* read dtr register */
2008-07-04 20:59:30 +04:00
if ( i2c_transfer ( client - > adapter , & msgs [ 0 ] , 2 ) ! = 2 ) {
2008-04-28 13:12:00 +04:00
dev_err ( & client - > dev , " %s: read error \n " , __func__ ) ;
2006-03-27 13:16:42 +04:00
return - EIO ;
}
2008-04-28 13:12:00 +04:00
dev_dbg ( & client - > dev , " %s: raw dtr=%x \n " , __func__ , dtr ) ;
2006-03-27 13:16:42 +04:00
* trim = 0 ;
if ( dtr & X1205_DTR_DTR0 )
* trim + = 20 ;
if ( dtr & X1205_DTR_DTR1 )
* trim + = 10 ;
if ( dtr & X1205_DTR_DTR2 )
* trim = - * trim ;
return 0 ;
}
static int x1205_get_atrim ( struct i2c_client * client , int * trim )
{
s8 atr ;
static unsigned char atr_addr [ 2 ] = { 0 , X1205_REG_ATR } ;
struct i2c_msg msgs [ ] = {
2012-10-05 04:14:18 +04:00
{ /* setup read ptr */
. addr = client - > addr ,
. len = 2 ,
. buf = atr_addr
} ,
{ /* read atr */
. addr = client - > addr ,
. flags = I2C_M_RD ,
. len = 1 ,
. buf = & atr
} ,
2006-03-27 13:16:42 +04:00
} ;
/* read atr register */
2008-07-04 20:59:30 +04:00
if ( i2c_transfer ( client - > adapter , & msgs [ 0 ] , 2 ) ! = 2 ) {
2008-04-28 13:12:00 +04:00
dev_err ( & client - > dev , " %s: read error \n " , __func__ ) ;
2006-03-27 13:16:42 +04:00
return - EIO ;
}
2008-04-28 13:12:00 +04:00
dev_dbg ( & client - > dev , " %s: raw atr=%x \n " , __func__ , atr ) ;
2006-03-27 13:16:42 +04:00
/* atr is a two's complement value on 6 bits,
* perform sign extension . The formula is
* Catr = ( atr * 0.25 pF ) + 11.00 pF .
*/
2015-04-16 22:45:09 +03:00
atr = sign_extend32 ( atr , 5 ) ;
2006-03-27 13:16:42 +04:00
2008-04-28 13:12:00 +04:00
dev_dbg ( & client - > dev , " %s: raw atr=%x (%d) \n " , __func__ , atr , atr ) ;
2006-03-27 13:16:42 +04:00
* trim = ( atr * 250 ) + 11000 ;
2008-04-28 13:12:00 +04:00
dev_dbg ( & client - > dev , " %s: real=%d \n " , __func__ , * trim ) ;
2006-03-27 13:16:42 +04:00
return 0 ;
}
2013-07-04 02:06:07 +04:00
struct x1205_limit {
2006-03-27 13:16:42 +04:00
unsigned char reg , mask , min , max ;
} ;
static int x1205_validate_client ( struct i2c_client * client )
{
int i , xfer ;
/* Probe array. We will read the register at the specified
* address and check if the given bits are zero .
*/
static const unsigned char probe_zero_pattern [ ] = {
/* register, mask */
X1205_REG_SR , 0x18 ,
X1205_REG_DTR , 0xF8 ,
X1205_REG_ATR , 0xC0 ,
X1205_REG_INT , 0x18 ,
X1205_REG_0 , 0xFF ,
} ;
static const struct x1205_limit probe_limits_pattern [ ] = {
/* register, mask, min, max */
{ X1205_REG_Y2K , 0xFF , 19 , 20 } ,
{ X1205_REG_DW , 0xFF , 0 , 6 } ,
{ X1205_REG_YR , 0xFF , 0 , 99 } ,
{ X1205_REG_MO , 0xFF , 0 , 12 } ,
{ X1205_REG_DT , 0xFF , 0 , 31 } ,
{ X1205_REG_HR , 0x7F , 0 , 23 } ,
{ X1205_REG_MN , 0xFF , 0 , 59 } ,
{ X1205_REG_SC , 0xFF , 0 , 59 } ,
{ X1205_REG_Y2K1 , 0xFF , 19 , 20 } ,
{ X1205_REG_Y2K0 , 0xFF , 19 , 20 } ,
} ;
/* check that registers have bits a 0 where expected */
for ( i = 0 ; i < ARRAY_SIZE ( probe_zero_pattern ) ; i + = 2 ) {
unsigned char buf ;
unsigned char addr [ 2 ] = { 0 , probe_zero_pattern [ i ] } ;
struct i2c_msg msgs [ 2 ] = {
2012-10-05 04:14:18 +04:00
{
. addr = client - > addr ,
. len = 2 ,
. buf = addr
} ,
{
. addr = client - > addr ,
. flags = I2C_M_RD ,
. len = 1 ,
. buf = & buf
} ,
2006-03-27 13:16:42 +04:00
} ;
2013-07-04 02:06:07 +04:00
xfer = i2c_transfer ( client - > adapter , msgs , 2 ) ;
if ( xfer ! = 2 ) {
2006-12-10 13:19:02 +03:00
dev_err ( & client - > dev ,
2006-03-27 13:16:42 +04:00
" %s: could not read register %x \n " ,
2008-04-28 13:12:00 +04:00
__func__ , probe_zero_pattern [ i ] ) ;
2006-03-27 13:16:42 +04:00
return - EIO ;
}
if ( ( buf & probe_zero_pattern [ i + 1 ] ) ! = 0 ) {
2006-12-10 13:19:02 +03:00
dev_err ( & client - > dev ,
2006-03-27 13:16:42 +04:00
" %s: register=%02x, zero pattern=%d, value=%x \n " ,
2008-04-28 13:12:00 +04:00
__func__ , probe_zero_pattern [ i ] , i , buf ) ;
2006-03-27 13:16:42 +04:00
return - ENODEV ;
}
}
/* check limits (only registers with bcd values) */
for ( i = 0 ; i < ARRAY_SIZE ( probe_limits_pattern ) ; i + + ) {
unsigned char reg , value ;
unsigned char addr [ 2 ] = { 0 , probe_limits_pattern [ i ] . reg } ;
struct i2c_msg msgs [ 2 ] = {
2012-10-05 04:14:18 +04:00
{
. addr = client - > addr ,
. len = 2 ,
. buf = addr
} ,
{
. addr = client - > addr ,
. flags = I2C_M_RD ,
. len = 1 ,
. buf = & reg
} ,
2006-03-27 13:16:42 +04:00
} ;
2013-07-04 02:06:07 +04:00
xfer = i2c_transfer ( client - > adapter , msgs , 2 ) ;
if ( xfer ! = 2 ) {
2006-12-10 13:19:02 +03:00
dev_err ( & client - > dev ,
2006-03-27 13:16:42 +04:00
" %s: could not read register %x \n " ,
2008-04-28 13:12:00 +04:00
__func__ , probe_limits_pattern [ i ] . reg ) ;
2006-03-27 13:16:42 +04:00
return - EIO ;
}
2008-10-19 07:28:41 +04:00
value = bcd2bin ( reg & probe_limits_pattern [ i ] . mask ) ;
2006-03-27 13:16:42 +04:00
if ( value > probe_limits_pattern [ i ] . max | |
value < probe_limits_pattern [ i ] . min ) {
2006-12-10 13:19:02 +03:00
dev_dbg ( & client - > dev ,
2006-03-27 13:16:42 +04:00
" %s: register=%x, lim pattern=%d, value=%d \n " ,
2008-04-28 13:12:00 +04:00
__func__ , probe_limits_pattern [ i ] . reg ,
2006-03-27 13:16:42 +04:00
i , value ) ;
return - ENODEV ;
}
}
return 0 ;
}
static int x1205_rtc_read_alarm ( struct device * dev , struct rtc_wkalrm * alrm )
{
2008-07-04 20:59:30 +04:00
int err ;
unsigned char intreg , status ;
static unsigned char int_addr [ 2 ] = { 0 , X1205_REG_INT } ;
struct i2c_client * client = to_i2c_client ( dev ) ;
struct i2c_msg msgs [ ] = {
2012-10-05 04:14:18 +04:00
{ /* setup read ptr */
. addr = client - > addr ,
. len = 2 ,
. buf = int_addr
} ,
{ /* read INT register */
. addr = client - > addr ,
. flags = I2C_M_RD ,
. len = 1 ,
. buf = & intreg
} ,
2008-07-04 20:59:30 +04:00
} ;
/* read interrupt register and status register */
if ( i2c_transfer ( client - > adapter , & msgs [ 0 ] , 2 ) ! = 2 ) {
dev_err ( & client - > dev , " %s: read error \n " , __func__ ) ;
return - EIO ;
}
err = x1205_get_status ( client , & status ) ;
if ( err = = 0 ) {
alrm - > pending = ( status & X1205_SR_AL0 ) ? 1 : 0 ;
alrm - > enabled = ( intreg & X1205_INT_AL0E ) ? 1 : 0 ;
err = x1205_get_datetime ( client , & alrm - > time , X1205_ALM0_BASE ) ;
}
return err ;
2006-03-27 13:16:42 +04:00
}
static int x1205_rtc_set_alarm ( struct device * dev , struct rtc_wkalrm * alrm )
{
return x1205_set_datetime ( to_i2c_client ( dev ) ,
2009-12-16 03:46:16 +03:00
& alrm - > time , X1205_ALM0_BASE , alrm - > enabled ) ;
2006-03-27 13:16:42 +04:00
}
static int x1205_rtc_read_time ( struct device * dev , struct rtc_time * tm )
{
return x1205_get_datetime ( to_i2c_client ( dev ) ,
tm , X1205_CCR_BASE ) ;
}
static int x1205_rtc_set_time ( struct device * dev , struct rtc_time * tm )
{
return x1205_set_datetime ( to_i2c_client ( dev ) ,
2009-12-16 03:46:16 +03:00
tm , X1205_CCR_BASE , 0 ) ;
2006-03-27 13:16:42 +04:00
}
static int x1205_rtc_proc ( struct device * dev , struct seq_file * seq )
{
int err , dtrim , atrim ;
2013-07-04 02:06:07 +04:00
err = x1205_get_dtrim ( to_i2c_client ( dev ) , & dtrim ) ;
if ( ! err )
2006-03-27 13:16:42 +04:00
seq_printf ( seq , " digital_trim \t : %d ppm \n " , dtrim ) ;
2013-07-04 02:06:07 +04:00
err = x1205_get_atrim ( to_i2c_client ( dev ) , & atrim ) ;
if ( ! err )
2006-03-27 13:16:42 +04:00
seq_printf ( seq , " analog_trim \t : %d.%02d pF \n " ,
atrim / 1000 , atrim % 1000 ) ;
return 0 ;
}
2006-10-01 10:28:17 +04:00
static const struct rtc_class_ops x1205_rtc_ops = {
2006-03-27 13:16:42 +04:00
. proc = x1205_rtc_proc ,
. read_time = x1205_rtc_read_time ,
. set_time = x1205_rtc_set_time ,
. read_alarm = x1205_rtc_read_alarm ,
. set_alarm = x1205_rtc_set_alarm ,
} ;
static ssize_t x1205_sysfs_show_atrim ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
2006-04-11 09:54:42 +04:00
int err , atrim ;
2006-03-27 13:16:42 +04:00
2006-04-11 09:54:42 +04:00
err = x1205_get_atrim ( to_i2c_client ( dev ) , & atrim ) ;
if ( err )
return err ;
return sprintf ( buf , " %d.%02d pF \n " , atrim / 1000 , atrim % 1000 ) ;
2006-03-27 13:16:42 +04:00
}
static DEVICE_ATTR ( atrim , S_IRUGO , x1205_sysfs_show_atrim , NULL ) ;
static ssize_t x1205_sysfs_show_dtrim ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
2006-04-11 09:54:42 +04:00
int err , dtrim ;
2006-03-27 13:16:42 +04:00
2006-04-11 09:54:42 +04:00
err = x1205_get_dtrim ( to_i2c_client ( dev ) , & dtrim ) ;
if ( err )
return err ;
2006-03-27 13:16:42 +04:00
2006-04-11 09:54:42 +04:00
return sprintf ( buf , " %d ppm \n " , dtrim ) ;
2006-03-27 13:16:42 +04:00
}
static DEVICE_ATTR ( dtrim , S_IRUGO , x1205_sysfs_show_dtrim , NULL ) ;
2008-04-28 13:11:54 +04:00
static int x1205_sysfs_register ( struct device * dev )
{
int err ;
err = device_create_file ( dev , & dev_attr_atrim ) ;
if ( err )
return err ;
err = device_create_file ( dev , & dev_attr_dtrim ) ;
if ( err )
device_remove_file ( dev , & dev_attr_atrim ) ;
return err ;
}
static void x1205_sysfs_unregister ( struct device * dev )
2006-03-27 13:16:42 +04:00
{
2008-04-28 13:11:54 +04:00
device_remove_file ( dev , & dev_attr_atrim ) ;
device_remove_file ( dev , & dev_attr_dtrim ) ;
2006-03-27 13:16:42 +04:00
}
2008-04-28 13:11:54 +04:00
2008-04-30 01:11:39 +04:00
static int x1205_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
2006-03-27 13:16:42 +04:00
{
int err = 0 ;
unsigned char sr ;
struct rtc_device * rtc ;
2008-04-28 13:11:54 +04:00
dev_dbg ( & client - > dev , " %s \n " , __func__ ) ;
2006-03-27 13:16:42 +04:00
2008-04-28 13:11:54 +04:00
if ( ! i2c_check_functionality ( client - > adapter , I2C_FUNC_I2C ) )
return - ENODEV ;
2006-03-27 13:16:42 +04:00
2008-04-28 13:11:54 +04:00
if ( x1205_validate_client ( client ) < 0 )
return - ENODEV ;
2006-03-27 13:16:42 +04:00
2013-04-30 03:19:55 +04:00
rtc = devm_rtc_device_register ( & client - > dev , x1205_driver . driver . name ,
& x1205_rtc_ops , THIS_MODULE ) ;
2006-03-27 13:16:42 +04:00
2008-04-28 13:11:54 +04:00
if ( IS_ERR ( rtc ) )
return PTR_ERR ( rtc ) ;
2006-03-27 13:16:42 +04:00
i2c_set_clientdata ( client , rtc ) ;
2011-03-31 05:57:33 +04:00
/* Check for power failures and eventually enable the osc */
2013-07-04 02:06:07 +04:00
err = x1205_get_status ( client , & sr ) ;
if ( ! err ) {
2006-03-27 13:16:42 +04:00
if ( sr & X1205_SR_RTCF ) {
dev_err ( & client - > dev ,
" power failure detected, "
" please set the clock \n " ) ;
udelay ( 50 ) ;
x1205_fix_osc ( client ) ;
}
2013-07-04 02:06:07 +04:00
} else {
2006-03-27 13:16:42 +04:00
dev_err ( & client - > dev , " couldn't read status \n " ) ;
2013-07-04 02:06:07 +04:00
}
2006-03-27 13:16:42 +04:00
2008-04-28 13:11:54 +04:00
err = x1205_sysfs_register ( & client - > dev ) ;
if ( err )
2014-04-04 01:49:36 +04:00
dev_err ( & client - > dev , " Unable to create sysfs entries \n " ) ;
2006-03-27 13:16:42 +04:00
return 0 ;
}
2008-04-28 13:11:54 +04:00
static int x1205_remove ( struct i2c_client * client )
2006-03-27 13:16:42 +04:00
{
2008-04-28 13:11:54 +04:00
x1205_sysfs_unregister ( & client - > dev ) ;
2006-03-27 13:16:42 +04:00
return 0 ;
}
2008-04-30 01:11:40 +04:00
static const struct i2c_device_id x1205_id [ ] = {
{ " x1205 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , x1205_id ) ;
2019-03-19 10:40:14 +03:00
static const struct of_device_id x1205_dt_ids [ ] = {
{ . compatible = " xircom,x1205 " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , x1205_dt_ids ) ;
2008-04-28 13:11:54 +04:00
static struct i2c_driver x1205_driver = {
. driver = {
. name = " rtc-x1205 " ,
2019-03-19 10:40:14 +03:00
. of_match_table = x1205_dt_ids ,
2008-04-28 13:11:54 +04:00
} ,
. probe = x1205_probe ,
. remove = x1205_remove ,
2008-04-30 01:11:40 +04:00
. id_table = x1205_id ,
2008-04-28 13:11:54 +04:00
} ;
2012-03-24 02:02:31 +04:00
module_i2c_driver ( x1205_driver ) ;
2006-03-27 13:16:42 +04:00
MODULE_AUTHOR (
" Karen Spearel <kas111 at gmail dot com>, "
" Alessandro Zummo <a.zummo@towertech.it> " ) ;
MODULE_DESCRIPTION ( " Xicor/Intersil X1205 RTC driver " ) ;
MODULE_LICENSE ( " GPL " ) ;