From 32a145395ef1a8f3d561986ac57584708b36d31a Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E6=9E=97=E8=BE=89=E8=BE=89?= Date: Thu, 13 May 2010 01:47:43 +0000 Subject: [PATCH] add hym8563 rtc --- .config | 35 ++- arch/arm/mach-rk2818/board-midsdk.c | 10 +- arch/arm/mach-rk2818/devices.c | 4 +- drivers/rtc/Kconfig | 9 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-HYM8563.c | 397 ++++++++++++++++++++++++++++ drivers/rtc/rtc-HYM8563.h | 59 +++++ 7 files changed, 501 insertions(+), 14 deletions(-) create mode 100644 drivers/rtc/rtc-HYM8563.c create mode 100644 drivers/rtc/rtc-HYM8563.h diff --git a/.config b/.config index 7af7989cdc7a..6a3b3b9f15fc 100644 --- a/.config +++ b/.config @@ -697,7 +697,7 @@ CONFIG_I2C_HELPER_AUTO=y # # I2C Hardware Bus support # -# CONFIG_I2C_RK2818 is not set +CONFIG_I2C_RK2818=y # # Miscellaneous I2C Chip support @@ -709,7 +709,22 @@ CONFIG_I2C_HELPER_AUTO=y # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set # CONFIG_I2C_DEBUG_CHIP is not set -# CONFIG_SPI is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +CONFIG_SPIM_RK2818=y + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set # # PPS support @@ -985,9 +1000,10 @@ CONFIG_RTC_HCTOSYS_DEVICE="rtc0" # # RTC interfaces # -# CONFIG_RTC_INTF_SYSFS is not set -# CONFIG_RTC_INTF_PROC is not set -# CONFIG_RTC_INTF_DEV is not set +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set CONFIG_RTC_INTF_ALARM=y CONFIG_RTC_INTF_ALARM_DEV=y # CONFIG_RTC_DRV_TEST is not set @@ -995,6 +1011,7 @@ CONFIG_RTC_INTF_ALARM_DEV=y # # I2C RTC drivers # +CONFIG_RTC_HYM8563=y # CONFIG_RTC_DRV_DS1307 is not set # CONFIG_RTC_DRV_DS1374 is not set # CONFIG_RTC_DRV_DS1672 is not set @@ -1202,7 +1219,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" CONFIG_NLS_CODEPAGE_437=y # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set +CONFIG_NLS_CODEPAGE_850=y # CONFIG_NLS_CODEPAGE_852 is not set # CONFIG_NLS_CODEPAGE_855 is not set # CONFIG_NLS_CODEPAGE_857 is not set @@ -1214,7 +1231,7 @@ CONFIG_NLS_CODEPAGE_437=y # CONFIG_NLS_CODEPAGE_865 is not set # CONFIG_NLS_CODEPAGE_866 is not set # CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set +CONFIG_NLS_CODEPAGE_936=y # CONFIG_NLS_CODEPAGE_950 is not set # CONFIG_NLS_CODEPAGE_932 is not set # CONFIG_NLS_CODEPAGE_949 is not set @@ -1233,10 +1250,10 @@ CONFIG_NLS_ISO8859_1=y # CONFIG_NLS_ISO8859_9 is not set # CONFIG_NLS_ISO8859_13 is not set # CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set +CONFIG_NLS_ISO8859_15=y # CONFIG_NLS_KOI8_R is not set # CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set +CONFIG_NLS_UTF8=y # CONFIG_DLM is not set # diff --git a/arch/arm/mach-rk2818/board-midsdk.c b/arch/arm/mach-rk2818/board-midsdk.c index b83ae59c014f..0dcffa541787 100644 --- a/arch/arm/mach-rk2818/board-midsdk.c +++ b/arch/arm/mach-rk2818/board-midsdk.c @@ -281,11 +281,13 @@ static struct spi_board_info board_spi_devices[] = { .mode = SPI_MODE_0, }, -}; +}; static struct platform_device *devices[] __initdata = { &rk2818_device_uart1, &rk2818_device_dm9k, + &rk2818_device_i2c0, + &rk2818_device_i2c1, &rk2818_device_spim, }; @@ -299,9 +301,9 @@ static void __init machine_rk2818_init_irq(void) } static void __init machine_rk2818_board_init(void) -{ +{ rk2818_i2c_board_init(); - platform_add_devices(devices, ARRAY_SIZE(devices)); + platform_add_devices(devices, ARRAY_SIZE(devices)); spi_register_board_info(board_spi_devices, ARRAY_SIZE(board_spi_devices)); rk2818_mux_api_set(GPIOB4_SPI0CS0_MMC0D4_NAME,IOMUXA_GPIO0_B4); //IOMUXA_SPI0_CSN0);//use for gpio SPI CS0 rk2818_mux_api_set(GPIOB0_SPI0CSN1_MMC1PCA_NAME,IOMUXA_GPIO0_B0); //IOMUXA_SPI0_CSN1);//use for gpio SPI CS1 @@ -315,7 +317,7 @@ static void __init machine_rk2818_mapio(void) rk2818_iomux_init(); } -MACHINE_START(RK2818, "rk2818midsdk") +MACHINE_START(RK2818, "RK28board") /* UART for LL DEBUG */ .phys_io = 0x18002000, diff --git a/arch/arm/mach-rk2818/devices.c b/arch/arm/mach-rk2818/devices.c index 7a61c1cb659f..6e9b05b01c11 100644 --- a/arch/arm/mach-rk2818/devices.c +++ b/arch/arm/mach-rk2818/devices.c @@ -51,7 +51,9 @@ static struct resource resources_i2c1[] = { .flags = IORESOURCE_MEM, }, }; - +/* + * rk2818 4 uarts device + */ static struct resource resources_uart0[] = { { .start = IRQ_NR_UART0, diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 91641f0f9e38..eaaced736867 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -146,6 +146,15 @@ comment "I2C RTC drivers" if I2C +config RTC_HYM8563 + tristate "RK2818 extern HYM8563 RTC" + depends on I2C_RK2818 + help + If you say yes here you will get support for the + HYM8563 I2C RTC chip. + This driver can also be built as a module. If so, the module + will be called rtc-HYM8563. + config RTC_DRV_DS1307 tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025" help diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index e669616df323..b5963e58a7d5 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -87,3 +87,4 @@ obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o +obj-$(CONFIG_RTC_HYM8563) += rtc-HYM8563.o diff --git a/drivers/rtc/rtc-HYM8563.c b/drivers/rtc/rtc-HYM8563.c new file mode 100644 index 000000000000..052a4e0a702a --- /dev/null +++ b/drivers/rtc/rtc-HYM8563.c @@ -0,0 +1,397 @@ +/*drivers/rtc/rtc-HYM8563.c - driver for HYM8563 + * + * Copyright (C) 2010 ROCKCHIP, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include "rtc-HYM8563.h" + +#if 0 +#define DBG(x...) printk(KERN_INFO x) +#else +#define DBG(x...) +#endif + +static const unsigned short normal_i2c[] = { + HYM_ADDR , /* HYM8563 address */ + I2C_CLIENT_END +}; +I2C_CLIENT_INSMOD; /* defines addr_data */ + +static int hym8563_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], unsigned len) +{ + int ret; + struct i2c_msg msgs[1] = { + { client->addr, 1, len, buf }, + }; + buf[0] = reg; + BUG_ON(len == 0); + BUG_ON(reg > RTC_T_COUNT); + BUG_ON(reg + len > RTC_T_COUNT + 1); + + ret = i2c_transfer(client->adapter, msgs, 1); + if (ret > 0) + ret = 0; + + return ret; +} + +static int hym8563_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], __u16 len) +{ + int ret; + u8 i2c_buf[HYM8563_REG_LEN + 1]; + struct i2c_msg msgs[1] = { + { client->addr, 0, len + 1, i2c_buf } + }; + + BUG_ON(len == 0); + BUG_ON(reg > RTC_T_COUNT); + BUG_ON(reg + len > RTC_T_COUNT + 1); + + i2c_buf[0] = reg; + memcpy(&i2c_buf[1], &buf[0], len); + + ret = i2c_transfer(client->adapter, msgs, 1); + if (ret > 0) + ret = 0; + + return ret; +} + +/*the init of the hym8563 at first time */ +static int hym8563_init_device(struct i2c_client *client) +{ + u8 regs[2]; + int sr; + + regs[0]=0; + hym8563_i2c_set_regs(client, RTC_CTL1, regs, 1); + + //disable clkout + regs[0] = 0x80; + hym8563_i2c_set_regs(client, RTC_CLKOUT, regs, 1); + /*enable alarm interrupt*/ + hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1); + regs[0] = 0x0; + regs[0] |= AIE; + hym8563_i2c_set_regs(client, RTC_CTL2, regs, 1); + hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1); + + sr = hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1); + if(sr<0) + { + DBG("----hym8563_init err"); + } + + if(regs[0] & (AF|TF)) + { + regs[0] &= ~(AF|TF); + hym8563_i2c_set_regs(client, RTC_CTL2, regs, 1); + } + return 0; +} + +static int hym8563_read_datetime(struct i2c_client *client, struct rtc_time *tm) +{ + u8 i,regs[HYM8563_RTC_SECTION_LEN] = { 0, }; + + for(i=0;itm_sec = bcd2bin(regs[0x00] & 0x7F); + tm->tm_min = bcd2bin(regs[0x01] & 0x7F); + tm->tm_hour = bcd2bin(regs[0x02] & 0x3F); + tm->tm_mday = bcd2bin(regs[0x03] & 0x3F); + tm->tm_wday = bcd2bin(regs[0x04] & 0x07); + + tm->tm_mon = bcd2bin(regs[0x05] & 0x1F) ; + tm->tm_mon -= 1; //inorder to cooperate the systerm time + + tm->tm_year = bcd2bin(regs[0x06] & 0xFF); + if(regs[5] & 0x80) + tm->tm_year += 1900; + else + tm->tm_year += 2000; + + tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); + tm->tm_year -= 1900; //inorder to cooperate the systerm time + if(tm->tm_year < 0) + tm->tm_year = 0; + tm->tm_isdst = 0; + return 0; +} + +static int hym8563_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + return hym8563_read_datetime(to_i2c_client(dev), tm); +} + +static int hym8563_set_time(struct i2c_client *client, struct rtc_time *tm) +{ + u8 regs[HYM8563_RTC_SECTION_LEN] = { 0, }; + u8 mon_day,i; + u8 ret = 0; + + mon_day = rtc_month_days((tm->tm_mon), tm->tm_year + 1900); + + if(tm->tm_sec >= 60 || tm->tm_sec < 0 ) //set sec + regs[0x00] = bin2bcd(0x00); + else + regs[0x00] = bin2bcd(tm->tm_sec); + + if(tm->tm_min >= 60 || tm->tm_min < 0 ) //set min + regs[0x01] = bin2bcd(0x00); + else + regs[0x01] = bin2bcd(tm->tm_min); + + if(tm->tm_hour >= 24 || tm->tm_hour < 0 ) //set hour + regs[0x02] = bin2bcd(0x00); + else + regs[0x02] = bin2bcd(tm->tm_hour); + + if((tm->tm_mday) > mon_day) //if the input month day is bigger than the biggest day of this month, set the biggest day + regs[0x03] = bin2bcd(mon_day); + else if((tm->tm_mday) > 0) + regs[0x03] = bin2bcd(tm->tm_mday); + else if((tm->tm_mday) <= 0) + regs[0x03] = bin2bcd(0x01); + + if( tm->tm_year >= 200) // year >= 2100 + regs[0x06] = bin2bcd(99); //year = 2099 + else if(tm->tm_year >= 100) // 2000 <= year < 2100 + regs[0x06] = bin2bcd(tm->tm_year - 100); + else if(tm->tm_year >= 0){ // 1900 <= year < 2000 + regs[0x06] = bin2bcd(tm->tm_year); + regs[0x05] |= 0x80; + }else{ // year < 1900 + regs[0x06] = bin2bcd(0); //year = 1900 + regs[0x05] |= 0x80; + } + regs[0x04] = bin2bcd(tm->tm_wday); //set the weekday + regs[0x05] = (regs[0x05] & 0x80)| (bin2bcd(tm->tm_mon + 1) & 0x7F); //set the month + + for(i=0;itime.tm_mon), tm->time.tm_year + 1900); + hym8563_i2c_read_regs(client, RTC_A_MIN, regs, 4); + + if(tm->time.tm_min >= 60 || tm->time.tm_min < 0 ) //set min + regs[0x00] = bin2bcd(0x00) & 0x7f; + else + regs[0x00] = bin2bcd(tm->time.tm_min) & 0x7f; + if(tm->time.tm_hour >= 24 || tm->time.tm_hour < 0 ) //set hour + regs[0x01] = bin2bcd(0x00) & 0x7f; + else + regs[0x01] = bin2bcd(tm->time.tm_hour) & 0x7f; + regs[0x03] = bin2bcd (tm->time.tm_wday) & 0x7f; + + if((tm->time.tm_mday) > mon_day) //if the input month day is bigger than the biggest day of this month, set the biggest day + regs[0x02] = bin2bcd(mon_day) & 0x7f; + else if((tm->time.tm_mday) > 0) + regs[0x02] = bin2bcd(tm->time.tm_mday) & 0x7f; + else if((tm->time.tm_mday) <= 0) + regs[0x02] = bin2bcd(0x01) & 0x7f; + + hym8563_i2c_set_regs(client, RTC_A_MIN, regs, 4); + hym8563_i2c_read_regs(client, RTC_A_MIN, regs, 4); + hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1); + if(tm->enabled == 1) + regs[0] |= AIE; + else + regs[0] &= 0x0; + hym8563_i2c_set_regs(client, RTC_CTL2, regs, 1); + hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1); + return 0; +} + +#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE) +static int hym8563_i2c_open_alarm(struct i2c_client *client) +{ + u8 data; + hym8563_i2c_read_regs(client, RTC_CTL2, &data, 1); + data |= AIE; + hym8563_i2c_set_regs(client, RTC_CTL2, &data, 1); + + return 0; +} + +static int hym8563_i2c_close_alarm(struct i2c_client *client) +{ + u8 data; + hym8563_i2c_read_regs(client, RTC_CTL2, &data, 1); + data &= ~AIE; + hym8563_i2c_set_regs(client, RTC_CTL2, &data, 1); + + return 0; +} + +static int hym8563_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct i2c_client *client = to_i2c_client(dev); + + switch (cmd) { + case RTC_AIE_OFF: + if(hym8563_i2c_close_alarm(client) < 0) + goto err; + break; + case RTC_AIE_ON: + if(hym8563_i2c_open_alarm(client)) + goto err; + break; + default: + return -ENOIOCTLCMD; + } + return 0; +err: + return -EIO; +} +#else +#define hym8563_rtc_ioctl NULL +#endif + +#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE) +static int hym8563_rtc_proc(struct device *dev, struct seq_file *seq) +{ + return 0; +} +#else +#define hym8563_rtc_proc NULL +#endif + +static const struct rtc_class_ops hym8563_rtc_ops = { + .read_time = hym8563_rtc_read_time, + .set_time = hym8563_rtc_set_time, + .read_alarm = hym8563_rtc_read_alarm, + .set_alarm = hym8563_rtc_set_alarm, + .ioctl = hym8563_rtc_ioctl, + .proc = hym8563_rtc_proc +}; + +static int __devinit hym8563_probe(struct i2c_client *client,const struct i2c_device_id *id) +{ + int rc = 0; + struct rtc_device *rtc = NULL; + struct rtc_time tm_read, tm = { + .tm_wday = 4, + .tm_year = 109, + .tm_mon = 9, + .tm_mday = 1, + .tm_hour = 12, + .tm_min = 10, + .tm_sec = 58 + }; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + rtc = rtc_device_register(client->name, &client->dev, + &hym8563_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) { + rc = PTR_ERR(rtc); + rtc = NULL; + goto exit; + } + hym8563_init_device(client); + hym8563_read_datetime(client, &tm_read); //read time from hym8563 + + DBG("%s [%d]tm_sec=%d \n",__FUNCTION__,__LINE__,tm_read.tm_sec); + DBG("%s [%d]tm_min=%d \n",__FUNCTION__,__LINE__,tm_read.tm_min); + DBG("%s [%d]tm_hour=%d \n",__FUNCTION__,__LINE__,tm_read.tm_hour); + DBG("%s [%d]tm_mday=%d \n",__FUNCTION__,__LINE__,tm_read.tm_mday); + DBG("%s [%d]tm_mon=%d \n",__FUNCTION__,__LINE__,tm_read.tm_mon); + DBG("%s [%d]tm_year=%d \n",__FUNCTION__,__LINE__,tm_read.tm_year); + if(((tm_read.tm_year < 70) | (tm_read.tm_year > 137 )) | (tm_read.tm_mon == -1)) //if the hym8563 haven't initialized + { + hym8563_set_time(client, &tm); //initialize the hym8563 + } + return 0; + +exit: + if (rtc) + rtc_device_unregister(rtc); + return rc; +} + +static int __devexit hym8563_remove(struct i2c_client *client) +{ + struct rtc_device *rtc = i2c_get_clientdata(client); + + rtc_device_unregister(rtc); + + return 0; +} + +static const struct i2c_device_id hym8563_id[] = { + { "rtc_hym8563", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, hym8563_id); + +static struct i2c_driver hym8563_driver = { + .driver = { + .name = "rtc_hym8563", + .owner = THIS_MODULE, + }, + .probe = hym8563_probe, + .remove = __devexit_p(hym8563_remove), + .id_table = hym8563_id, +}; + +static int __init hym8563_init(void) +{ + return i2c_add_driver(&hym8563_driver); +} + +static void __exit hym8563_exit(void) +{ + i2c_del_driver(&hym8563_driver); +} + +MODULE_AUTHOR("lhh lhh@rock-chips.com"); +MODULE_DESCRIPTION("HYM8563 RTC driver"); +MODULE_LICENSE("GPL"); + +module_init(hym8563_init); +module_exit(hym8563_exit); + diff --git a/drivers/rtc/rtc-HYM8563.h b/drivers/rtc/rtc-HYM8563.h new file mode 100644 index 000000000000..947b2705de9a --- /dev/null +++ b/drivers/rtc/rtc-HYM8563.h @@ -0,0 +1,59 @@ +/*drivers/rtc/rtc-HYM8563.h - driver for HYM8563 + * + * Copyright (C) 2010 ROCKCHIP, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DRIVERS_HYM8563_H +#define _DRIVERS_HYM8563_H + +#define HYM_ADDR 0x51 + +#define RTC_CTL1 0x00 +#define RTC_CTL2 0x01 +#define RTC_SEC 0x02 +#define RTC_MIN 0x03 +#define RTC_HOUR 0x04 +#define RTC_DAY 0x05 +#define RTC_WEEK 0x06 +#define RTC_MON 0x07 +#define RTC_YEAR 0x08 +#define RTC_A_MIN 0x09 +#define RTC_A_HOUR 0x0A +#define RTC_A_DAY 0x0B +#define RTC_A_WEEK 0x0C +#define RTC_CLKOUT 0x0D +#define RTC_T_CTL 0x0E +#define RTC_T_COUNT 0x0F +#define CENTURY 0x80 +#define TI 0x10 +#define AF 0x08 +#define TF 0x04 +#define AIE 0x02 +#define TIE 0x01 +#define FE 0x80 +#define TE 0x80 +#define FD1 0x02 +#define FD0 0x01 +#define TD1 0x02 +#define TD0 0x01 +#define VL 0x80 + +#define HYM8563_REG_LEN 0x10 +#define HYM8563_RTC_SECTION_LEN 0x07 + +struct hym8563_platform_data { + unsigned int speed; + unsigned int mode; + unsigned int reg_byte_cnt; +}; + +#endif /*_DRIVERS_HYM8563_H*/ -- 2.34.1