diff options
Diffstat (limited to 'drivers/rtc/rtc-rs5c372.c')
| -rw-r--r-- | drivers/rtc/rtc-rs5c372.c | 117 |
1 files changed, 38 insertions, 79 deletions
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index 2f2c68d476d..ccf54f06396 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -13,6 +13,8 @@ #include <linux/i2c.h> #include <linux/rtc.h> #include <linux/bcd.h> +#include <linux/slab.h> +#include <linux/module.h> #define DRV_VERSION "0.6" @@ -66,6 +68,7 @@ enum rtc_type { rtc_undef = 0, rtc_r2025sd, + rtc_r2221tl, rtc_rs5c372a, rtc_rs5c372b, rtc_rv5c386, @@ -74,6 +77,7 @@ enum rtc_type { static const struct i2c_device_id rs5c372_id[] = { { "r2025sd", rtc_r2025sd }, + { "r2221tl", rtc_r2221tl }, { "rs5c372a", rtc_rs5c372a }, { "rs5c372b", rtc_rs5c372b }, { "rv5c386", rtc_rv5c386 }, @@ -102,7 +106,12 @@ static int rs5c_get_regs(struct rs5c372 *rs5c) { struct i2c_client *client = rs5c->client; struct i2c_msg msgs[] = { - { client->addr, I2C_M_RD, sizeof rs5c->buf, rs5c->buf }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = sizeof(rs5c->buf), + .buf = rs5c->buf + }, }; /* This implements the third reading method from the datasheet, using @@ -206,7 +215,7 @@ static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm) static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm) { struct rs5c372 *rs5c = i2c_get_clientdata(client); - unsigned char buf[8]; + unsigned char buf[7]; int addr; dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d " @@ -280,10 +289,8 @@ static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm) return rs5c372_set_datetime(to_i2c_client(dev), tm); } -#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE) -static int -rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +static int rs5c_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct i2c_client *client = to_i2c_client(dev); struct rs5c372 *rs5c = i2c_get_clientdata(client); @@ -291,49 +298,22 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) int status, addr; buf = rs5c->regs[RS5C_REG_CTRL1]; - switch (cmd) { - case RTC_UIE_OFF: - case RTC_UIE_ON: - /* some 327a modes use a different IRQ pin for 1Hz irqs */ - if (rs5c->type == rtc_rs5c372a - && (buf & RS5C372A_CTRL1_SL1)) - return -ENOIOCTLCMD; - case RTC_AIE_OFF: - case RTC_AIE_ON: - /* these irq management calls only make sense for chips - * which are wired up to an IRQ. - */ - if (!rs5c->has_irq) - return -ENOIOCTLCMD; - break; - default: - return -ENOIOCTLCMD; - } + + if (!rs5c->has_irq) + return -EINVAL; status = rs5c_get_regs(rs5c); if (status < 0) return status; addr = RS5C_ADDR(RS5C_REG_CTRL1); - switch (cmd) { - case RTC_AIE_OFF: /* alarm off */ - buf &= ~RS5C_CTRL1_AALE; - break; - case RTC_AIE_ON: /* alarm on */ + if (enabled) buf |= RS5C_CTRL1_AALE; - break; - case RTC_UIE_OFF: /* update off */ - buf &= ~RS5C_CTRL1_CT_MASK; - break; - case RTC_UIE_ON: /* update on */ - buf &= ~RS5C_CTRL1_CT_MASK; - buf |= RS5C_CTRL1_CT4; - break; - } + else + buf &= ~RS5C_CTRL1_AALE; if (i2c_smbus_write_byte_data(client, addr, buf) < 0) { - printk(KERN_WARNING "%s: can't update alarm\n", - rs5c->rtc->name); + dev_warn(dev, "can't update alarm\n"); status = -EIO; } else rs5c->regs[RS5C_REG_CTRL1] = buf; @@ -341,10 +321,6 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) return status; } -#else -#define rs5c_rtc_ioctl NULL -#endif - /* NOTE: Since RTC_WKALM_{RD,SET} were originally defined for EFI, * which only exposes a polled programming interface; and since @@ -406,7 +382,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t) addr = RS5C_ADDR(RS5C_REG_CTRL1); buf[0] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE; if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0) { - pr_debug("%s: can't disable alarm\n", rs5c->rtc->name); + dev_dbg(dev, "can't disable alarm\n"); return -EIO; } rs5c->regs[RS5C_REG_CTRL1] = buf[0]; @@ -420,7 +396,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t) for (i = 0; i < sizeof(buf); i++) { addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i); if (i2c_smbus_write_byte_data(client, addr, buf[i]) < 0) { - pr_debug("%s: can't set alarm time\n", rs5c->rtc->name); + dev_dbg(dev, "can't set alarm time\n"); return -EIO; } } @@ -430,8 +406,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t) addr = RS5C_ADDR(RS5C_REG_CTRL1); buf[0] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE; if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0) - printk(KERN_WARNING "%s: can't enable alarm\n", - rs5c->rtc->name); + dev_warn(dev, "can't enable alarm\n"); rs5c->regs[RS5C_REG_CTRL1] = buf[0]; } @@ -460,11 +435,11 @@ static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq) static const struct rtc_class_ops rs5c372_rtc_ops = { .proc = rs5c372_rtc_proc, - .ioctl = rs5c_rtc_ioctl, .read_time = rs5c372_rtc_read_time, .set_time = rs5c372_rtc_set_time, .read_alarm = rs5c_read_alarm, .set_alarm = rs5c_set_alarm, + .alarm_irq_enable = rs5c_rtc_alarm_irq_enable, }; #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE) @@ -556,6 +531,7 @@ static int rs5c_oscillator_setup(struct rs5c372 *rs5c372) rs5c372->time24 = 1; break; case rtc_r2025sd: + case rtc_r2221tl: case rtc_rv5c386: case rtc_rv5c387a: buf[0] |= RV5C387_CTRL1_24; @@ -606,7 +582,9 @@ static int rs5c372_probe(struct i2c_client *client, } } - if (!(rs5c372 = kzalloc(sizeof(struct rs5c372), GFP_KERNEL))) { + rs5c372 = devm_kzalloc(&client->dev, sizeof(struct rs5c372), + GFP_KERNEL); + if (!rs5c372) { err = -ENOMEM; goto exit; } @@ -621,7 +599,7 @@ static int rs5c372_probe(struct i2c_client *client, err = rs5c_get_regs(rs5c372); if (err < 0) - goto exit_kfree; + goto exit; /* clock may be set for am/pm or 24 hr time */ switch (rs5c372->type) { @@ -634,6 +612,7 @@ static int rs5c372_probe(struct i2c_client *client, rs5c372->time24 = 1; break; case rtc_r2025sd: + case rtc_r2221tl: case rtc_rv5c386: case rtc_rv5c387a: if (rs5c372->regs[RS5C_REG_CTRL1] & RV5C387_CTRL1_24) @@ -644,7 +623,7 @@ static int rs5c372_probe(struct i2c_client *client, break; default: dev_err(&client->dev, "unknown RTC type\n"); - goto exit_kfree; + goto exit; } /* if the oscillator lost power and no other software (like @@ -656,7 +635,7 @@ static int rs5c372_probe(struct i2c_client *client, err = rs5c_oscillator_setup(rs5c372); if (unlikely(err < 0)) { dev_err(&client->dev, "setup error\n"); - goto exit_kfree; + goto exit; } if (rs5c372_get_datetime(client, &tm) < 0) @@ -665,6 +644,7 @@ static int rs5c372_probe(struct i2c_client *client, dev_info(&client->dev, "%s found, %s, driver version " DRV_VERSION "\n", ({ char *s; switch (rs5c372->type) { case rtc_r2025sd: s = "r2025sd"; break; + case rtc_r2221tl: s = "r2221tl"; break; case rtc_rs5c372a: s = "rs5c372a"; break; case rtc_rs5c372b: s = "rs5c372b"; break; case rtc_rv5c386: s = "rv5c386"; break; @@ -675,38 +655,28 @@ static int rs5c372_probe(struct i2c_client *client, ); /* REVISIT use client->irq to register alarm irq ... */ - - rs5c372->rtc = rtc_device_register(rs5c372_driver.driver.name, - &client->dev, &rs5c372_rtc_ops, THIS_MODULE); + rs5c372->rtc = devm_rtc_device_register(&client->dev, + rs5c372_driver.driver.name, + &rs5c372_rtc_ops, THIS_MODULE); if (IS_ERR(rs5c372->rtc)) { err = PTR_ERR(rs5c372->rtc); - goto exit_kfree; + goto exit; } err = rs5c_sysfs_register(&client->dev); if (err) - goto exit_devreg; + goto exit; return 0; -exit_devreg: - rtc_device_unregister(rs5c372->rtc); - -exit_kfree: - kfree(rs5c372); - exit: return err; } static int rs5c372_remove(struct i2c_client *client) { - struct rs5c372 *rs5c372 = i2c_get_clientdata(client); - - rtc_device_unregister(rs5c372->rtc); rs5c_sysfs_unregister(&client->dev); - kfree(rs5c372); return 0; } @@ -719,18 +689,7 @@ static struct i2c_driver rs5c372_driver = { .id_table = rs5c372_id, }; -static __init int rs5c372_init(void) -{ - return i2c_add_driver(&rs5c372_driver); -} - -static __exit void rs5c372_exit(void) -{ - i2c_del_driver(&rs5c372_driver); -} - -module_init(rs5c372_init); -module_exit(rs5c372_exit); +module_i2c_driver(rs5c372_driver); MODULE_AUTHOR( "Pavel Mironchik <pmironchik@optifacio.net>, " |
