rtc: ds3232: convert to use regmap

This is preparation for merging rtc-ds3232 i2c driver and rtc-ds3234
spi driver.

Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Dennis Aberilla <denzzzhome@yahoo.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
This commit is contained in:
Akinobu Mita 2016-03-07 00:27:47 +09:00 committed by Alexandre Belloni
parent 832315b05b
commit 370927c4b6
1 changed files with 113 additions and 103 deletions

View File

@ -9,11 +9,6 @@
* Free Software Foundation; either version 2 of the License, or (at your * Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. * option) any later version.
*/ */
/*
* It would be more efficient to use i2c msgs/i2c_transfer directly but, as
* recommened in .../Documentation/i2c/writing-clients section
* "Sending and receiving", using SMBus level communication is preferred.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@ -25,6 +20,7 @@
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/regmap.h>
#define DS3232_REG_SECONDS 0x00 #define DS3232_REG_SECONDS 0x00
#define DS3232_REG_MINUTES 0x01 #define DS3232_REG_MINUTES 0x01
@ -50,7 +46,9 @@
# define DS3232_REG_SR_A1F 0x01 # define DS3232_REG_SR_A1F 0x01
struct ds3232 { struct ds3232 {
struct i2c_client *client; struct device *dev;
struct regmap *regmap;
int irq;
struct rtc_device *rtc; struct rtc_device *rtc;
struct work_struct work; struct work_struct work;
@ -63,26 +61,25 @@ struct ds3232 {
int exiting; int exiting;
}; };
static struct i2c_driver ds3232_driver; static int ds3232_check_rtc_status(struct device *dev)
static int ds3232_check_rtc_status(struct i2c_client *client)
{ {
struct ds3232 *ds3232 = dev_get_drvdata(dev);
int ret = 0; int ret = 0;
int control, stat; int control, stat;
stat = i2c_smbus_read_byte_data(client, DS3232_REG_SR); ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat);
if (stat < 0) if (ret)
return stat; return ret;
if (stat & DS3232_REG_SR_OSF) if (stat & DS3232_REG_SR_OSF)
dev_warn(&client->dev, dev_warn(dev,
"oscillator discontinuity flagged, " "oscillator discontinuity flagged, "
"time unreliable\n"); "time unreliable\n");
stat &= ~(DS3232_REG_SR_OSF | DS3232_REG_SR_A1F | DS3232_REG_SR_A2F); stat &= ~(DS3232_REG_SR_OSF | DS3232_REG_SR_A1F | DS3232_REG_SR_A2F);
ret = i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat);
if (ret < 0) if (ret)
return ret; return ret;
/* If the alarm is pending, clear it before requesting /* If the alarm is pending, clear it before requesting
@ -90,31 +87,28 @@ static int ds3232_check_rtc_status(struct i2c_client *client)
* before everything is initialized. * before everything is initialized.
*/ */
control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
if (control < 0) if (ret)
return control; return ret;
control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE); control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE);
control |= DS3232_REG_CR_INTCN; control |= DS3232_REG_CR_INTCN;
return i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); return regmap_write(ds3232->regmap, DS3232_REG_CR, control);
} }
static int ds3232_read_time(struct device *dev, struct rtc_time *time) static int ds3232_read_time(struct device *dev, struct rtc_time *time)
{ {
struct i2c_client *client = to_i2c_client(dev); struct ds3232 *ds3232 = dev_get_drvdata(dev);
int ret; int ret;
u8 buf[7]; u8 buf[7];
unsigned int year, month, day, hour, minute, second; unsigned int year, month, day, hour, minute, second;
unsigned int week, twelve_hr, am_pm; unsigned int week, twelve_hr, am_pm;
unsigned int century, add_century = 0; unsigned int century, add_century = 0;
ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_SECONDS, 7, buf); ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_SECONDS, buf, 7);
if (ret)
if (ret < 0)
return ret; return ret;
if (ret < 7)
return -EIO;
second = buf[0]; second = buf[0];
minute = buf[1]; minute = buf[1];
@ -159,7 +153,7 @@ static int ds3232_read_time(struct device *dev, struct rtc_time *time)
static int ds3232_set_time(struct device *dev, struct rtc_time *time) static int ds3232_set_time(struct device *dev, struct rtc_time *time)
{ {
struct i2c_client *client = to_i2c_client(dev); struct ds3232 *ds3232 = dev_get_drvdata(dev);
u8 buf[7]; u8 buf[7];
/* Extract time from rtc_time and load into ds3232*/ /* Extract time from rtc_time and load into ds3232*/
@ -179,8 +173,7 @@ static int ds3232_set_time(struct device *dev, struct rtc_time *time)
buf[6] = bin2bcd(time->tm_year); buf[6] = bin2bcd(time->tm_year);
} }
return i2c_smbus_write_i2c_block_data(client, return regmap_bulk_write(ds3232->regmap, DS3232_REG_SECONDS, buf, 7);
DS3232_REG_SECONDS, 7, buf);
} }
/* /*
@ -190,24 +183,21 @@ static int ds3232_set_time(struct device *dev, struct rtc_time *time)
*/ */
static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{ {
struct i2c_client *client = to_i2c_client(dev); struct ds3232 *ds3232 = dev_get_drvdata(dev);
struct ds3232 *ds3232 = i2c_get_clientdata(client);
int control, stat; int control, stat;
int ret; int ret;
u8 buf[4]; u8 buf[4];
mutex_lock(&ds3232->mutex); mutex_lock(&ds3232->mutex);
ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR); ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat);
if (ret < 0) if (ret)
goto out; goto out;
stat = ret; ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR); if (ret)
if (ret < 0)
goto out; goto out;
control = ret; ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_ALARM1, buf, 4);
ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); if (ret)
if (ret < 0)
goto out; goto out;
alarm->time.tm_sec = bcd2bin(buf[0] & 0x7F); alarm->time.tm_sec = bcd2bin(buf[0] & 0x7F);
@ -236,13 +226,12 @@ out:
*/ */
static int ds3232_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) static int ds3232_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{ {
struct i2c_client *client = to_i2c_client(dev); struct ds3232 *ds3232 = dev_get_drvdata(dev);
struct ds3232 *ds3232 = i2c_get_clientdata(client);
int control, stat; int control, stat;
int ret; int ret;
u8 buf[4]; u8 buf[4];
if (client->irq <= 0) if (ds3232->irq <= 0)
return -EINVAL; return -EINVAL;
mutex_lock(&ds3232->mutex); mutex_lock(&ds3232->mutex);
@ -253,47 +242,45 @@ static int ds3232_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
buf[3] = bin2bcd(alarm->time.tm_mday); buf[3] = bin2bcd(alarm->time.tm_mday);
/* clear alarm interrupt enable bit */ /* clear alarm interrupt enable bit */
ret = i2c_smbus_read_byte_data(client, DS3232_REG_CR); ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
if (ret < 0) if (ret)
goto out; goto out;
control = ret;
control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE); control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE);
ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control);
if (ret < 0) if (ret)
goto out; goto out;
/* clear any pending alarm flag */ /* clear any pending alarm flag */
ret = i2c_smbus_read_byte_data(client, DS3232_REG_SR); ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat);
if (ret < 0) if (ret)
goto out; goto out;
stat = ret;
stat &= ~(DS3232_REG_SR_A1F | DS3232_REG_SR_A2F); stat &= ~(DS3232_REG_SR_A1F | DS3232_REG_SR_A2F);
ret = i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat);
if (ret < 0) if (ret)
goto out; goto out;
ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); ret = regmap_bulk_write(ds3232->regmap, DS3232_REG_ALARM1, buf, 4);
if (alarm->enabled) { if (alarm->enabled) {
control |= DS3232_REG_CR_A1IE; control |= DS3232_REG_CR_A1IE;
ret = i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control);
} }
out: out:
mutex_unlock(&ds3232->mutex); mutex_unlock(&ds3232->mutex);
return ret; return ret;
} }
static void ds3232_update_alarm(struct i2c_client *client) static void ds3232_update_alarm(struct device *dev)
{ {
struct ds3232 *ds3232 = i2c_get_clientdata(client); struct ds3232 *ds3232 = dev_get_drvdata(dev);
int control; int control;
int ret; int ret;
u8 buf[4]; u8 buf[4];
mutex_lock(&ds3232->mutex); mutex_lock(&ds3232->mutex);
ret = i2c_smbus_read_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_ALARM1, buf, 4);
if (ret < 0) if (ret)
goto unlock; goto unlock;
buf[0] = bcd2bin(buf[0]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? buf[0] = bcd2bin(buf[0]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
@ -305,12 +292,12 @@ static void ds3232_update_alarm(struct i2c_client *client)
buf[3] = bcd2bin(buf[3]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ? buf[3] = bcd2bin(buf[3]) < 0 || (ds3232->rtc->irq_data & RTC_UF) ?
0x80 : buf[3]; 0x80 : buf[3];
ret = i2c_smbus_write_i2c_block_data(client, DS3232_REG_ALARM1, 4, buf); ret = regmap_bulk_write(ds3232->regmap, DS3232_REG_ALARM1, buf, 4);
if (ret < 0) if (ret)
goto unlock; goto unlock;
control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
if (control < 0) if (ret)
goto unlock; goto unlock;
if (ds3232->rtc->irq_data & (RTC_AF | RTC_UF)) if (ds3232->rtc->irq_data & (RTC_AF | RTC_UF))
@ -319,7 +306,7 @@ static void ds3232_update_alarm(struct i2c_client *client)
else else
/* disable alarm1 interrupt */ /* disable alarm1 interrupt */
control &= ~(DS3232_REG_CR_A1IE); control &= ~(DS3232_REG_CR_A1IE);
i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); regmap_write(ds3232->regmap, DS3232_REG_CR, control);
unlock: unlock:
mutex_unlock(&ds3232->mutex); mutex_unlock(&ds3232->mutex);
@ -327,10 +314,9 @@ unlock:
static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled) static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled)
{ {
struct i2c_client *client = to_i2c_client(dev); struct ds3232 *ds3232 = dev_get_drvdata(dev);
struct ds3232 *ds3232 = i2c_get_clientdata(client);
if (client->irq <= 0) if (ds3232->irq <= 0)
return -EINVAL; return -EINVAL;
if (enabled) if (enabled)
@ -338,14 +324,14 @@ static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled)
else else
ds3232->rtc->irq_data &= ~RTC_AF; ds3232->rtc->irq_data &= ~RTC_AF;
ds3232_update_alarm(client); ds3232_update_alarm(dev);
return 0; return 0;
} }
static irqreturn_t ds3232_irq(int irq, void *dev_id) static irqreturn_t ds3232_irq(int irq, void *dev_id)
{ {
struct i2c_client *client = dev_id; struct device *dev = dev_id;
struct ds3232 *ds3232 = i2c_get_clientdata(client); struct ds3232 *ds3232 = dev_get_drvdata(dev);
disable_irq_nosync(irq); disable_irq_nosync(irq);
@ -363,34 +349,33 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id)
static void ds3232_work(struct work_struct *work) static void ds3232_work(struct work_struct *work)
{ {
struct ds3232 *ds3232 = container_of(work, struct ds3232, work); struct ds3232 *ds3232 = container_of(work, struct ds3232, work);
struct i2c_client *client = ds3232->client; int ret;
int stat, control; int stat, control;
mutex_lock(&ds3232->mutex); mutex_lock(&ds3232->mutex);
stat = i2c_smbus_read_byte_data(client, DS3232_REG_SR); ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat);
if (stat < 0) if (ret)
goto unlock; goto unlock;
if (stat & DS3232_REG_SR_A1F) { if (stat & DS3232_REG_SR_A1F) {
control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
if (control < 0) { if (ret) {
pr_warn("Read Control Register error - Disable IRQ%d\n", pr_warn("Read Control Register error - Disable IRQ%d\n",
client->irq); ds3232->irq);
} else { } else {
/* disable alarm1 interrupt */ /* disable alarm1 interrupt */
control &= ~(DS3232_REG_CR_A1IE); control &= ~(DS3232_REG_CR_A1IE);
i2c_smbus_write_byte_data(client, DS3232_REG_CR, regmap_write(ds3232->regmap, DS3232_REG_CR, control);
control);
/* clear the alarm pend flag */ /* clear the alarm pend flag */
stat &= ~DS3232_REG_SR_A1F; stat &= ~DS3232_REG_SR_A1F;
i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); regmap_write(ds3232->regmap, DS3232_REG_SR, stat);
rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF); rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF);
if (!ds3232->exiting) if (!ds3232->exiting)
enable_irq(client->irq); enable_irq(ds3232->irq);
} }
} }
@ -406,49 +391,53 @@ static const struct rtc_class_ops ds3232_rtc_ops = {
.alarm_irq_enable = ds3232_alarm_irq_enable, .alarm_irq_enable = ds3232_alarm_irq_enable,
}; };
static int ds3232_probe(struct i2c_client *client, static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq,
const struct i2c_device_id *id) const char *name)
{ {
struct ds3232 *ds3232; struct ds3232 *ds3232;
int ret; int ret;
ds3232 = devm_kzalloc(&client->dev, sizeof(struct ds3232), GFP_KERNEL); ds3232 = devm_kzalloc(dev, sizeof(*ds3232), GFP_KERNEL);
if (!ds3232) if (!ds3232)
return -ENOMEM; return -ENOMEM;
ds3232->client = client; ds3232->regmap = regmap;
i2c_set_clientdata(client, ds3232); ds3232->irq = irq;
ds3232->dev = dev;
dev_set_drvdata(dev, ds3232);
INIT_WORK(&ds3232->work, ds3232_work); INIT_WORK(&ds3232->work, ds3232_work);
mutex_init(&ds3232->mutex); mutex_init(&ds3232->mutex);
ret = ds3232_check_rtc_status(client); ret = ds3232_check_rtc_status(dev);
if (ret) if (ret)
return ret; return ret;
if (client->irq > 0) { if (ds3232->irq > 0) {
ret = devm_request_irq(&client->dev, client->irq, ds3232_irq, ret = devm_request_irq(dev, ds3232->irq, ds3232_irq,
IRQF_SHARED, "ds3232", client); IRQF_SHARED, name, dev);
if (ret) { if (ret) {
dev_err(&client->dev, "unable to request IRQ\n"); ds3232->irq = 0;
} dev_err(dev, "unable to request IRQ\n");
device_init_wakeup(&client->dev, 1); } else
device_init_wakeup(dev, 1);
} }
ds3232->rtc = devm_rtc_device_register(&client->dev, client->name, ds3232->rtc = devm_rtc_device_register(dev, name, &ds3232_rtc_ops,
&ds3232_rtc_ops, THIS_MODULE); THIS_MODULE);
return PTR_ERR_OR_ZERO(ds3232->rtc); return PTR_ERR_OR_ZERO(ds3232->rtc);
} }
static int ds3232_remove(struct i2c_client *client) static int ds3232_remove(struct device *dev)
{ {
struct ds3232 *ds3232 = i2c_get_clientdata(client); struct ds3232 *ds3232 = dev_get_drvdata(dev);
if (client->irq > 0) { if (ds3232->irq > 0) {
mutex_lock(&ds3232->mutex); mutex_lock(&ds3232->mutex);
ds3232->exiting = 1; ds3232->exiting = 1;
mutex_unlock(&ds3232->mutex); mutex_unlock(&ds3232->mutex);
devm_free_irq(&client->dev, client->irq, client); devm_free_irq(dev, ds3232->irq, dev);
cancel_work_sync(&ds3232->work); cancel_work_sync(&ds3232->work);
} }
@ -459,11 +448,10 @@ static int ds3232_remove(struct i2c_client *client)
static int ds3232_suspend(struct device *dev) static int ds3232_suspend(struct device *dev)
{ {
struct ds3232 *ds3232 = dev_get_drvdata(dev); struct ds3232 *ds3232 = dev_get_drvdata(dev);
struct i2c_client *client = to_i2c_client(dev);
if (device_can_wakeup(dev)) { if (device_can_wakeup(dev)) {
ds3232->suspended = true; ds3232->suspended = true;
if (irq_set_irq_wake(client->irq, 1)) { if (irq_set_irq_wake(ds3232->irq, 1)) {
dev_warn_once(dev, "Cannot set wakeup source\n"); dev_warn_once(dev, "Cannot set wakeup source\n");
ds3232->suspended = false; ds3232->suspended = false;
} }
@ -475,7 +463,6 @@ static int ds3232_suspend(struct device *dev)
static int ds3232_resume(struct device *dev) static int ds3232_resume(struct device *dev)
{ {
struct ds3232 *ds3232 = dev_get_drvdata(dev); struct ds3232 *ds3232 = dev_get_drvdata(dev);
struct i2c_client *client = to_i2c_client(dev);
if (ds3232->suspended) { if (ds3232->suspended) {
ds3232->suspended = false; ds3232->suspended = false;
@ -483,7 +470,7 @@ static int ds3232_resume(struct device *dev)
/* Clear the hardware alarm pend flag */ /* Clear the hardware alarm pend flag */
schedule_work(&ds3232->work); schedule_work(&ds3232->work);
irq_set_irq_wake(client->irq, 0); irq_set_irq_wake(ds3232->irq, 0);
} }
return 0; return 0;
@ -494,6 +481,30 @@ static const struct dev_pm_ops ds3232_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ds3232_suspend, ds3232_resume) SET_SYSTEM_SLEEP_PM_OPS(ds3232_suspend, ds3232_resume)
}; };
static int ds3232_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct regmap *regmap;
static const struct regmap_config config = {
.reg_bits = 8,
.val_bits = 8,
};
regmap = devm_regmap_init_i2c(client, &config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "%s: regmap allocation failed: %ld\n",
__func__, PTR_ERR(regmap));
return PTR_ERR(regmap);
}
return ds3232_probe(&client->dev, regmap, client->irq, client->name);
}
static int ds3232_i2c_remove(struct i2c_client *client)
{
return ds3232_remove(&client->dev);
}
static const struct i2c_device_id ds3232_id[] = { static const struct i2c_device_id ds3232_id[] = {
{ "ds3232", 0 }, { "ds3232", 0 },
{ } { }
@ -505,11 +516,10 @@ static struct i2c_driver ds3232_driver = {
.name = "rtc-ds3232", .name = "rtc-ds3232",
.pm = &ds3232_pm_ops, .pm = &ds3232_pm_ops,
}, },
.probe = ds3232_probe, .probe = ds3232_i2c_probe,
.remove = ds3232_remove, .remove = ds3232_i2c_remove,
.id_table = ds3232_id, .id_table = ds3232_id,
}; };
module_i2c_driver(ds3232_driver); module_i2c_driver(ds3232_driver);
MODULE_AUTHOR("Srikanth Srinivasan <srikanth.srinivasan@freescale.com>"); MODULE_AUTHOR("Srikanth Srinivasan <srikanth.srinivasan@freescale.com>");