aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLan Chunhe-B25806 <b25806@freescale.com>2010-10-27 18:33:12 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-10-27 21:03:06 -0400
commitf46418c5cadfe76b15c630ff746ca859a8207d71 (patch)
tree06f596a1bb7801eff7d05171953555bbad45d8d9
parent5b3ffddd8ddb4712dfe14ad3e23eb5494f11bf61 (diff)
drivers/rtc/rtc-ds3232.c: add alarm function
The DS3232 RTC driver only has the tick function. Add an alarm function so the driver is complete. Signed-off-by: Lan Chunhe-B25806 <b25806@freescale.com> Cc: Alessandro Zummo <a.zummo@towertech.it> Cc: Wan ZongShun <mcuos.com@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/rtc/Kconfig3
-rw-r--r--drivers/rtc/rtc-ds3232.c181
2 files changed, 183 insertions, 1 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 636ba8224884..6a77437d4f5a 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -171,7 +171,8 @@ config RTC_DRV_DS3232
171 depends on RTC_CLASS && I2C 171 depends on RTC_CLASS && I2C
172 help 172 help
173 If you say yes here you get support for Dallas Semiconductor 173 If you say yes here you get support for Dallas Semiconductor
174 DS3232 real-time clock chips. 174 DS3232 real-time clock chips. If an interrupt is associated
175 with the device, the alarm functionality is supported.
175 176
176 This driver can also be built as a module. If so, the module 177 This driver can also be built as a module. If so, the module
177 will be called rtc-ds3232. 178 will be called rtc-ds3232.
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 */
184static 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;
221out:
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 */
230static 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 }
274out:
275 mutex_unlock(&ds3232->mutex);
276 return ret;
277}
278
279static 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
317unlock:
318 mutex_unlock(&ds3232->mutex);
319}
320
321static 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
338static 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
178static irqreturn_t ds3232_irq(int irq, void *dev_id) 355static 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:
222static const struct rtc_class_ops ds3232_rtc_ops = { 399static 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
227static int __devinit ds3232_probe(struct i2c_client *client, 408static int __devinit ds3232_probe(struct i2c_client *client,