123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- --- a/drivers/rtc/Kconfig
- +++ b/drivers/rtc/Kconfig
- @@ -567,6 +567,15 @@ config RTC_DRV_S5M
- This driver can also be built as a module. If so, the module
- will be called rtc-s5m.
-
- +config RTC_DRV_PT7C4338
- + tristate "Pericom Technology Inc. PT7C4338 RTC"
- + help
- + If you say yes here you get support for the Pericom Technology
- + Inc. PT7C4338 RTC chip.
- +
- + This driver can also be built as a module. If so, the module
- + will be called rtc-pt7c4338.
- +
- endif # I2C
-
- comment "SPI RTC drivers"
- --- a/drivers/rtc/Makefile
- +++ b/drivers/rtc/Makefile
- @@ -106,6 +106,7 @@ obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030
- obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
- obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o
- obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o
- +obj-$(CONFIG_RTC_DRV_PT7C4338) += rtc-pt7c4338.o
- obj-$(CONFIG_RTC_DRV_PUV3) += rtc-puv3.o
- obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o
- obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
- --- /dev/null
- +++ b/drivers/rtc/rtc-pt7c4338.c
- @@ -0,0 +1,216 @@
- +/*
- + * Copyright 2010 Freescale Semiconductor, Inc.
- + *
- + * Author: Priyanka Jain <Priyanka.Jain@freescale.com>
- + *
- + * See file CREDITS for list of people who contributed to this
- + * project.
- + *
- + * This program is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU General Public License as
- + * published by the Free Software Foundation; either version 2 of
- + * the License, or (at your option) any later version.
- + *
- + * 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.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- + * MA 02111-1307 USA
- + */
- +
- +/*
- + * This file provides Date & Time support (no alarms) for PT7C4338 chip.
- + *
- + * This file is based on drivers/rtc/rtc-ds1307.c
- + *
- + * PT7C4338 chip is manufactured by Pericom Technology Inc.
- + * It is a serial real-time clock which provides
- + * 1)Low-power clock/calendar.
- + * 2)Programmable square-wave output.
- + * It has 56 bytes of nonvolatile RAM.
- + */
- +
- +#include <linux/kernel.h>
- +#include <linux/module.h>
- +#include <linux/slab.h>
- +#include <linux/i2c.h>
- +#include <linux/rtc.h>
- +#include <linux/bcd.h>
- +
- +/* RTC register addresses */
- +#define PT7C4338_REG_SECONDS 0x00
- +#define PT7C4338_REG_MINUTES 0x01
- +#define PT7C4338_REG_HOURS 0x02
- +#define PT7C4338_REG_AMPM 0x02
- +#define PT7C4338_REG_DAY 0x03
- +#define PT7C4338_REG_DATE 0x04
- +#define PT7C4338_REG_MONTH 0x05
- +#define PT7C4338_REG_YEAR 0x06
- +#define PT7C4338_REG_CTRL_STAT 0x07
- +
- +/* RTC second register address bit */
- +#define PT7C4338_SEC_BIT_CH 0x80 /*Clock Halt (in Register 0)*/
- +
- +/* RTC control and status register bits */
- +#define PT7C4338_CTRL_STAT_BIT_RS0 0x1 /*Rate select 0*/
- +#define PT7C4338_CTRL_STAT_BIT_RS1 0x2 /*Rate select 1*/
- +#define PT7C4338_CTRL_STAT_BIT_SQWE 0x10 /*Square Wave Enable*/
- +#define PT7C4338_CTRL_STAT_BIT_OSF 0x20 /*Oscillator Stop Flag*/
- +#define PT7C4338_CTRL_STAT_BIT_OUT 0x80 /*Output Level Control*/
- +
- +static const struct i2c_device_id pt7c4338_id[] = {
- + { "pt7c4338", 0 },
- + { }
- +};
- +MODULE_DEVICE_TABLE(i2c, pt7c4338_id);
- +
- +struct pt7c4338{
- + struct i2c_client *client;
- + struct rtc_device *rtc;
- +};
- +
- +static int pt7c4338_read_time(struct device *dev, struct rtc_time *time)
- +{
- + struct i2c_client *client = to_i2c_client(dev);
- + int ret;
- + u8 buf[7];
- + u8 year, month, day, hour, minute, second;
- + u8 week, twelve_hr, am_pm;
- +
- + ret = i2c_smbus_read_i2c_block_data(client,
- + PT7C4338_REG_SECONDS, 7, buf);
- + if (ret < 0)
- + return ret;
- + if (ret < 7)
- + return -EIO;
- +
- + second = buf[0];
- + minute = buf[1];
- + hour = buf[2];
- + week = buf[3];
- + day = buf[4];
- + month = buf[5];
- + year = buf[6];
- +
- + /* Extract additional information for AM/PM */
- + twelve_hr = hour & 0x40;
- + am_pm = hour & 0x20;
- +
- + /* Write to rtc_time structure */
- + time->tm_sec = bcd2bin(second & 0x7f);
- + time->tm_min = bcd2bin(minute & 0x7f);
- + if (twelve_hr) {
- + /* Convert to 24 hr */
- + if (am_pm)
- + time->tm_hour = bcd2bin(hour & 0x10) + 12;
- + else
- + time->tm_hour = bcd2bin(hour & 0xBF);
- + } else {
- + time->tm_hour = bcd2bin(hour);
- + }
- +
- + time->tm_wday = bcd2bin(week & 0x07) - 1;
- + time->tm_mday = bcd2bin(day & 0x3f);
- + time->tm_mon = bcd2bin(month & 0x1F) - 1;
- + /* assume 20YY not 19YY */
- + time->tm_year = bcd2bin(year) + 100;
- +
- + return 0;
- +}
- +
- +static int pt7c4338_set_time(struct device *dev, struct rtc_time *time)
- +{
- + struct i2c_client *client = to_i2c_client(dev);
- + u8 buf[7];
- +
- + /* Extract time from rtc_time and load into pt7c4338*/
- + buf[0] = bin2bcd(time->tm_sec);
- + buf[1] = bin2bcd(time->tm_min);
- + buf[2] = bin2bcd(time->tm_hour);
- + buf[3] = bin2bcd(time->tm_wday + 1); /* Day of the week */
- + buf[4] = bin2bcd(time->tm_mday); /* Date */
- + buf[5] = bin2bcd(time->tm_mon + 1);
- +
- + /* assume 20YY not 19YY */
- + if (time->tm_year >= 100)
- + buf[6] = bin2bcd(time->tm_year - 100);
- + else
- + buf[6] = bin2bcd(time->tm_year);
- +
- + return i2c_smbus_write_i2c_block_data(client,
- + PT7C4338_REG_SECONDS, 7, buf);
- +}
- +
- +static const struct rtc_class_ops pt7c4338_rtc_ops = {
- + .read_time = pt7c4338_read_time,
- + .set_time = pt7c4338_set_time,
- +};
- +
- +static int pt7c4338_probe(struct i2c_client *client,
- + const struct i2c_device_id *id)
- +{
- + struct pt7c4338 *pt7c4338;
- + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- + int ret;
- +
- + pt7c4338 = kzalloc(sizeof(struct pt7c4338), GFP_KERNEL);
- + if (!pt7c4338)
- + return -ENOMEM;
- +
- + pt7c4338->client = client;
- + i2c_set_clientdata(client, pt7c4338);
- + pt7c4338->rtc = rtc_device_register(client->name, &client->dev,
- + &pt7c4338_rtc_ops, THIS_MODULE);
- + if (IS_ERR(pt7c4338->rtc)) {
- + ret = PTR_ERR(pt7c4338->rtc);
- + dev_err(&client->dev, "unable to register the class device\n");
- + goto out_free;
- + }
- +
- + return 0;
- +out_free:
- + i2c_set_clientdata(client, NULL);
- + kfree(pt7c4338);
- + return ret;
- +}
- +
- +static int pt7c4338_remove(struct i2c_client *client)
- +{
- + struct pt7c4338 *pt7c4338 = i2c_get_clientdata(client);
- +
- + rtc_device_unregister(pt7c4338->rtc);
- + i2c_set_clientdata(client, NULL);
- + kfree(pt7c4338);
- + return 0;
- +}
- +
- +static struct i2c_driver pt7c4338_driver = {
- + .driver = {
- + .name = "rtc-pt7c4338",
- + .owner = THIS_MODULE,
- + },
- + .probe = pt7c4338_probe,
- + .remove = pt7c4338_remove,
- + .id_table = pt7c4338_id,
- +};
- +
- +static int __init pt7c4338_init(void)
- +{
- + return i2c_add_driver(&pt7c4338_driver);
- +}
- +
- +static void __exit pt7c4338_exit(void)
- +{
- + i2c_del_driver(&pt7c4338_driver);
- +}
- +
- +module_init(pt7c4338_init);
- +module_exit(pt7c4338_exit);
- +
- +MODULE_AUTHOR("Priyanka Jain <Priyanka.Jain@freescale.com>");
- +MODULE_DESCRIPTION("pericom Technology Inc. PT7C4338 RTC Driver");
- +MODULE_LICENSE("GPL");
|