Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.26-rc2 267 lines 6.2 kB view raw
1/* drivers/rtc/rtc-v3020.c 2 * 3 * Copyright (C) 2006 8D Technologies inc. 4 * Copyright (C) 2004 Compulab Ltd. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * Driver for the V3020 RTC 11 * 12 * Changelog: 13 * 14 * 10-May-2006: Raphael Assenat <raph@8d.com> 15 * - Converted to platform driver 16 * - Use the generic rtc class 17 * 18 * ??-???-2004: Someone at Compulab 19 * - Initial driver creation. 20 * 21 */ 22#include <linux/platform_device.h> 23#include <linux/module.h> 24#include <linux/init.h> 25#include <linux/rtc.h> 26#include <linux/types.h> 27#include <linux/bcd.h> 28#include <linux/rtc-v3020.h> 29#include <linux/delay.h> 30 31#include <asm/io.h> 32 33#undef DEBUG 34 35struct v3020 { 36 void __iomem *ioaddress; 37 int leftshift; 38 struct rtc_device *rtc; 39}; 40 41static void v3020_set_reg(struct v3020 *chip, unsigned char address, 42 unsigned char data) 43{ 44 int i; 45 unsigned char tmp; 46 47 tmp = address; 48 for (i = 0; i < 4; i++) { 49 writel((tmp & 1) << chip->leftshift, chip->ioaddress); 50 tmp >>= 1; 51 udelay(1); 52 } 53 54 /* Commands dont have data */ 55 if (!V3020_IS_COMMAND(address)) { 56 for (i = 0; i < 8; i++) { 57 writel((data & 1) << chip->leftshift, chip->ioaddress); 58 data >>= 1; 59 udelay(1); 60 } 61 } 62} 63 64static unsigned char v3020_get_reg(struct v3020 *chip, unsigned char address) 65{ 66 unsigned int data=0; 67 int i; 68 69 for (i = 0; i < 4; i++) { 70 writel((address & 1) << chip->leftshift, chip->ioaddress); 71 address >>= 1; 72 udelay(1); 73 } 74 75 for (i = 0; i < 8; i++) { 76 data >>= 1; 77 if (readl(chip->ioaddress) & (1 << chip->leftshift)) 78 data |= 0x80; 79 udelay(1); 80 } 81 82 return data; 83} 84 85static int v3020_read_time(struct device *dev, struct rtc_time *dt) 86{ 87 struct v3020 *chip = dev_get_drvdata(dev); 88 int tmp; 89 90 /* Copy the current time to ram... */ 91 v3020_set_reg(chip, V3020_CMD_CLOCK2RAM, 0); 92 93 /* ...and then read constant values. */ 94 tmp = v3020_get_reg(chip, V3020_SECONDS); 95 dt->tm_sec = BCD2BIN(tmp); 96 tmp = v3020_get_reg(chip, V3020_MINUTES); 97 dt->tm_min = BCD2BIN(tmp); 98 tmp = v3020_get_reg(chip, V3020_HOURS); 99 dt->tm_hour = BCD2BIN(tmp); 100 tmp = v3020_get_reg(chip, V3020_MONTH_DAY); 101 dt->tm_mday = BCD2BIN(tmp); 102 tmp = v3020_get_reg(chip, V3020_MONTH); 103 dt->tm_mon = BCD2BIN(tmp) - 1; 104 tmp = v3020_get_reg(chip, V3020_WEEK_DAY); 105 dt->tm_wday = BCD2BIN(tmp); 106 tmp = v3020_get_reg(chip, V3020_YEAR); 107 dt->tm_year = BCD2BIN(tmp)+100; 108 109#ifdef DEBUG 110 printk("\n%s : Read RTC values\n",__func__); 111 printk("tm_hour: %i\n",dt->tm_hour); 112 printk("tm_min : %i\n",dt->tm_min); 113 printk("tm_sec : %i\n",dt->tm_sec); 114 printk("tm_year: %i\n",dt->tm_year); 115 printk("tm_mon : %i\n",dt->tm_mon); 116 printk("tm_mday: %i\n",dt->tm_mday); 117 printk("tm_wday: %i\n",dt->tm_wday); 118#endif 119 120 return 0; 121} 122 123 124static int v3020_set_time(struct device *dev, struct rtc_time *dt) 125{ 126 struct v3020 *chip = dev_get_drvdata(dev); 127 128#ifdef DEBUG 129 printk("\n%s : Setting RTC values\n",__func__); 130 printk("tm_sec : %i\n",dt->tm_sec); 131 printk("tm_min : %i\n",dt->tm_min); 132 printk("tm_hour: %i\n",dt->tm_hour); 133 printk("tm_mday: %i\n",dt->tm_mday); 134 printk("tm_wday: %i\n",dt->tm_wday); 135 printk("tm_year: %i\n",dt->tm_year); 136#endif 137 138 /* Write all the values to ram... */ 139 v3020_set_reg(chip, V3020_SECONDS, BIN2BCD(dt->tm_sec)); 140 v3020_set_reg(chip, V3020_MINUTES, BIN2BCD(dt->tm_min)); 141 v3020_set_reg(chip, V3020_HOURS, BIN2BCD(dt->tm_hour)); 142 v3020_set_reg(chip, V3020_MONTH_DAY, BIN2BCD(dt->tm_mday)); 143 v3020_set_reg(chip, V3020_MONTH, BIN2BCD(dt->tm_mon + 1)); 144 v3020_set_reg(chip, V3020_WEEK_DAY, BIN2BCD(dt->tm_wday)); 145 v3020_set_reg(chip, V3020_YEAR, BIN2BCD(dt->tm_year % 100)); 146 147 /* ...and set the clock. */ 148 v3020_set_reg(chip, V3020_CMD_RAM2CLOCK, 0); 149 150 /* Compulab used this delay here. I dont know why, 151 * the datasheet does not specify a delay. */ 152 /*mdelay(5);*/ 153 154 return 0; 155} 156 157static const struct rtc_class_ops v3020_rtc_ops = { 158 .read_time = v3020_read_time, 159 .set_time = v3020_set_time, 160}; 161 162static int rtc_probe(struct platform_device *pdev) 163{ 164 struct v3020_platform_data *pdata = pdev->dev.platform_data; 165 struct v3020 *chip; 166 struct rtc_device *rtc; 167 int retval = -EBUSY; 168 int i; 169 int temp; 170 171 if (pdev->num_resources != 1) 172 return -EBUSY; 173 174 if (pdev->resource[0].flags != IORESOURCE_MEM) 175 return -EBUSY; 176 177 chip = kzalloc(sizeof *chip, GFP_KERNEL); 178 if (!chip) 179 return -ENOMEM; 180 181 chip->leftshift = pdata->leftshift; 182 chip->ioaddress = ioremap(pdev->resource[0].start, 1); 183 if (chip->ioaddress == NULL) 184 goto err_chip; 185 186 /* Make sure the v3020 expects a communication cycle 187 * by reading 8 times */ 188 for (i = 0; i < 8; i++) 189 temp = readl(chip->ioaddress); 190 191 /* Test chip by doing a write/read sequence 192 * to the chip ram */ 193 v3020_set_reg(chip, V3020_SECONDS, 0x33); 194 if(v3020_get_reg(chip, V3020_SECONDS) != 0x33) { 195 retval = -ENODEV; 196 goto err_io; 197 } 198 199 /* Make sure frequency measurment mode, test modes, and lock 200 * are all disabled */ 201 v3020_set_reg(chip, V3020_STATUS_0, 0x0); 202 203 dev_info(&pdev->dev, "Chip available at physical address 0x%llx," 204 "data connected to D%d\n", 205 (unsigned long long)pdev->resource[0].start, 206 chip->leftshift); 207 208 platform_set_drvdata(pdev, chip); 209 210 rtc = rtc_device_register("v3020", 211 &pdev->dev, &v3020_rtc_ops, THIS_MODULE); 212 if (IS_ERR(rtc)) { 213 retval = PTR_ERR(rtc); 214 goto err_io; 215 } 216 chip->rtc = rtc; 217 218 return 0; 219 220err_io: 221 iounmap(chip->ioaddress); 222err_chip: 223 kfree(chip); 224 225 return retval; 226} 227 228static int rtc_remove(struct platform_device *dev) 229{ 230 struct v3020 *chip = platform_get_drvdata(dev); 231 struct rtc_device *rtc = chip->rtc; 232 233 if (rtc) 234 rtc_device_unregister(rtc); 235 236 iounmap(chip->ioaddress); 237 kfree(chip); 238 239 return 0; 240} 241 242static struct platform_driver rtc_device_driver = { 243 .probe = rtc_probe, 244 .remove = rtc_remove, 245 .driver = { 246 .name = "v3020", 247 .owner = THIS_MODULE, 248 }, 249}; 250 251static __init int v3020_init(void) 252{ 253 return platform_driver_register(&rtc_device_driver); 254} 255 256static __exit void v3020_exit(void) 257{ 258 platform_driver_unregister(&rtc_device_driver); 259} 260 261module_init(v3020_init); 262module_exit(v3020_exit); 263 264MODULE_DESCRIPTION("V3020 RTC"); 265MODULE_AUTHOR("Raphael Assenat"); 266MODULE_LICENSE("GPL"); 267MODULE_ALIAS("platform:v3020");