2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2006-10-04 01:01:26 +04:00
/* drivers/rtc/rtc-max6902.c
2006-06-25 16:48:23 +04:00
*
* Copyright ( C ) 2006 8 D Technologies inc .
* Copyright ( C ) 2004 Compulab Ltd .
*
* Driver for MAX6902 spi RTC
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/platform_device.h>
# include <linux/init.h>
# include <linux/rtc.h>
# include <linux/spi/spi.h>
# include <linux/bcd.h>
# define MAX6902_REG_SECONDS 0x01
# define MAX6902_REG_MINUTES 0x03
# define MAX6902_REG_HOURS 0x05
# define MAX6902_REG_DATE 0x07
# define MAX6902_REG_MONTH 0x09
# define MAX6902_REG_DAY 0x0B
# define MAX6902_REG_YEAR 0x0D
# define MAX6902_REG_CONTROL 0x0F
# define MAX6902_REG_CENTURY 0x13
2009-01-07 01:42:19 +03:00
static int max6902_set_reg ( struct device * dev , unsigned char address ,
2006-06-25 16:48:23 +04:00
unsigned char data )
{
struct spi_device * spi = to_spi_device ( dev ) ;
unsigned char buf [ 2 ] ;
/* MSB must be '0' to write */
buf [ 0 ] = address & 0x7f ;
buf [ 1 ] = data ;
2009-01-07 01:42:19 +03:00
return spi_write_then_read ( spi , buf , 2 , NULL , 0 ) ;
2006-06-25 16:48:23 +04:00
}
static int max6902_get_reg ( struct device * dev , unsigned char address ,
unsigned char * data )
{
struct spi_device * spi = to_spi_device ( dev ) ;
/* Set MSB to indicate read */
2009-01-07 01:42:19 +03:00
* data = address | 0x80 ;
2006-06-25 16:48:23 +04:00
2009-01-07 01:42:19 +03:00
return spi_write_then_read ( spi , data , 1 , data , 1 ) ;
2006-06-25 16:48:23 +04:00
}
2009-01-07 01:42:19 +03:00
static int max6902_read_time ( struct device * dev , struct rtc_time * dt )
2006-06-25 16:48:23 +04:00
{
2009-01-07 01:42:19 +03:00
int err , century ;
2006-06-25 16:48:23 +04:00
struct spi_device * spi = to_spi_device ( dev ) ;
2009-01-07 01:42:19 +03:00
unsigned char buf [ 8 ] ;
2006-06-25 16:48:23 +04:00
2009-01-07 01:42:19 +03:00
buf [ 0 ] = 0xbf ; /* Burst read */
2006-06-25 16:48:23 +04:00
2009-01-07 01:42:19 +03:00
err = spi_write_then_read ( spi , buf , 1 , buf , 8 ) ;
if ( err ! = 0 )
return err ;
2006-06-25 16:48:23 +04:00
/* The chip sends data in this order:
* Seconds , Minutes , Hours , Date , Month , Day , Year */
2009-01-07 01:42:19 +03:00
dt - > tm_sec = bcd2bin ( buf [ 0 ] ) ;
dt - > tm_min = bcd2bin ( buf [ 1 ] ) ;
dt - > tm_hour = bcd2bin ( buf [ 2 ] ) ;
dt - > tm_mday = bcd2bin ( buf [ 3 ] ) ;
dt - > tm_mon = bcd2bin ( buf [ 4 ] ) - 1 ;
dt - > tm_wday = bcd2bin ( buf [ 5 ] ) ;
dt - > tm_year = bcd2bin ( buf [ 6 ] ) ;
/* Read century */
err = max6902_get_reg ( dev , MAX6902_REG_CENTURY , & buf [ 0 ] ) ;
if ( err ! = 0 )
return err ;
2006-06-25 16:48:23 +04:00
2009-01-07 01:42:19 +03:00
century = bcd2bin ( buf [ 0 ] ) * 100 ;
2006-06-25 16:48:23 +04:00
dt - > tm_year + = century ;
dt - > tm_year - = 1900 ;
2018-02-19 18:23:56 +03:00
return 0 ;
2006-06-25 16:48:23 +04:00
}
2009-01-07 01:42:19 +03:00
static int max6902_set_time ( struct device * dev , struct rtc_time * dt )
2006-06-25 16:48:23 +04:00
{
2009-01-07 01:42:19 +03:00
dt - > tm_year = dt - > tm_year + 1900 ;
2006-06-25 16:48:23 +04:00
/* Remove write protection */
2013-04-30 03:20:57 +04:00
max6902_set_reg ( dev , MAX6902_REG_CONTROL , 0 ) ;
2006-06-25 16:48:23 +04:00
2013-04-30 03:20:57 +04:00
max6902_set_reg ( dev , MAX6902_REG_SECONDS , bin2bcd ( dt - > tm_sec ) ) ;
max6902_set_reg ( dev , MAX6902_REG_MINUTES , bin2bcd ( dt - > tm_min ) ) ;
max6902_set_reg ( dev , MAX6902_REG_HOURS , bin2bcd ( dt - > tm_hour ) ) ;
2006-06-25 16:48:23 +04:00
2013-04-30 03:20:57 +04:00
max6902_set_reg ( dev , MAX6902_REG_DATE , bin2bcd ( dt - > tm_mday ) ) ;
max6902_set_reg ( dev , MAX6902_REG_MONTH , bin2bcd ( dt - > tm_mon + 1 ) ) ;
max6902_set_reg ( dev , MAX6902_REG_DAY , bin2bcd ( dt - > tm_wday ) ) ;
max6902_set_reg ( dev , MAX6902_REG_YEAR , bin2bcd ( dt - > tm_year % 100 ) ) ;
max6902_set_reg ( dev , MAX6902_REG_CENTURY , bin2bcd ( dt - > tm_year / 100 ) ) ;
2006-06-25 16:48:23 +04:00
/* Compulab used a delay here. However, the datasheet
* does not mention a delay being required anywhere . . . */
/* delay(2000); */
/* Write protect */
2013-04-30 03:20:57 +04:00
max6902_set_reg ( dev , MAX6902_REG_CONTROL , 0x80 ) ;
2006-06-25 16:48:23 +04:00
return 0 ;
}
2006-10-01 10:28:17 +04:00
static const struct rtc_class_ops max6902_rtc_ops = {
2006-06-25 16:48:23 +04:00
. read_time = max6902_read_time ,
. set_time = max6902_set_time ,
} ;
2012-12-22 01:09:38 +04:00
static int max6902_probe ( struct spi_device * spi )
2006-06-25 16:48:23 +04:00
{
struct rtc_device * rtc ;
unsigned char tmp ;
int res ;
spi - > mode = SPI_MODE_3 ;
spi - > bits_per_word = 8 ;
spi_setup ( spi ) ;
res = max6902_get_reg ( & spi - > dev , MAX6902_REG_SECONDS , & tmp ) ;
2009-01-07 01:42:19 +03:00
if ( res ! = 0 )
2006-06-25 16:48:23 +04:00
return res ;
2009-01-07 01:42:19 +03:00
2013-04-30 03:19:43 +04:00
rtc = devm_rtc_device_register ( & spi - > dev , " max6902 " ,
& max6902_rtc_ops , THIS_MODULE ) ;
2009-01-07 01:42:19 +03:00
if ( IS_ERR ( rtc ) )
return PTR_ERR ( rtc ) ;
2006-06-25 16:48:23 +04:00
2013-04-30 03:20:22 +04:00
spi_set_drvdata ( spi , rtc ) ;
2006-06-25 16:48:23 +04:00
return 0 ;
}
static struct spi_driver max6902_driver = {
. driver = {
2007-08-23 01:01:57 +04:00
. name = " rtc-max6902 " ,
2006-06-25 16:48:23 +04:00
} ,
2007-08-23 01:01:57 +04:00
. probe = max6902_probe ,
2006-06-25 16:48:23 +04:00
} ;
2012-03-24 02:02:30 +04:00
module_spi_driver ( max6902_driver ) ;
2006-06-25 16:48:23 +04:00
2013-07-04 02:05:54 +04:00
MODULE_DESCRIPTION ( " max6902 spi RTC driver " ) ;
MODULE_AUTHOR ( " Raphael Assenat " ) ;
MODULE_LICENSE ( " GPL " ) ;
2009-09-23 03:46:08 +04:00
MODULE_ALIAS ( " spi:rtc-max6902 " ) ;