Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933021AbZIDG77 (ORCPT ); Fri, 4 Sep 2009 02:59:59 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S932994AbZIDG75 (ORCPT ); Fri, 4 Sep 2009 02:59:57 -0400 Received: from mail-bw0-f219.google.com ([209.85.218.219]:55110 "EHLO mail-bw0-f219.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932966AbZIDG7w (ORCPT ); Fri, 4 Sep 2009 02:59:52 -0400 DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:date:message-id:subject:from:to:content-type; b=YotpDazjUK6UqN+x+htcz8EOz4epvp1vrVWFvcWCl3uMIofBcuIsqZCfoi0m9pTPT1 ll0QU3/bkczViQf58hOOMVN+Ujyjqza3UvY5ckaI8WPqfTHBK3zDs70V0s81FUQ79uhA lApdiWJ1bHSQ5gFlxDljdUSgfMlXsLGTjoJmE= MIME-Version: 1.0 Date: Fri, 4 Sep 2009 08:59:51 +0200 Message-ID: Subject: [PATCH -mm] rtc-pcf2123 fixes From: christian pellegrin To: Chris Verges , Andrew Morton , linux-kernel@vger.kernel.org Content-Type: text/plain; charset=ISO-8859-1 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5358 Lines: 191 Hi, the following patch: fixes bug with write command bitfield fixes bug on crashing when module unloaded but no chip present adds access to registers via sysfs (needed for accessing calibration register which is needed for a good stability of the RTC) Signed-off: Christian Pellegrin Tested-by: Christian Pellegrin --- diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index 2fcff82..0c55f7d 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -10,6 +10,23 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. + * + * Please note that the CS is active high, so platform data + * should look something like: + + static struct spi_board_info ek_spi_devices[] = { + ... + { + .modalias = "rtc-pcf2123", + .chip_select = 1, + .controller_data = (void *) AT91_PIN_PA10, + .max_speed_hz = 1000 * 1000, + .mode = SPI_CS_HIGH, + .bus_num = 0, + }, +... +}; + */ #include @@ -20,10 +37,9 @@ #include #include #include -#include #include -#define DRV_VERSION "0.3" +#define DRV_VERSION "0.4" #define PCF2123_REG_CTRL1 0x00 /* Control Register 1 */ #define PCF2123_REG_CTRL2 0x01 /* Control Register 2 */ @@ -36,13 +52,19 @@ #define PCF2123_REG_MO 0x07 #define PCF2123_REG_YR 0x08 -#define PCF2123_CMD_W(addr) (((addr) & 0x0F) | 0x40) /* single write */ +#define PCF2123_CMD_W(addr) (((addr) & 0x0F) | 0x10) /* single write */ #define PCF2123_CMD_R(addr) (((addr) & 0x0F) | 0x90) /* single read */ static struct spi_driver pcf2123_driver; +struct pcf2123_sysfs_reg { + struct device_attribute attr; /* must be first */ + char name[2]; +}; + struct pcf2123_plat_data { struct rtc_device *rtc; + struct pcf2123_sysfs_reg regs[16]; }; /* @@ -55,6 +77,39 @@ static inline void pcf2123_delay_trec(void) ndelay(30); } +static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr, + char *buffer) +{ + struct spi_device *spi = to_spi_device(dev); + struct pcf2123_sysfs_reg *r = (struct pcf2123_sysfs_reg *) attr; + u8 txbuf[1], rxbuf[1]; + int ret; + + txbuf[0] = PCF2123_CMD_R(simple_strtoul(r->name, NULL, 16)); + ret = spi_write_then_read(spi, txbuf, 1, rxbuf, 1); + if (ret < 0) + return sprintf(buffer, "error: %d", ret); + pcf2123_delay_trec(); + return sprintf(buffer, "0x%x", rxbuf[0]); +} + +static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr, + const char *buffer, size_t count) +{ + struct spi_device *spi = to_spi_device(dev); + struct pcf2123_sysfs_reg *r = (struct pcf2123_sysfs_reg *) attr; + u8 txbuf[2]; + int ret; + + txbuf[0] = PCF2123_CMD_W(simple_strtoul(r->name, NULL, 16)); + txbuf[1] = simple_strtoul(buffer, NULL, 0); + ret = spi_write(spi, txbuf, sizeof(txbuf)); + if (ret < 0) + return -EIO; + pcf2123_delay_trec(); + return count; +} + static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct spi_device *spi = to_spi_device(dev); @@ -149,7 +204,7 @@ static int __devinit pcf2123_probe(struct spi_device *spi) struct rtc_device *rtc; struct pcf2123_plat_data *pdata; u8 txbuf[2], rxbuf[1]; - int ret; + int ret, i; pdata = kzalloc(sizeof(struct pcf2123_plat_data), GFP_KERNEL); if (!pdata) @@ -201,28 +256,50 @@ static int __devinit pcf2123_probe(struct spi_device *spi) &pcf2123_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { + dev_err(&spi->dev, "failed to register.\n"); ret = PTR_ERR(rtc); goto kfree_exit; } pdata->rtc = rtc; + for (i = 0; i < 16; i++) { + sprintf(pdata->regs[i].name, "%1x", i); + pdata->regs[i].attr.attr.mode = S_IRUGO | S_IWUSR; + pdata->regs[i].attr.attr.name = pdata->regs[i].name; + pdata->regs[i].attr.show = pcf2123_show; + pdata->regs[i].attr.store = pcf2123_store; + ret = device_create_file(&spi->dev, &pdata->regs[i].attr); + if (ret) { + dev_err(&spi->dev, "Unable to create sysfs %s\n", + pdata->regs[i].name); + pdata->regs[i].name[0] = '\0'; + } + } + return 0; kfree_exit: kfree(pdata); + spi->dev.platform_data = NULL; return ret; } static int pcf2123_remove(struct spi_device *spi) { struct pcf2123_plat_data *pdata = spi->dev.platform_data; - struct rtc_device *rtc = pdata->rtc; - - if (rtc) - rtc_device_unregister(rtc); - - kfree(pdata); - + int i; + + if (pdata) { + struct rtc_device *rtc = pdata->rtc; + + if (rtc) + rtc_device_unregister(rtc); + for (i = 0; i < 16; i++) + if (pdata->regs[i].name[0]) + device_remove_file(&spi->dev, + &pdata->regs[i].attr); + kfree(pdata); + } return 0; } -- Christian Pellegrin, see http://www.evolware.org/chri/ "Real Programmers don't play tennis, or any other sport which requires you to change clothes. Mountain climbing is OK, and Real Programmers wear their climbing boots to work in case a mountain should suddenly spring up in the middle of the computer room." -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/