📄 pt7c4372a_rtc.c
字号:
/* * @file pt7c4372a_rtc.c * @brief t30x RTC * * $Id: pt7c4372a_rtc.c,v 1.2 2008/05/09 09:27:39 gary Exp $ * $Author: gary $ * $Revision: 1.2 $ * * Copyright (c) 2008 Inc. All rights reserved. * * @date 2008/04/24 gary new file. * 2008/05/09 gary setup control register 2 properly. * */#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/time.h>#include <linux/timer.h>#include <asm/io.h>#include <asm/time.h>#include <asm/mach-t30x/t30x.h>#include <asm/mach-t30x/gpio.h>#include <asm/mach-t30x/ostimer.h>#define PT_RTC_VER "1.01"/* pt7c4372a register definitions. */#define REG_SEC 0x0#define REG_MIN 0x1#define REG_HOUR 0x2#define REG_DAYWEEK 0x3#define REG_DAYS 0x4#define REG_MON 0x5#define REG_YEAR 0x6#define REG_TIME_TRIM 0x7#if 0/* no need for now */#define REG_ALARMA_MIN 0x8#define REG_ALARMA_HOUR 0x9#define REG_ALARMA_DAY 0xa#define REG_ALARMB_MIN 0xb#define REG_ALARMB_HOUR 0xc#define REG_ALARMB_DAY 0xd#endif#define REG_CTRL1 0xe#define REG_CTRL2 0xf/* address 0y0110010, + read 0x65, + write 0x64 */#define ADDR 0x32#define I2C_READ 0x01#define I2C_WRITE 0x00void t30x_udelay(int offset){ unsigned long timeout = readl(T30X_OSTIMER_OSCR) + offset; unsigned long current_cnt; while ( (signed)(timeout - (current_cnt = readl(T30X_OSTIMER_OSCR)))>0 );}static int ostimer_offset;/* * GPIO operation functions. */void t30x_set_gpio_2(int state){ if ( state ) writel(0x0004, GPIO_SET); else writel(0x0004, GPIO_CLEAR);}void t30x_set_gpio_3(int state){ if ( state ) writel(0x0008, GPIO_SET); else writel(0x0008, GPIO_CLEAR);}int t30x_get_gpio_3(void){ return (readl(GPIO_LEVEL)&0x0008) ? 1 : 0;} void t30x_set_gpio_oe_3(int oe){ if ( oe ) { /* output enabled */ t30x_set_gpio_3(1); writel(readl(GPIO_OE)|0x0008, GPIO_OE); } else { t30x_set_gpio_3(0); writel(readl(GPIO_OE)&(~0x0008), GPIO_OE); }}/* gpio-2 SCL, gpio-3 SDA */ #define setsda(val) t30x_set_gpio_3(val)#define getsda() t30x_get_gpio_3()#define setscl(val) t30x_set_gpio_2(val)#define sda_to_read() t30x_set_gpio_oe_3(0)#define sda_to_write() t30x_set_gpio_oe_3(1)static inline void sdalo(void){ t30x_udelay(ostimer_offset); setsda(0); t30x_udelay(ostimer_offset);}static inline void sdahi(void){ t30x_udelay(ostimer_offset); setsda(1); t30x_udelay(ostimer_offset); }static inline void scllo(void){ t30x_udelay(ostimer_offset); setscl(0); t30x_udelay(ostimer_offset);}static inline void sclhi(void){ t30x_udelay(ostimer_offset); setscl(1); t30x_udelay(ostimer_offset);}static void i2c_start(void){ sdalo(); scllo();}#if 0static void i2c_repstart(void){ setsda(1); sclhi(); t30x_udelay(ostimer_offset); sdalo(); scllo();}#endifstatic void i2c_stop(void){ sdalo(); sclhi(); sdahi();}static int i2c_outb(char c){ int i; int sb; int ack; /* assert: scl is low */ for ( i=7; i>=0; i-- ) { sb = c & ( 1 << i ); setsda(sb); t30x_udelay(ostimer_offset); sclhi(); /* do arbitration here: * if ( sb && ! getsda(adap) ) -> ouch! Get out of here. */ setscl(0); t30x_udelay(ostimer_offset); } sda_to_read(); sclhi(); /* read ack: SDA should be pulled down by slave */ ack=getsda(); /* ack: sda is pulled low ->success. */ scllo(); sda_to_write(); return 0==ack; /* return 1 if device acked */ /* assert: scl is low (sda undef) */}static int i2c_inb(void){ /* read byte via i2c port, without start/stop sequence */ /* acknowledge is sent in i2c_read. */ int i; unsigned char indata=0; /* assert: scl is low */// sdahi(); sda_to_read(); for (i=0;i<8;i++) { sclhi(); indata *= 2; if ( getsda() ) indata |= 0x01; scllo(); } /* assert: scl is low */ sda_to_write(); return (int) (indata & 0xff);}static unsigned char read_reg(unsigned char reg){ int rc; unsigned char data = 0; unsigned long flags; spinlock_t lock; spin_lock_init(&lock); spin_lock_irqsave(&lock, flags); i2c_start(); rc = i2c_outb(ADDR<<1 | I2C_WRITE); if ( !rc ) printk("pt_rtc read_reg no ack 1\n"); rc = i2c_outb((reg<<4 | 0x04)); if ( !rc ) printk("pt_rtc read_reg no ack 2\n"); rc = i2c_inb(); data |= (rc&0xff); /* n-ack */ sdahi(); sclhi(); scllo(); i2c_stop(); spin_unlock_irqrestore(&lock, flags); return data;}static int write_reg(unsigned char reg, unsigned char val){ int rc; unsigned long flags; spinlock_t lock; spin_lock_init(&lock); spin_lock_irqsave(&lock, flags); i2c_start(); rc = i2c_outb(ADDR<<1 | I2C_WRITE); if ( !rc ) printk("pt_rtc write_reg ack 1 failed\n"); rc = i2c_outb((reg<<4|0x00)); if ( !rc ) printk("pt_rtc write_reg ack 2 failed\n"); rc = i2c_outb((unsigned char)(val & 0xff)); if ( !rc ) printk("pt_rtc write_reg ack 4 failed\n"); i2c_stop(); spin_unlock_irqrestore(&lock, flags); return rc;}inline int bcd2bin(int s){ return ( ((s>>4)&0x0f)*10 + (s&0x0f) );}inline int bin2bcd(int s){ return ( ((s/10)*16) + (s%10) );} unsigned long pt_rtc_get_time(void){ unsigned int sec, min, hrs, day, mon, yrs; while ( 1 ) { sec = read_reg(REG_SEC)&0x7f; min = read_reg(REG_MIN)&0x7f; hrs = read_reg(REG_HOUR)&0x3f; day = read_reg(REG_DAYS)&0x3f; mon = read_reg(REG_MON)&0x1f; yrs = (read_reg(REG_YEAR)&0xff); if ( sec == 0x59 && sec != (read_reg(REG_SEC)&0x7f) ) continue; else break; } sec = bcd2bin(sec); min = bcd2bin(min); hrs = bcd2bin(hrs); day = bcd2bin(day); mon = bcd2bin(mon); yrs = bcd2bin(yrs) + 2000; return mktime(yrs, mon, day, hrs, min, sec);}int pt_rtc_set_time(unsigned long time){ struct rtc_time tm; to_tm(time, &tm); tm.tm_mon += 1; tm.tm_year -= 2000; write_reg(REG_YEAR, bin2bcd(tm.tm_year)); write_reg(REG_MON, bin2bcd(tm.tm_mon)); write_reg(REG_DAYS, bin2bcd(tm.tm_mday)); write_reg(REG_HOUR, bin2bcd(tm.tm_hour)); write_reg(REG_MIN, bin2bcd(tm.tm_min)); write_reg(REG_SEC, bin2bcd(tm.tm_sec)); return 0;}void __init pt_rtc_init(void){#ifdef CONFIG_T307_OSTIMER#error "PT7C4372A driver would use T30x OSTIMER... failed..."#endif /* print driver banner. */ printk("Use PT7C4372A as external RTC, driver ver. %s\n", PT_RTC_VER); /* set up bit [14:15] to 0x00 for GPIO 2, 3 usage */ writel(readl(GPIO_ALTFUNC_SEL)&(~0xc000), GPIO_ALTFUNC_SEL); /* disable gpio 2, 3 interrupt mask */ writel(readl(GPIO_INT_MASK)|0x0c, GPIO_INT_MASK); /* setup gpio 2, 3 to 1 */ writel(0x0c, GPIO_SET); /* setup output enabled to 1 for default output */ writel(readl(GPIO_OE)|0x0c, GPIO_OE); writel(0x0f, T30X_OSTIMER_OSIMR); writel(0, T30X_OSTIMER_OSCCD); ostimer_offset = 10; write_reg(REG_CTRL2, 0x20);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -