diff options
Diffstat (limited to 'drivers/rtc/rtc-ds3232.c')
| -rw-r--r-- | drivers/rtc/rtc-ds3232.c | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 9de8516e3531..57063552d3b7 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * RTC client/driver for the Maxim/Dallas DS3232 Real-Time Clock over I2C | 2 | * RTC client/driver for the Maxim/Dallas DS3232 Real-Time Clock over I2C |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2009-2010 Freescale Semiconductor. | 4 | * Copyright (C) 2009-2010 Freescale Semiconductor. |
| 5 | * Author: Jack Lan <jack.lan@freescale.com> | ||
| 5 | * | 6 | * |
| 6 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
| 7 | * under the terms of the GNU General Public License as published by the | 8 | * under the terms of the GNU General Public License as published by the |
| @@ -175,6 +176,182 @@ static int ds3232_set_time(struct device *dev, struct rtc_time *time) | |||
| 175 | DS3232_REG_SECONDS, 7, buf); | 176 | DS3232_REG_SECONDS, 7, buf); |
| 176 | } | 177 | } |
| 177 | 178 | ||
| 179 | /* | ||
| 180 | * DS3232 has two alarm, we only use alarm1 | ||
| 181 | * According to linux specification, only support one-shot alarm | ||
| 182 | * no periodic alarm mode | ||
| 183 | */ | ||
| 184 | static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | ||
| 185 | { | ||
| 186 | struct i2c_client *client = to_i2c_client(dev); | ||
| 187 | struct ds3232 *ds3232 = i2c_get_clientdata(client); | ||
| 188 | int control, stat; | ||
| 189 | int ret; | ||
| 190 | u8 buf[4]; | ||
| 191 | |||
| 192 | mutex_lock(&ds3232->mutex); | ||
| 193 | |||
| 194 | ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR); | ||
| 195 | if (ret < 0) | ||
| 196 | goto out; | ||
| 197 | stat = ret; | ||
| 198 | ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR); | ||
| 199 | if (ret < 0) | ||
| 200 | goto out; | ||
| 201 | control = ret; | ||
| 202 | ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); | ||
| 203 | if (ret < 0) | ||
| 204 | goto out; | ||
| 205 | |||
| 206 | alarm->time.tm_sec = bcd2bin(buf[0] & 0x7F); | ||
| 207 | alarm->time.tm_min = bcd2bin(buf[1] & 0x7F); | ||
| 208 | alarm->time.tm_hour = bcd2bin(buf[2] & 0x7F); | ||
| 209 | alarm->time.tm_mday = bcd2bin(buf[3] & 0x7F); | ||
| 210 | |||
| 211 | alarm->time.tm_mon = -1; | ||
| 212 | alarm->time.tm_year = -1; | ||
| 213 | alarm->time.tm_wday = -1; | ||
| 214 | alarm->time.tm_yday = -1; | ||
| 215 | alarm->time.tm_isdst = -1; | ||
| 216 | |||
| 217 | alarm->enabled = !!(control & DS3232_REG_CR_A1IE); | ||
| 218 | alarm->pending = !!(stat & DS3232_REG_SR_A1F); | ||
| 219 | |||
| 220 | ret = 0; | ||
| 221 | out: | ||
| 222 | mutex_unlock(&ds3232->mutex); | ||
| 223 | return ret; | ||
| 224 | } | ||
| 225 | |||
| 226 | /* | ||
| 227 | * linux rtc-module does not support wday alarm | ||
| 228 | * and only 24h time mode supported indeed | ||
| 229 | */ | ||
| 230 | static int ds3232_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) | ||
| 231 | { | ||
| 232 | struct i2c_client *client = to_i2c_client(dev); | ||
| 233 | struct ds3232 *ds3232 = i2c_get_clientdata(client); | ||
| 234 | int control, stat; | ||
| 235 | int ret; | ||
| 236 | u8 buf[4]; | ||
| 237 | |||
| 238 | if (client->irq <= 0) | ||
| 239 | return -EINVAL; | ||
| 240 | |||
| 241 | mutex_lock(&ds3232->mutex); | ||
| 242 | |||
| 243 | buf[0] = bin2bcd(alarm->time.tm_sec); | ||
| 244 | buf[1] = bin2bcd(alarm->time.tm_min); | ||
| 245 | buf[2] = bin2bcd(alarm->time.tm_hour); | ||
| 246 | buf[3] = bin2bcd(alarm->time.tm_mday); | ||
| 247 | |||
| 248 | /* clear alarm interrupt enable bit */ | ||
| 249 | ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR); | ||
| 250 | if (ret < 0) | ||
| 251 | goto out; | ||
| 252 | control = ret; | ||
| 253 | control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE); | ||
| 254 | ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); | ||
| 255 | if (ret < 0) | ||
| 256 | goto out; | ||
| 257 | |||
| 258 | /* clear any pending alarm flag */ | ||
| 259 | ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR); | ||
| 260 | if (ret < 0) | ||
| 261 | goto out; | ||
| 262 | stat = ret; | ||
| 263 | stat &= ~(DS3232_REG_SR_A1F | DS3232_REG_SR_A2F); | ||
| 264 | ret = i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); | ||
| 265 | if (ret < 0) | ||
| 266 | goto out; | ||
| 267 | |||
| 268 | ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); | ||
| 269 | |||
| 270 | if (alarm->enabled) { | ||
| 271 | control |= DS3232_REG_CR_A1IE; | ||
| 272 | ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); | ||
| 273 | } | ||
| 274 | out: | ||
| 275 | mutex_unlock(&ds3232->mutex); | ||
| 276 | return ret; | ||
| 277 | } | ||
| 278 | |||
| 279 | static void ds3232_update_alarm(struct i2c_client *client) | ||
| 280 | { | ||
| 281 | struct ds3232 *ds3232 = i2c_get_clientdata(client); | ||
| 282 | int control; | ||
| 283 | int ret; | ||
| 284 | u8 buf[4]; | ||
| 285 | |||
| 286 | mutex_lock(&ds3232->mutex); | ||
| 287 | |||
| 288 | ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); | ||
| 289 | if (ret < 0) | ||
| 290 | goto unlock; | ||
| 291 | |||
| 292 | buf[0] = bcd2bin(buf[0]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? | ||
| 293 | 0x80 : buf[0]; | ||
| 294 | buf[1] = bcd2bin(buf[1]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? | ||
| 295 | 0x80 : buf[1]; | ||
| 296 | buf[2] = bcd2bin(buf[2]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? | ||
| 297 | 0x80 : buf[2]; | ||
| 298 | buf[3] = bcd2bin(buf[3]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? | ||
| 299 | 0x80 : buf[3]; | ||
| 300 | |||
| 301 | ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); | ||
| 302 | if (ret < 0) | ||
| 303 | goto unlock; | ||
| 304 | |||
| 305 | control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); | ||
| 306 | if (control < 0) | ||
| 307 | goto unlock; | ||
| 308 | |||
| 309 | if (ds3232->rtc->irq_data & (RTC_AF | RTC_UF)) | ||
| 310 | /* enable alarm1 interrupt */ | ||
| 311 | control |= DS3232_REG_CR_A1IE; | ||
| 312 | else | ||
| 313 | /* disable alarm1 interrupt */ | ||
| 314 | control &= ~(DS3232_REG_CR_A1IE); | ||
| 315 | i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); | ||
| 316 | |||
| 317 | unlock: | ||
| 318 | mutex_unlock(&ds3232->mutex); | ||
| 319 | } | ||
| 320 | |||
| 321 | static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled) | ||
| 322 | { | ||
| 323 | struct i2c_client *client = to_i2c_client(dev); | ||
| 324 | struct ds3232 *ds3232 = i2c_get_clientdata(client); | ||
| 325 | |||
| 326 | if (client->irq <= 0) | ||
| 327 | return -EINVAL; | ||
| 328 | |||
| 329 | if (enabled) | ||
| 330 | ds3232->rtc->irq_data |= RTC_AF; | ||
| 331 | else | ||
| 332 | ds3232->rtc->irq_data &= ~RTC_AF; | ||
| 333 | |||
| 334 | ds3232_update_alarm(client); | ||
| 335 | return 0; | ||
| 336 | } | ||
| 337 | |||
| 338 | static int ds3232_update_irq_enable(struct device *dev, unsigned int enabled) | ||
| 339 | { | ||
| 340 | struct i2c_client *client = to_i2c_client(dev); | ||
| 341 | struct ds3232 *ds3232 = i2c_get_clientdata(client); | ||
| 342 | |||
| 343 | if (client->irq <= 0) | ||
| 344 | return -EINVAL; | ||
| 345 | |||
| 346 | if (enabled) | ||
| 347 | ds3232->rtc->irq_data |= RTC_UF; | ||
| 348 | else | ||
| 349 | ds3232->rtc->irq_data &= ~RTC_UF; | ||
| 350 | |||
| 351 | ds3232_update_alarm(client); | ||
| 352 | return 0; | ||
| 353 | } | ||
| 354 | |||
| 178 | static irqreturn_t ds3232_irq(int irq, void *dev_id) | 355 | static irqreturn_t ds3232_irq(int irq, void *dev_id) |
| 179 | { | 356 | { |
| 180 | struct i2c_client *client = dev_id; | 357 | struct i2c_client *client = dev_id; |
| @@ -222,6 +399,10 @@ unlock: | |||
| 222 | static const struct rtc_class_ops ds3232_rtc_ops = { | 399 | static const struct rtc_class_ops ds3232_rtc_ops = { |
| 223 | .read_time = ds3232_read_time, | 400 | .read_time = ds3232_read_time, |
| 224 | .set_time = ds3232_set_time, | 401 | .set_time = ds3232_set_time, |
| 402 | .read_alarm = ds3232_read_alarm, | ||
| 403 | .set_alarm = ds3232_set_alarm, | ||
| 404 | .alarm_irq_enable = ds3232_alarm_irq_enable, | ||
| 405 | .update_irq_enable = ds3232_update_irq_enable, | ||
| 225 | }; | 406 | }; |
| 226 | 407 | ||
| 227 | static int __devinit ds3232_probe(struct i2c_client *client, | 408 | static int __devinit ds3232_probe(struct i2c_client *client, |
