⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pt7c4372a_rtc.c

📁 linux kernel RTC driver program with pt7c4372a_ic
💻 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 + -