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 v3.8-rc7 326 lines 7.0 kB view raw
1/* 2 * Copyright (C) 2012 Avionic Design GmbH 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9#include <linux/bcd.h> 10#include <linux/i2c.h> 11#include <linux/module.h> 12#include <linux/rtc.h> 13#include <linux/of.h> 14 15#define DRIVER_NAME "rtc-pcf8523" 16 17#define REG_CONTROL1 0x00 18#define REG_CONTROL1_CAP_SEL (1 << 7) 19#define REG_CONTROL1_STOP (1 << 5) 20 21#define REG_CONTROL3 0x02 22#define REG_CONTROL3_PM_BLD (1 << 7) /* battery low detection disabled */ 23#define REG_CONTROL3_PM_VDD (1 << 6) /* switch-over disabled */ 24#define REG_CONTROL3_PM_DSM (1 << 5) /* direct switching mode */ 25#define REG_CONTROL3_PM_MASK 0xe0 26 27#define REG_SECONDS 0x03 28#define REG_SECONDS_OS (1 << 7) 29 30#define REG_MINUTES 0x04 31#define REG_HOURS 0x05 32#define REG_DAYS 0x06 33#define REG_WEEKDAYS 0x07 34#define REG_MONTHS 0x08 35#define REG_YEARS 0x09 36 37struct pcf8523 { 38 struct rtc_device *rtc; 39}; 40 41static int pcf8523_read(struct i2c_client *client, u8 reg, u8 *valuep) 42{ 43 struct i2c_msg msgs[2]; 44 u8 value = 0; 45 int err; 46 47 msgs[0].addr = client->addr; 48 msgs[0].flags = 0; 49 msgs[0].len = sizeof(reg); 50 msgs[0].buf = &reg; 51 52 msgs[1].addr = client->addr; 53 msgs[1].flags = I2C_M_RD; 54 msgs[1].len = sizeof(value); 55 msgs[1].buf = &value; 56 57 err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 58 if (err < 0) 59 return err; 60 61 *valuep = value; 62 63 return 0; 64} 65 66static int pcf8523_write(struct i2c_client *client, u8 reg, u8 value) 67{ 68 u8 buffer[2] = { reg, value }; 69 struct i2c_msg msg; 70 int err; 71 72 msg.addr = client->addr; 73 msg.flags = 0; 74 msg.len = sizeof(buffer); 75 msg.buf = buffer; 76 77 err = i2c_transfer(client->adapter, &msg, 1); 78 if (err < 0) 79 return err; 80 81 return 0; 82} 83 84static int pcf8523_select_capacitance(struct i2c_client *client, bool high) 85{ 86 u8 value; 87 int err; 88 89 err = pcf8523_read(client, REG_CONTROL1, &value); 90 if (err < 0) 91 return err; 92 93 if (!high) 94 value &= ~REG_CONTROL1_CAP_SEL; 95 else 96 value |= REG_CONTROL1_CAP_SEL; 97 98 err = pcf8523_write(client, REG_CONTROL1, value); 99 if (err < 0) 100 return err; 101 102 return err; 103} 104 105static int pcf8523_set_pm(struct i2c_client *client, u8 pm) 106{ 107 u8 value; 108 int err; 109 110 err = pcf8523_read(client, REG_CONTROL3, &value); 111 if (err < 0) 112 return err; 113 114 value = (value & ~REG_CONTROL3_PM_MASK) | pm; 115 116 err = pcf8523_write(client, REG_CONTROL3, value); 117 if (err < 0) 118 return err; 119 120 return 0; 121} 122 123static int pcf8523_stop_rtc(struct i2c_client *client) 124{ 125 u8 value; 126 int err; 127 128 err = pcf8523_read(client, REG_CONTROL1, &value); 129 if (err < 0) 130 return err; 131 132 value |= REG_CONTROL1_STOP; 133 134 err = pcf8523_write(client, REG_CONTROL1, value); 135 if (err < 0) 136 return err; 137 138 return 0; 139} 140 141static int pcf8523_start_rtc(struct i2c_client *client) 142{ 143 u8 value; 144 int err; 145 146 err = pcf8523_read(client, REG_CONTROL1, &value); 147 if (err < 0) 148 return err; 149 150 value &= ~REG_CONTROL1_STOP; 151 152 err = pcf8523_write(client, REG_CONTROL1, value); 153 if (err < 0) 154 return err; 155 156 return 0; 157} 158 159static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) 160{ 161 struct i2c_client *client = to_i2c_client(dev); 162 u8 start = REG_SECONDS, regs[7]; 163 struct i2c_msg msgs[2]; 164 int err; 165 166 msgs[0].addr = client->addr; 167 msgs[0].flags = 0; 168 msgs[0].len = 1; 169 msgs[0].buf = &start; 170 171 msgs[1].addr = client->addr; 172 msgs[1].flags = I2C_M_RD; 173 msgs[1].len = sizeof(regs); 174 msgs[1].buf = regs; 175 176 err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 177 if (err < 0) 178 return err; 179 180 if (regs[0] & REG_SECONDS_OS) { 181 /* 182 * If the oscillator was stopped, try to clear the flag. Upon 183 * power-up the flag is always set, but if we cannot clear it 184 * the oscillator isn't running properly for some reason. The 185 * sensible thing therefore is to return an error, signalling 186 * that the clock cannot be assumed to be correct. 187 */ 188 189 regs[0] &= ~REG_SECONDS_OS; 190 191 err = pcf8523_write(client, REG_SECONDS, regs[0]); 192 if (err < 0) 193 return err; 194 195 err = pcf8523_read(client, REG_SECONDS, &regs[0]); 196 if (err < 0) 197 return err; 198 199 if (regs[0] & REG_SECONDS_OS) 200 return -EAGAIN; 201 } 202 203 tm->tm_sec = bcd2bin(regs[0] & 0x7f); 204 tm->tm_min = bcd2bin(regs[1] & 0x7f); 205 tm->tm_hour = bcd2bin(regs[2] & 0x3f); 206 tm->tm_mday = bcd2bin(regs[3] & 0x3f); 207 tm->tm_wday = regs[4] & 0x7; 208 tm->tm_mon = bcd2bin(regs[5] & 0x1f); 209 tm->tm_year = bcd2bin(regs[6]) + 100; 210 211 return rtc_valid_tm(tm); 212} 213 214static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm) 215{ 216 struct i2c_client *client = to_i2c_client(dev); 217 struct i2c_msg msg; 218 u8 regs[8]; 219 int err; 220 221 err = pcf8523_stop_rtc(client); 222 if (err < 0) 223 return err; 224 225 regs[0] = REG_SECONDS; 226 regs[1] = bin2bcd(tm->tm_sec); 227 regs[2] = bin2bcd(tm->tm_min); 228 regs[3] = bin2bcd(tm->tm_hour); 229 regs[4] = bin2bcd(tm->tm_mday); 230 regs[5] = tm->tm_wday; 231 regs[6] = bin2bcd(tm->tm_mon); 232 regs[7] = bin2bcd(tm->tm_year - 100); 233 234 msg.addr = client->addr; 235 msg.flags = 0; 236 msg.len = sizeof(regs); 237 msg.buf = regs; 238 239 err = i2c_transfer(client->adapter, &msg, 1); 240 if (err < 0) { 241 /* 242 * If the time cannot be set, restart the RTC anyway. Note 243 * that errors are ignored if the RTC cannot be started so 244 * that we have a chance to propagate the original error. 245 */ 246 pcf8523_start_rtc(client); 247 return err; 248 } 249 250 return pcf8523_start_rtc(client); 251} 252 253static const struct rtc_class_ops pcf8523_rtc_ops = { 254 .read_time = pcf8523_rtc_read_time, 255 .set_time = pcf8523_rtc_set_time, 256}; 257 258static int pcf8523_probe(struct i2c_client *client, 259 const struct i2c_device_id *id) 260{ 261 struct pcf8523 *pcf; 262 int err; 263 264 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) 265 return -ENODEV; 266 267 pcf = devm_kzalloc(&client->dev, sizeof(*pcf), GFP_KERNEL); 268 if (!pcf) 269 return -ENOMEM; 270 271 err = pcf8523_select_capacitance(client, true); 272 if (err < 0) 273 return err; 274 275 err = pcf8523_set_pm(client, 0); 276 if (err < 0) 277 return err; 278 279 pcf->rtc = rtc_device_register(DRIVER_NAME, &client->dev, 280 &pcf8523_rtc_ops, THIS_MODULE); 281 if (IS_ERR(pcf->rtc)) 282 return PTR_ERR(pcf->rtc); 283 284 i2c_set_clientdata(client, pcf); 285 286 return 0; 287} 288 289static int pcf8523_remove(struct i2c_client *client) 290{ 291 struct pcf8523 *pcf = i2c_get_clientdata(client); 292 293 rtc_device_unregister(pcf->rtc); 294 295 return 0; 296} 297 298static const struct i2c_device_id pcf8523_id[] = { 299 { "pcf8523", 0 }, 300 { } 301}; 302MODULE_DEVICE_TABLE(i2c, pcf8523_id); 303 304#ifdef CONFIG_OF 305static const struct of_device_id pcf8523_of_match[] = { 306 { .compatible = "nxp,pcf8523" }, 307 { } 308}; 309MODULE_DEVICE_TABLE(of, pcf8523_of_match); 310#endif 311 312static struct i2c_driver pcf8523_driver = { 313 .driver = { 314 .name = DRIVER_NAME, 315 .owner = THIS_MODULE, 316 .of_match_table = of_match_ptr(pcf8523_of_match), 317 }, 318 .probe = pcf8523_probe, 319 .remove = pcf8523_remove, 320 .id_table = pcf8523_id, 321}; 322module_i2c_driver(pcf8523_driver); 323 324MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); 325MODULE_DESCRIPTION("NXP PCF8523 RTC driver"); 326MODULE_LICENSE("GPL v2");