Path: blob/master/arch/cris/arch-v10/drivers/ds1302.c
15131 views
/*!***************************************************************************1*!2*! FILE NAME : ds1302.c3*!4*! DESCRIPTION: Implements an interface for the DS1302 RTC through Etrax I/O5*!6*! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init7*!8*! ---------------------------------------------------------------------------9*!10*! (C) Copyright 1999-2007 Axis Communications AB, LUND, SWEDEN11*!12*!***************************************************************************/131415#include <linux/fs.h>16#include <linux/init.h>17#include <linux/mm.h>18#include <linux/module.h>19#include <linux/miscdevice.h>20#include <linux/delay.h>21#include <linux/mutex.h>22#include <linux/bcd.h>23#include <linux/capability.h>2425#include <asm/uaccess.h>26#include <asm/system.h>27#include <arch/svinto.h>28#include <asm/io.h>29#include <asm/rtc.h>30#include <arch/io_interface_mux.h>3132#include "i2c.h"3334#define RTC_MAJOR_NR 121 /* local major, change later */3536static DEFINE_MUTEX(ds1302_mutex);37static const char ds1302_name[] = "ds1302";3839/* The DS1302 might be connected to different bits on different products.40* It has three signals - SDA, SCL and RST. RST and SCL are always outputs,41* but SDA can have a selected direction.42* For now, only PORT_PB is hardcoded.43*/4445/* The RST bit may be on either the Generic Port or Port PB. */46#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT47#define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x)48#define TK_RST_DIR(x)49#else50#define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x)51#define TK_RST_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x)52#endif535455#define TK_SDA_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SDABIT, x)56#define TK_SCL_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SCLBIT, x)5758#define TK_SDA_IN() ((*R_PORT_PB_READ >> CONFIG_ETRAX_DS1302_SDABIT) & 1)59/* 1 is out, 0 is in */60#define TK_SDA_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_SDABIT, x)61#define TK_SCL_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_SCLBIT, x)626364/*65* The reason for tempudelay and not udelay is that loops_per_usec66* (used in udelay) is not set when functions here are called from time.c67*/6869static void tempudelay(int usecs)70{71volatile int loops;7273for(loops = usecs * 12; loops > 0; loops--)74/* nothing */;75}767778/* Send 8 bits. */79static void80out_byte(unsigned char x)81{82int i;83TK_SDA_DIR(1);84for (i = 8; i--;) {85/* The chip latches incoming bits on the rising edge of SCL. */86TK_SCL_OUT(0);87TK_SDA_OUT(x & 1);88tempudelay(1);89TK_SCL_OUT(1);90tempudelay(1);91x >>= 1;92}93TK_SDA_DIR(0);94}9596static unsigned char97in_byte(void)98{99unsigned char x = 0;100int i;101102/* Read byte. Bits come LSB first, on the falling edge of SCL.103* Assume SDA is in input direction already.104*/105TK_SDA_DIR(0);106107for (i = 8; i--;) {108TK_SCL_OUT(0);109tempudelay(1);110x >>= 1;111x |= (TK_SDA_IN() << 7);112TK_SCL_OUT(1);113tempudelay(1);114}115116return x;117}118119/* Prepares for a transaction by de-activating RST (active-low). */120121static void122start(void)123{124TK_SCL_OUT(0);125tempudelay(1);126TK_RST_OUT(0);127tempudelay(5);128TK_RST_OUT(1);129}130131/* Ends a transaction by taking RST active again. */132133static void134stop(void)135{136tempudelay(2);137TK_RST_OUT(0);138}139140/* Enable writing. */141142static void143ds1302_wenable(void)144{145start();146out_byte(0x8e); /* Write control register */147out_byte(0x00); /* Disable write protect bit 7 = 0 */148stop();149}150151/* Disable writing. */152153static void154ds1302_wdisable(void)155{156start();157out_byte(0x8e); /* Write control register */158out_byte(0x80); /* Disable write protect bit 7 = 0 */159stop();160}161162163164/* Read a byte from the selected register in the DS1302. */165166unsigned char167ds1302_readreg(int reg)168{169unsigned char x;170171start();172out_byte(0x81 | (reg << 1)); /* read register */173x = in_byte();174stop();175176return x;177}178179/* Write a byte to the selected register. */180181void182ds1302_writereg(int reg, unsigned char val)183{184#ifndef CONFIG_ETRAX_RTC_READONLY185int do_writereg = 1;186#else187int do_writereg = 0;188189if (reg == RTC_TRICKLECHARGER)190do_writereg = 1;191#endif192193if (do_writereg) {194ds1302_wenable();195start();196out_byte(0x80 | (reg << 1)); /* write register */197out_byte(val);198stop();199ds1302_wdisable();200}201}202203void204get_rtc_time(struct rtc_time *rtc_tm)205{206unsigned long flags;207208local_irq_save(flags);209210rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);211rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);212rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);213rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);214rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);215rtc_tm->tm_year = CMOS_READ(RTC_YEAR);216217local_irq_restore(flags);218219rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);220rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);221rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);222rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);223rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);224rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);225226/*227* Account for differences between how the RTC uses the values228* and how they are defined in a struct rtc_time;229*/230231if (rtc_tm->tm_year <= 69)232rtc_tm->tm_year += 100;233234rtc_tm->tm_mon--;235}236237static unsigned char days_in_mo[] =238{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};239240/* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date). */241242static int rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)243{244unsigned long flags;245246switch(cmd) {247case RTC_RD_TIME: /* read the time/date from RTC */248{249struct rtc_time rtc_tm;250251memset(&rtc_tm, 0, sizeof (struct rtc_time));252get_rtc_time(&rtc_tm);253if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time)))254return -EFAULT;255return 0;256}257258case RTC_SET_TIME: /* set the RTC */259{260struct rtc_time rtc_tm;261unsigned char mon, day, hrs, min, sec, leap_yr;262unsigned int yrs;263264if (!capable(CAP_SYS_TIME))265return -EPERM;266267if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))268return -EFAULT;269270yrs = rtc_tm.tm_year + 1900;271mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */272day = rtc_tm.tm_mday;273hrs = rtc_tm.tm_hour;274min = rtc_tm.tm_min;275sec = rtc_tm.tm_sec;276277278if ((yrs < 1970) || (yrs > 2069))279return -EINVAL;280281leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));282283if ((mon > 12) || (day == 0))284return -EINVAL;285286if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))287return -EINVAL;288289if ((hrs >= 24) || (min >= 60) || (sec >= 60))290return -EINVAL;291292if (yrs >= 2000)293yrs -= 2000; /* RTC (0, 1, ... 69) */294else295yrs -= 1900; /* RTC (70, 71, ... 99) */296297sec = bin2bcd(sec);298min = bin2bcd(min);299hrs = bin2bcd(hrs);300day = bin2bcd(day);301mon = bin2bcd(mon);302yrs = bin2bcd(yrs);303304local_irq_save(flags);305CMOS_WRITE(yrs, RTC_YEAR);306CMOS_WRITE(mon, RTC_MONTH);307CMOS_WRITE(day, RTC_DAY_OF_MONTH);308CMOS_WRITE(hrs, RTC_HOURS);309CMOS_WRITE(min, RTC_MINUTES);310CMOS_WRITE(sec, RTC_SECONDS);311local_irq_restore(flags);312313/* Notice that at this point, the RTC is updated but314* the kernel is still running with the old time.315* You need to set that separately with settimeofday316* or adjtimex.317*/318return 0;319}320321case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */322{323int tcs_val;324325if (!capable(CAP_SYS_TIME))326return -EPERM;327328if(copy_from_user(&tcs_val, (int*)arg, sizeof(int)))329return -EFAULT;330331tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F);332ds1302_writereg(RTC_TRICKLECHARGER, tcs_val);333return 0;334}335case RTC_VL_READ:336{337/* TODO:338* Implement voltage low detection support339*/340printk(KERN_WARNING "DS1302: RTC Voltage Low detection"341" is not supported\n");342return 0;343}344case RTC_VL_CLR:345{346/* TODO:347* Nothing to do since Voltage Low detection is not supported348*/349return 0;350}351default:352return -ENOIOCTLCMD;353}354}355356static long rtc_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)357{358int ret;359360mutex_lock(&ds1302_mutex);361ret = rtc_ioctl(file, cmd, arg);362mutex_unlock(&ds1302_mutex);363364return ret;365}366367static void368print_rtc_status(void)369{370struct rtc_time tm;371372get_rtc_time(&tm);373374/*375* There is no way to tell if the luser has the RTC set for local376* time or for Universal Standard Time (GMT). Probably local though.377*/378379printk(KERN_INFO "rtc_time\t: %02d:%02d:%02d\n",380tm.tm_hour, tm.tm_min, tm.tm_sec);381printk(KERN_INFO "rtc_date\t: %04d-%02d-%02d\n",382tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);383}384385/* The various file operations we support. */386387static const struct file_operations rtc_fops = {388.owner = THIS_MODULE,389.unlocked_ioctl = rtc_unlocked_ioctl,390.llseek = noop_llseek,391};392393/* Probe for the chip by writing something to its RAM and try reading it back. */394395#define MAGIC_PATTERN 0x42396397static int __init398ds1302_probe(void)399{400int retval, res;401402TK_RST_DIR(1);403TK_SCL_DIR(1);404TK_SDA_DIR(0);405406/* Try to talk to timekeeper. */407408ds1302_wenable();409start();410out_byte(0xc0); /* write RAM byte 0 */411out_byte(MAGIC_PATTERN); /* write something magic */412start();413out_byte(0xc1); /* read RAM byte 0 */414415if((res = in_byte()) == MAGIC_PATTERN) {416stop();417ds1302_wdisable();418printk(KERN_INFO "%s: RTC found.\n", ds1302_name);419printk(KERN_INFO "%s: SDA, SCL, RST on PB%i, PB%i, %s%i\n",420ds1302_name,421CONFIG_ETRAX_DS1302_SDABIT,422CONFIG_ETRAX_DS1302_SCLBIT,423#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT424"GENIO",425#else426"PB",427#endif428CONFIG_ETRAX_DS1302_RSTBIT);429print_rtc_status();430retval = 1;431} else {432stop();433retval = 0;434}435436return retval;437}438439440/* Just probe for the RTC and register the device to handle the ioctl needed. */441442int __init443ds1302_init(void)444{445#ifdef CONFIG_ETRAX_I2C446i2c_init();447#endif448449if (!ds1302_probe()) {450#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT451#if CONFIG_ETRAX_DS1302_RSTBIT == 27452/*453* The only way to set g27 to output is to enable ATA.454*455* Make sure that R_GEN_CONFIG is setup correct.456*/457/* Allocating the ATA interface will grab almost all458* pins in I/O groups a, b, c and d. A consequence of459* allocating the ATA interface is that the fixed460* interfaces shared RAM, parallel port 0, parallel461* port 1, parallel port W, SCSI-8 port 0, SCSI-8 port462* 1, SCSI-W, serial port 2, serial port 3,463* synchronous serial port 3 and USB port 2 and almost464* all GPIO pins on port g cannot be used.465*/466if (cris_request_io_interface(if_ata, "ds1302/ATA")) {467printk(KERN_WARNING "ds1302: Failed to get IO interface\n");468return -1;469}470471#elif CONFIG_ETRAX_DS1302_RSTBIT == 0472if (cris_io_interface_allocate_pins(if_gpio_grp_a,473'g',474CONFIG_ETRAX_DS1302_RSTBIT,475CONFIG_ETRAX_DS1302_RSTBIT)) {476printk(KERN_WARNING "ds1302: Failed to get IO interface\n");477return -1;478}479480/* Set the direction of this bit to out. */481genconfig_shadow = ((genconfig_shadow &482~IO_MASK(R_GEN_CONFIG, g0dir)) |483(IO_STATE(R_GEN_CONFIG, g0dir, out)));484*R_GEN_CONFIG = genconfig_shadow;485#endif486if (!ds1302_probe()) {487printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name);488return -1;489}490#else491printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name);492return -1;493#endif494}495/* Initialise trickle charger */496ds1302_writereg(RTC_TRICKLECHARGER,497RTC_TCR_PATTERN |(CONFIG_ETRAX_DS1302_TRICKLE_CHARGE & 0x0F));498/* Start clock by resetting CLOCK_HALT */499ds1302_writereg(RTC_SECONDS, (ds1302_readreg(RTC_SECONDS) & 0x7F));500return 0;501}502503static int __init ds1302_register(void)504{505ds1302_init();506if (register_chrdev(RTC_MAJOR_NR, ds1302_name, &rtc_fops)) {507printk(KERN_INFO "%s: unable to get major %d for rtc\n",508ds1302_name, RTC_MAJOR_NR);509return -1;510}511return 0;512513}514515module_init(ds1302_register);516517518