2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2010-08-10 18:02:14 -07:00
/*
* An I2C driver for the Intersil ISL 12022
*
* Author : Roman Fietze < roman . fietze @ telemotive . de >
*
* Based on the Philips PCF8563 RTC
* by Alessandro Zummo < a . zummo @ towertech . it > .
*/
# include <linux/i2c.h>
# include <linux/bcd.h>
# include <linux/rtc.h>
# include <linux/slab.h>
2011-05-27 09:57:25 -04:00
# include <linux/module.h>
2013-07-03 15:07:49 -07:00
# include <linux/err.h>
2014-08-08 14:20:20 -07:00
# include <linux/of.h>
# include <linux/of_device.h>
2022-09-21 13:46:23 +02:00
# include <linux/regmap.h>
2010-08-10 18:02:14 -07:00
/* ISL register offsets */
# define ISL12022_REG_SC 0x00
# define ISL12022_REG_MN 0x01
# define ISL12022_REG_HR 0x02
# define ISL12022_REG_DT 0x03
# define ISL12022_REG_MO 0x04
# define ISL12022_REG_YR 0x05
# define ISL12022_REG_DW 0x06
# define ISL12022_REG_SR 0x07
# define ISL12022_REG_INT 0x08
/* ISL register bits */
# define ISL12022_HR_MIL (1 << 7) /* military or 24 hour time */
# define ISL12022_SR_LBAT85 (1 << 2)
# define ISL12022_SR_LBAT75 (1 << 1)
# define ISL12022_INT_WRTC (1 << 6)
static struct i2c_driver isl12022_driver ;
struct isl12022 {
struct rtc_device * rtc ;
2022-09-21 13:46:23 +02:00
struct regmap * regmap ;
2010-08-10 18:02:14 -07:00
} ;
/*
* In the routines that deal directly with the isl12022 hardware , we use
* rtc_time - - month 0 - 11 , hour 0 - 23 , yr = calendar year - epoch .
*/
2018-02-20 23:55:40 +01:00
static int isl12022_rtc_read_time ( struct device * dev , struct rtc_time * tm )
2010-08-10 18:02:14 -07:00
{
2022-09-21 13:46:23 +02:00
struct isl12022 * isl12022 = dev_get_drvdata ( dev ) ;
struct regmap * regmap = isl12022 - > regmap ;
2010-08-10 18:02:14 -07:00
uint8_t buf [ ISL12022_REG_INT + 1 ] ;
int ret ;
2022-09-21 13:46:23 +02:00
ret = regmap_bulk_read ( regmap , ISL12022_REG_SC , buf , sizeof ( buf ) ) ;
2010-08-10 18:02:14 -07:00
if ( ret )
return ret ;
if ( buf [ ISL12022_REG_SR ] & ( ISL12022_SR_LBAT85 | ISL12022_SR_LBAT75 ) ) {
2022-09-21 13:46:19 +02:00
dev_warn ( dev ,
2010-08-10 18:02:14 -07:00
" voltage dropped below %u%%, "
" date and time is not reliable. \n " ,
buf [ ISL12022_REG_SR ] & ISL12022_SR_LBAT85 ? 85 : 75 ) ;
}
2022-09-21 13:46:19 +02:00
dev_dbg ( dev ,
2010-08-10 18:02:14 -07:00
" %s: raw data is sec=%02x, min=%02x, hr=%02x, "
" mday=%02x, mon=%02x, year=%02x, wday=%02x, "
" sr=%02x, int=%02x " ,
__func__ ,
buf [ ISL12022_REG_SC ] ,
buf [ ISL12022_REG_MN ] ,
buf [ ISL12022_REG_HR ] ,
buf [ ISL12022_REG_DT ] ,
buf [ ISL12022_REG_MO ] ,
buf [ ISL12022_REG_YR ] ,
buf [ ISL12022_REG_DW ] ,
buf [ ISL12022_REG_SR ] ,
buf [ ISL12022_REG_INT ] ) ;
tm - > tm_sec = bcd2bin ( buf [ ISL12022_REG_SC ] & 0x7F ) ;
tm - > tm_min = bcd2bin ( buf [ ISL12022_REG_MN ] & 0x7F ) ;
tm - > tm_hour = bcd2bin ( buf [ ISL12022_REG_HR ] & 0x3F ) ;
tm - > tm_mday = bcd2bin ( buf [ ISL12022_REG_DT ] & 0x3F ) ;
tm - > tm_wday = buf [ ISL12022_REG_DW ] & 0x07 ;
tm - > tm_mon = bcd2bin ( buf [ ISL12022_REG_MO ] & 0x1F ) - 1 ;
tm - > tm_year = bcd2bin ( buf [ ISL12022_REG_YR ] ) + 100 ;
2022-09-21 13:46:20 +02:00
dev_dbg ( dev , " %s: %ptR \n " , __func__ , tm ) ;
2010-08-10 18:02:14 -07:00
2018-02-19 16:23:56 +01:00
return 0 ;
2010-08-10 18:02:14 -07:00
}
2018-02-20 23:55:40 +01:00
static int isl12022_rtc_set_time ( struct device * dev , struct rtc_time * tm )
2010-08-10 18:02:14 -07:00
{
2022-09-21 13:46:21 +02:00
struct isl12022 * isl12022 = dev_get_drvdata ( dev ) ;
2022-09-21 13:46:23 +02:00
struct regmap * regmap = isl12022 - > regmap ;
2010-08-10 18:02:14 -07:00
int ret ;
uint8_t buf [ ISL12022_REG_DW + 1 ] ;
2022-09-21 13:46:20 +02:00
dev_dbg ( dev , " %s: %ptR \n " , __func__ , tm ) ;
2010-08-10 18:02:14 -07:00
2022-09-21 13:46:23 +02:00
/* Ensure the write enable bit is set. */
ret = regmap_update_bits ( regmap , ISL12022_REG_INT ,
ISL12022_INT_WRTC , ISL12022_INT_WRTC ) ;
if ( ret )
return ret ;
2010-08-10 18:02:14 -07:00
/* hours, minutes and seconds */
buf [ ISL12022_REG_SC ] = bin2bcd ( tm - > tm_sec ) ;
buf [ ISL12022_REG_MN ] = bin2bcd ( tm - > tm_min ) ;
2010-08-10 18:02:21 -07:00
buf [ ISL12022_REG_HR ] = bin2bcd ( tm - > tm_hour ) | ISL12022_HR_MIL ;
2010-08-10 18:02:14 -07:00
buf [ ISL12022_REG_DT ] = bin2bcd ( tm - > tm_mday ) ;
/* month, 1 - 12 */
buf [ ISL12022_REG_MO ] = bin2bcd ( tm - > tm_mon + 1 ) ;
/* year and century */
buf [ ISL12022_REG_YR ] = bin2bcd ( tm - > tm_year % 100 ) ;
buf [ ISL12022_REG_DW ] = tm - > tm_wday & 0x07 ;
2022-09-21 13:46:23 +02:00
return regmap_bulk_write ( isl12022 - > regmap , ISL12022_REG_SC ,
buf , sizeof ( buf ) ) ;
2010-08-10 18:02:14 -07:00
}
static const struct rtc_class_ops isl12022_rtc_ops = {
. read_time = isl12022_rtc_read_time ,
. set_time = isl12022_rtc_set_time ,
} ;
2022-09-21 13:46:23 +02:00
static const struct regmap_config regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
. use_single_write = true ,
} ;
2022-06-10 18:23:43 +02:00
static int isl12022_probe ( struct i2c_client * client )
2010-08-10 18:02:14 -07:00
{
struct isl12022 * isl12022 ;
if ( ! i2c_check_functionality ( client - > adapter , I2C_FUNC_I2C ) )
return - ENODEV ;
2013-04-29 16:20:41 -07:00
isl12022 = devm_kzalloc ( & client - > dev , sizeof ( struct isl12022 ) ,
GFP_KERNEL ) ;
2010-08-10 18:02:14 -07:00
if ( ! isl12022 )
return - ENOMEM ;
2022-09-21 13:46:21 +02:00
dev_set_drvdata ( & client - > dev , isl12022 ) ;
2010-08-10 18:02:14 -07:00
2022-09-21 13:46:23 +02:00
isl12022 - > regmap = devm_regmap_init_i2c ( client , & regmap_config ) ;
if ( IS_ERR ( isl12022 - > regmap ) ) {
dev_err ( & client - > dev , " regmap allocation failed \n " ) ;
return PTR_ERR ( isl12022 - > regmap ) ;
}
2022-09-21 13:46:16 +02:00
isl12022 - > rtc = devm_rtc_allocate_device ( & client - > dev ) ;
if ( IS_ERR ( isl12022 - > rtc ) )
return PTR_ERR ( isl12022 - > rtc ) ;
isl12022 - > rtc - > ops = & isl12022_rtc_ops ;
2022-09-21 13:46:17 +02:00
isl12022 - > rtc - > range_min = RTC_TIMESTAMP_BEGIN_2000 ;
isl12022 - > rtc - > range_max = RTC_TIMESTAMP_END_2099 ;
2022-09-21 13:46:16 +02:00
return devm_rtc_register_device ( isl12022 - > rtc ) ;
2010-08-10 18:02:14 -07:00
}
2014-08-08 14:20:20 -07:00
# ifdef CONFIG_OF
2014-10-13 15:52:39 -07:00
static const struct of_device_id isl12022_dt_match [ ] = {
2015-02-16 15:58:31 -08:00
{ . compatible = " isl,isl12022 " } , /* for backward compat., don't use */
{ . compatible = " isil,isl12022 " } ,
2014-08-08 14:20:20 -07:00
{ } ,
} ;
2015-07-30 18:18:46 +02:00
MODULE_DEVICE_TABLE ( of , isl12022_dt_match ) ;
2014-08-08 14:20:20 -07:00
# endif
2010-08-10 18:02:14 -07:00
static const struct i2c_device_id isl12022_id [ ] = {
{ " isl12022 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , isl12022_id ) ;
static struct i2c_driver isl12022_driver = {
. driver = {
. name = " rtc-isl12022 " ,
2014-08-08 14:20:20 -07:00
# ifdef CONFIG_OF
. of_match_table = of_match_ptr ( isl12022_dt_match ) ,
# endif
2010-08-10 18:02:14 -07:00
} ,
2022-06-10 18:23:43 +02:00
. probe_new = isl12022_probe ,
2010-08-10 18:02:14 -07:00
. id_table = isl12022_id ,
} ;
2012-03-23 15:02:31 -07:00
module_i2c_driver ( isl12022_driver ) ;
2010-08-10 18:02:14 -07:00
MODULE_AUTHOR ( " roman.fietze@telemotive.de " ) ;
MODULE_DESCRIPTION ( " ISL 12022 RTC driver " ) ;
MODULE_LICENSE ( " GPL " ) ;