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 .
*
* 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 .
*
* 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 ;
2009-01-07 01:42:19 +03:00
return rtc_valid_tm ( dt ) ;
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 */
max6902_set_reg ( dev , 0xF , 0 ) ;
2008-10-19 07:28:41 +04:00
max6902_set_reg ( dev , 0x01 , bin2bcd ( dt - > tm_sec ) ) ;
max6902_set_reg ( dev , 0x03 , bin2bcd ( dt - > tm_min ) ) ;
max6902_set_reg ( dev , 0x05 , bin2bcd ( dt - > tm_hour ) ) ;
2006-06-25 16:48:23 +04:00
2008-10-19 07:28:41 +04:00
max6902_set_reg ( dev , 0x07 , bin2bcd ( dt - > tm_mday ) ) ;
2009-01-07 01:42:19 +03:00
max6902_set_reg ( dev , 0x09 , bin2bcd ( dt - > tm_mon + 1 ) ) ;
2008-10-19 07:28:41 +04:00
max6902_set_reg ( dev , 0x0B , bin2bcd ( dt - > tm_wday ) ) ;
2009-01-07 01:42:19 +03:00
max6902_set_reg ( dev , 0x0D , bin2bcd ( dt - > tm_year % 100 ) ) ;
max6902_set_reg ( dev , 0x13 , 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 */
max6902_set_reg ( dev , 0xF , 0x80 ) ;
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 ,
} ;
static int __devinit max6902_probe ( struct spi_device * spi )
{
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
rtc = rtc_device_register ( " max6902 " ,
& spi - > dev , & max6902_rtc_ops , THIS_MODULE ) ;
if ( IS_ERR ( rtc ) )
return PTR_ERR ( rtc ) ;
2006-06-25 16:48:23 +04:00
2011-01-13 04:00:09 +03:00
dev_set_drvdata ( & spi - > dev , rtc ) ;
2006-06-25 16:48:23 +04:00
return 0 ;
}
static int __devexit max6902_remove ( struct spi_device * spi )
{
2011-01-13 04:00:09 +03:00
struct rtc_device * rtc = dev_get_drvdata ( & spi - > dev ) ;
2006-06-25 16:48:23 +04:00
2009-01-07 01:42:19 +03:00
rtc_device_unregister ( 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
. bus = & spi_bus_type ,
. owner = THIS_MODULE ,
} ,
2007-08-23 01:01:57 +04:00
. probe = max6902_probe ,
2006-06-25 16:48:23 +04:00
. remove = __devexit_p ( max6902_remove ) ,
} ;
static __init int max6902_init ( void )
{
return spi_register_driver ( & max6902_driver ) ;
}
module_init ( max6902_init ) ;
static __exit void max6902_exit ( void )
{
spi_unregister_driver ( & max6902_driver ) ;
}
module_exit ( max6902_exit ) ;
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 " ) ;