Merge branch 'akpm' (patches from Andrew Morton) into next

Merge more updates from Andrew Morton:

 - Most of the rest of MM.

   This includes "mark remap_file_pages syscall as deprecated" but the
   actual "replace remap_file_pages syscall with emulation" is held
   back.  I guess we'll need to work out when to pull the trigger on
   that one.

 - various minor cleanups to obscure filesystems

 - the drivers/rtc queue

 - hfsplus updates

 - ufs, hpfs, fatfs, affs, reiserfs

 - Documentation/

 - signals

 - procfs

 - cpu hotplug

 - lib/idr.c

 - rapidio

 - sysctl

 - ipc updates

* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (171 commits)
  ufs: sb mutex merge + mutex_destroy
  powerpc: update comments for generic idle conversion
  cris: update comments for generic idle conversion
  idle: remove cpu_idle() forward declarations
  nbd: zero from and len fields in NBD_CMD_DISCONNECT.
  mm: convert some level-less printks to pr_*
  MAINTAINERS: adi-buildroot-devel is moderated
  MAINTAINERS: add linux-api for review of API/ABI changes
  mm/kmemleak-test.c: use pr_fmt for logging
  fs/dlm/debug_fs.c: replace seq_printf by seq_puts
  fs/dlm/lockspace.c: convert simple_str to kstr
  fs/dlm/config.c: convert simple_str to kstr
  mm: mark remap_file_pages() syscall as deprecated
  mm: memcontrol: remove unnecessary memcg argument from soft limit functions
  mm: memcontrol: clean up memcg zoneinfo lookup
  mm/memblock.c: call kmemleak directly from memblock_(alloc|free)
  mm/mempool.c: update the kmemleak stack trace for mempool allocations
  lib/radix-tree.c: update the kmemleak stack trace for radix tree allocations
  mm: introduce kmemleak_update_trace()
  mm/kmemleak.c: use %u to print ->checksum
  ...
This commit is contained in:
Linus Torvalds
2014-06-06 16:35:10 -07:00
198 changed files with 4204 additions and 1799 deletions

View File

@@ -386,12 +386,12 @@ config RTC_DRV_PCF8583
will be called rtc-pcf8583.
config RTC_DRV_M41T80
tristate "ST M41T62/65/M41T80/81/82/83/84/85/87"
tristate "ST M41T62/65/M41T80/81/82/83/84/85/87 and compatible"
help
If you say Y here you will get support for the ST M41T60
and M41T80 RTC chips series. Currently, the following chips are
supported: M41T62, M41T65, M41T80, M41T81, M41T82, M41T83, M41ST84,
M41ST85, and M41ST87.
M41ST85, M41ST87, and MicroCrystal RV4162.
This driver can also be built as a module. If so, the module
will be called rtc-m41t80.
@@ -573,6 +573,17 @@ config RTC_DRV_DS1305
This driver can also be built as a module. If so, the module
will be called rtc-ds1305.
config RTC_DRV_DS1343
select REGMAP_SPI
tristate "Dallas/Maxim DS1343/DS1344"
help
If you say yes here you get support for the
Dallas/Maxim DS1343 and DS1344 real time clock chips.
Support for trickle charger, alarm is provided.
This driver can also be built as a module. If so, the module
will be called rtc-ds1343.
config RTC_DRV_DS1347
tristate "Dallas/Maxim DS1347"
help
@@ -650,6 +661,14 @@ config RTC_DRV_RX4581
This driver can also be built as a module. If so the module
will be called rtc-rx4581.
config RTC_DRV_MCP795
tristate "Microchip MCP795"
help
If you say yes here you will get support for the Microchip MCP795.
This driver can also be built as a module. If so the module
will be called rtc-mcp795.
endif # SPI_MASTER
comment "Platform RTC drivers"
@@ -758,6 +777,16 @@ config RTC_DRV_DA9055
This driver can also be built as a module. If so, the module
will be called rtc-da9055
config RTC_DRV_DA9063
tristate "Dialog Semiconductor DA9063 RTC"
depends on MFD_DA9063
help
If you say yes here you will get support for the RTC subsystem
of the Dialog Semiconductor DA9063.
This driver can also be built as a module. If so, the module
will be called "rtc-da9063".
config RTC_DRV_EFI
tristate "EFI RTC"
depends on IA64
@@ -1327,6 +1356,15 @@ config RTC_DRV_MOXART
This driver can also be built as a module. If so, the module
will be called rtc-moxart
config RTC_DRV_XGENE
tristate "APM X-Gene RTC"
help
If you say yes here you get support for the APM X-Gene SoC real time
clock.
This driver can also be built as a module, if so, the module
will be called "rtc-xgene".
comment "HID Sensor RTC drivers"
config RTC_DRV_HID_SENSOR_TIME

View File

@@ -32,6 +32,7 @@ obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o
obj-$(CONFIG_RTC_DRV_DA9052) += rtc-da9052.o
obj-$(CONFIG_RTC_DRV_DA9055) += rtc-da9055.o
obj-$(CONFIG_RTC_DRV_DA9063) += rtc-da9063.o
obj-$(CONFIG_RTC_DRV_DAVINCI) += rtc-davinci.o
obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o
obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o
@@ -40,6 +41,7 @@ obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o
obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o
obj-$(CONFIG_RTC_DRV_DS1305) += rtc-ds1305.o
obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o
obj-$(CONFIG_RTC_DRV_DS1343) += rtc-ds1343.o
obj-$(CONFIG_RTC_DRV_DS1347) += rtc-ds1347.o
obj-$(CONFIG_RTC_DRV_DS1374) += rtc-ds1374.o
obj-$(CONFIG_RTC_DRV_DS1390) += rtc-ds1390.o
@@ -80,6 +82,7 @@ obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o
obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o
obj-$(CONFIG_RTC_DRV_MCP795) += rtc-mcp795.o
obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o
obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o
obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o
@@ -135,5 +138,6 @@ obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o
obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o
obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o
obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o
obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o

View File

@@ -292,7 +292,8 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year");
do {
alarm->time.tm_year++;
} while (rtc_valid_tm(&alarm->time) != 0);
} while (!is_leap_year(alarm->time.tm_year + 1900)
&& rtc_valid_tm(&alarm->time) != 0);
break;
default:
@@ -300,7 +301,16 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
}
done:
return 0;
err = rtc_valid_tm(&alarm->time);
if (err) {
dev_warn(&rtc->dev, "invalid alarm value: %d-%d-%d %d:%d:%d\n",
alarm->time.tm_year + 1900, alarm->time.tm_mon + 1,
alarm->time.tm_mday, alarm->time.tm_hour, alarm->time.tm_min,
alarm->time.tm_sec);
}
return err;
}
int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)

View File

@@ -293,7 +293,7 @@ static int pm860x_rtc_dt_init(struct platform_device *pdev,
int ret;
if (!np)
return -ENODEV;
np = of_find_node_by_name(np, "rtc");
np = of_get_child_by_name(np, "rtc");
if (!np) {
dev_err(&pdev->dev, "failed to find rtc node\n");
return -ENODEV;
@@ -301,6 +301,7 @@ static int pm860x_rtc_dt_init(struct platform_device *pdev,
ret = of_property_read_u32(np, "marvell,88pm860x-vrtc", &info->vrtc);
if (ret)
info->vrtc = 0;
of_node_put(np);
return 0;
}
#else

View File

@@ -48,6 +48,7 @@ struct at91_rtc_config {
static const struct at91_rtc_config *at91_rtc_config;
static DECLARE_COMPLETION(at91_rtc_updated);
static DECLARE_COMPLETION(at91_rtc_upd_rdy);
static unsigned int at91_alarm_year = AT91_RTC_EPOCH;
static void __iomem *at91_rtc_regs;
static int irq;
@@ -161,6 +162,8 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
wait_for_completion(&at91_rtc_upd_rdy);
/* Stop Time/Calendar from counting */
cr = at91_rtc_read(AT91_RTC_CR);
at91_rtc_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM);
@@ -183,7 +186,9 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
/* Restart Time/Calendar */
cr = at91_rtc_read(AT91_RTC_CR);
at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_SECEV);
at91_rtc_write(AT91_RTC_CR, cr & ~(AT91_RTC_UPDCAL | AT91_RTC_UPDTIM));
at91_rtc_write_ier(AT91_RTC_SECEV);
return 0;
}
@@ -290,8 +295,10 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
if (rtsr) { /* this interrupt is shared! Is it ours? */
if (rtsr & AT91_RTC_ALARM)
events |= (RTC_AF | RTC_IRQF);
if (rtsr & AT91_RTC_SECEV)
events |= (RTC_UF | RTC_IRQF);
if (rtsr & AT91_RTC_SECEV) {
complete(&at91_rtc_upd_rdy);
at91_rtc_write_idr(AT91_RTC_SECEV);
}
if (rtsr & AT91_RTC_ACKUPD)
complete(&at91_rtc_updated);
@@ -413,6 +420,11 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
return PTR_ERR(rtc);
platform_set_drvdata(pdev, rtc);
/* enable SECEV interrupt in order to initialize at91_rtc_upd_rdy
* completion.
*/
at91_rtc_write_ier(AT91_RTC_SECEV);
dev_info(&pdev->dev, "AT91 Real Time Clock driver.\n");
return 0;
}

View File

@@ -346,7 +346,7 @@ static int bfin_rtc_probe(struct platform_device *pdev)
{
struct bfin_rtc *rtc;
struct device *dev = &pdev->dev;
int ret = 0;
int ret;
unsigned long timeout = jiffies + HZ;
dev_dbg_stamp(dev);
@@ -361,16 +361,17 @@ static int bfin_rtc_probe(struct platform_device *pdev)
/* Register our RTC with the RTC framework */
rtc->rtc_dev = devm_rtc_device_register(dev, pdev->name, &bfin_rtc_ops,
THIS_MODULE);
if (unlikely(IS_ERR(rtc->rtc_dev))) {
ret = PTR_ERR(rtc->rtc_dev);
goto err;
}
if (unlikely(IS_ERR(rtc->rtc_dev)))
return PTR_ERR(rtc->rtc_dev);
/* Grab the IRQ and init the hardware */
ret = devm_request_irq(dev, IRQ_RTC, bfin_rtc_interrupt, 0,
pdev->name, dev);
if (unlikely(ret))
goto err;
dev_err(&pdev->dev,
"unable to request IRQ; alarm won't work, "
"and writes will be delayed\n");
/* sometimes the bootloader touched things, but the write complete was not
* enabled, so let's just do a quick timeout here since the IRQ will not fire ...
*/
@@ -381,9 +382,6 @@ static int bfin_rtc_probe(struct platform_device *pdev)
bfin_write_RTC_SWCNT(0);
return 0;
err:
return ret;
}
static int bfin_rtc_remove(struct platform_device *pdev)

View File

@@ -647,6 +647,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
int retval = 0;
unsigned char rtc_control;
unsigned address_space;
u32 flags = 0;
/* there can be only one ... */
if (cmos_rtc.dev)
@@ -660,9 +661,12 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
* REVISIT non-x86 systems may instead use memory space resources
* (needing ioremap etc), not i/o space resources like this ...
*/
ports = request_region(ports->start,
resource_size(ports),
driver_name);
if (RTC_IOMAPPED)
ports = request_region(ports->start, resource_size(ports),
driver_name);
else
ports = request_mem_region(ports->start, resource_size(ports),
driver_name);
if (!ports) {
dev_dbg(dev, "i/o registers already in use\n");
return -EBUSY;
@@ -699,6 +703,11 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
* expect CMOS_READ and friends to handle.
*/
if (info) {
if (info->flags)
flags = info->flags;
if (info->address_space)
address_space = info->address_space;
if (info->rtc_day_alarm && info->rtc_day_alarm < 128)
cmos_rtc.day_alrm = info->rtc_day_alarm;
if (info->rtc_mon_alarm && info->rtc_mon_alarm < 128)
@@ -726,18 +735,21 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
spin_lock_irq(&rtc_lock);
/* force periodic irq to CMOS reset default of 1024Hz;
*
* REVISIT it's been reported that at least one x86_64 ALI mobo
* doesn't use 32KHz here ... for portability we might need to
* do something about other clock frequencies.
*/
cmos_rtc.rtc->irq_freq = 1024;
hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq);
CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
if (!(flags & CMOS_RTC_FLAGS_NOFREQ)) {
/* force periodic irq to CMOS reset default of 1024Hz;
*
* REVISIT it's been reported that at least one x86_64 ALI
* mobo doesn't use 32KHz here ... for portability we might
* need to do something about other clock frequencies.
*/
cmos_rtc.rtc->irq_freq = 1024;
hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq);
CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
}
/* disable irqs */
cmos_irq_disable(&cmos_rtc, RTC_PIE | RTC_AIE | RTC_UIE);
if (is_valid_irq(rtc_irq))
cmos_irq_disable(&cmos_rtc, RTC_PIE | RTC_AIE | RTC_UIE);
rtc_control = CMOS_READ(RTC_CONTROL);
@@ -802,14 +814,18 @@ cleanup1:
cmos_rtc.dev = NULL;
rtc_device_unregister(cmos_rtc.rtc);
cleanup0:
release_region(ports->start, resource_size(ports));
if (RTC_IOMAPPED)
release_region(ports->start, resource_size(ports));
else
release_mem_region(ports->start, resource_size(ports));
return retval;
}
static void cmos_do_shutdown(void)
static void cmos_do_shutdown(int rtc_irq)
{
spin_lock_irq(&rtc_lock);
cmos_irq_disable(&cmos_rtc, RTC_IRQMASK);
if (is_valid_irq(rtc_irq))
cmos_irq_disable(&cmos_rtc, RTC_IRQMASK);
spin_unlock_irq(&rtc_lock);
}
@@ -818,7 +834,7 @@ static void __exit cmos_do_remove(struct device *dev)
struct cmos_rtc *cmos = dev_get_drvdata(dev);
struct resource *ports;
cmos_do_shutdown();
cmos_do_shutdown(cmos->irq);
sysfs_remove_bin_file(&dev->kobj, &nvram);
@@ -831,7 +847,10 @@ static void __exit cmos_do_remove(struct device *dev)
cmos->rtc = NULL;
ports = cmos->iomem;
release_region(ports->start, resource_size(ports));
if (RTC_IOMAPPED)
release_region(ports->start, resource_size(ports));
else
release_mem_region(ports->start, resource_size(ports));
cmos->iomem = NULL;
cmos->dev = NULL;
@@ -1065,10 +1084,13 @@ static void __exit cmos_pnp_remove(struct pnp_dev *pnp)
static void cmos_pnp_shutdown(struct pnp_dev *pnp)
{
if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(&pnp->dev))
struct device *dev = &pnp->dev;
struct cmos_rtc *cmos = dev_get_drvdata(dev);
if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev))
return;
cmos_do_shutdown();
cmos_do_shutdown(cmos->irq);
}
static const struct pnp_device_id rtc_ids[] = {
@@ -1143,11 +1165,21 @@ static inline void cmos_of_init(struct platform_device *pdev) {}
static int __init cmos_platform_probe(struct platform_device *pdev)
{
struct resource *resource;
int irq;
cmos_of_init(pdev);
cmos_wake_setup(&pdev->dev);
return cmos_do_probe(&pdev->dev,
platform_get_resource(pdev, IORESOURCE_IO, 0),
platform_get_irq(pdev, 0));
if (RTC_IOMAPPED)
resource = platform_get_resource(pdev, IORESOURCE_IO, 0);
else
resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
irq = -1;
return cmos_do_probe(&pdev->dev, resource, irq);
}
static int __exit cmos_platform_remove(struct platform_device *pdev)
@@ -1158,10 +1190,13 @@ static int __exit cmos_platform_remove(struct platform_device *pdev)
static void cmos_platform_shutdown(struct platform_device *pdev)
{
if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(&pdev->dev))
struct device *dev = &pdev->dev;
struct cmos_rtc *cmos = dev_get_drvdata(dev);
if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev))
return;
cmos_do_shutdown();
cmos_do_shutdown(cmos->irq);
}
/* work with hotplug and coldplug */

View File

@@ -20,28 +20,28 @@
#include <linux/mfd/da9052/da9052.h>
#include <linux/mfd/da9052/reg.h>
#define rtc_err(da9052, fmt, ...) \
dev_err(da9052->dev, "%s: " fmt, __func__, ##__VA_ARGS__)
#define rtc_err(rtc, fmt, ...) \
dev_err(rtc->da9052->dev, "%s: " fmt, __func__, ##__VA_ARGS__)
struct da9052_rtc {
struct rtc_device *rtc;
struct da9052 *da9052;
};
static int da9052_rtc_enable_alarm(struct da9052 *da9052, bool enable)
static int da9052_rtc_enable_alarm(struct da9052_rtc *rtc, bool enable)
{
int ret;
if (enable) {
ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG,
DA9052_ALARM_Y_ALARM_ON,
DA9052_ALARM_Y_ALARM_ON);
ret = da9052_reg_update(rtc->da9052, DA9052_ALARM_Y_REG,
DA9052_ALARM_Y_ALARM_ON|DA9052_ALARM_Y_TICK_ON,
DA9052_ALARM_Y_ALARM_ON);
if (ret != 0)
rtc_err(da9052, "Failed to enable ALM: %d\n", ret);
rtc_err(rtc, "Failed to enable ALM: %d\n", ret);
} else {
ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG,
DA9052_ALARM_Y_ALARM_ON, 0);
ret = da9052_reg_update(rtc->da9052, DA9052_ALARM_Y_REG,
DA9052_ALARM_Y_ALARM_ON|DA9052_ALARM_Y_TICK_ON, 0);
if (ret != 0)
rtc_err(da9052, "Write error: %d\n", ret);
rtc_err(rtc, "Write error: %d\n", ret);
}
return ret;
}
@@ -49,31 +49,20 @@ static int da9052_rtc_enable_alarm(struct da9052 *da9052, bool enable)
static irqreturn_t da9052_rtc_irq(int irq, void *data)
{
struct da9052_rtc *rtc = data;
int ret;
ret = da9052_reg_read(rtc->da9052, DA9052_ALARM_MI_REG);
if (ret < 0) {
rtc_err(rtc->da9052, "Read error: %d\n", ret);
return IRQ_NONE;
}
if (ret & DA9052_ALARMMI_ALARMTYPE) {
da9052_rtc_enable_alarm(rtc->da9052, 0);
rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
} else
rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_PF);
rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
return IRQ_HANDLED;
}
static int da9052_read_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm)
static int da9052_read_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm)
{
int ret;
uint8_t v[5];
ret = da9052_group_read(da9052, DA9052_ALARM_MI_REG, 5, v);
ret = da9052_group_read(rtc->da9052, DA9052_ALARM_MI_REG, 5, v);
if (ret != 0) {
rtc_err(da9052, "Failed to group read ALM: %d\n", ret);
rtc_err(rtc, "Failed to group read ALM: %d\n", ret);
return ret;
}
@@ -84,23 +73,33 @@ static int da9052_read_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm)
rtc_tm->tm_min = v[0] & DA9052_RTC_MIN;
ret = rtc_valid_tm(rtc_tm);
if (ret != 0)
return ret;
return ret;
}
static int da9052_set_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm)
static int da9052_set_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm)
{
struct da9052 *da9052 = rtc->da9052;
unsigned long alm_time;
int ret;
uint8_t v[3];
ret = rtc_tm_to_time(rtc_tm, &alm_time);
if (ret != 0)
return ret;
if (rtc_tm->tm_sec > 0) {
alm_time += 60 - rtc_tm->tm_sec;
rtc_time_to_tm(alm_time, rtc_tm);
}
BUG_ON(rtc_tm->tm_sec); /* it will cause repeated irqs if not zero */
rtc_tm->tm_year -= 100;
rtc_tm->tm_mon += 1;
ret = da9052_reg_update(da9052, DA9052_ALARM_MI_REG,
DA9052_RTC_MIN, rtc_tm->tm_min);
if (ret != 0) {
rtc_err(da9052, "Failed to write ALRM MIN: %d\n", ret);
rtc_err(rtc, "Failed to write ALRM MIN: %d\n", ret);
return ret;
}
@@ -115,22 +114,22 @@ static int da9052_set_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm)
ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG,
DA9052_RTC_YEAR, rtc_tm->tm_year);
if (ret != 0)
rtc_err(da9052, "Failed to write ALRM YEAR: %d\n", ret);
rtc_err(rtc, "Failed to write ALRM YEAR: %d\n", ret);
return ret;
}
static int da9052_rtc_get_alarm_status(struct da9052 *da9052)
static int da9052_rtc_get_alarm_status(struct da9052_rtc *rtc)
{
int ret;
ret = da9052_reg_read(da9052, DA9052_ALARM_Y_REG);
ret = da9052_reg_read(rtc->da9052, DA9052_ALARM_Y_REG);
if (ret < 0) {
rtc_err(da9052, "Failed to read ALM: %d\n", ret);
rtc_err(rtc, "Failed to read ALM: %d\n", ret);
return ret;
}
ret &= DA9052_ALARM_Y_ALARM_ON;
return (ret > 0) ? 1 : 0;
return !!(ret&DA9052_ALARM_Y_ALARM_ON);
}
static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
@@ -141,7 +140,7 @@ static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
ret = da9052_group_read(rtc->da9052, DA9052_COUNT_S_REG, 6, v);
if (ret < 0) {
rtc_err(rtc->da9052, "Failed to read RTC time : %d\n", ret);
rtc_err(rtc, "Failed to read RTC time : %d\n", ret);
return ret;
}
@@ -153,18 +152,14 @@ static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
rtc_tm->tm_sec = v[0] & DA9052_RTC_SEC;
ret = rtc_valid_tm(rtc_tm);
if (ret != 0) {
rtc_err(rtc->da9052, "rtc_valid_tm failed: %d\n", ret);
return ret;
}
return 0;
return ret;
}
static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct da9052_rtc *rtc;
uint8_t v[6];
int ret;
rtc = dev_get_drvdata(dev);
@@ -175,7 +170,10 @@ static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm)
v[4] = tm->tm_mon + 1;
v[5] = tm->tm_year - 100;
return da9052_group_write(rtc->da9052, DA9052_COUNT_S_REG, 6, v);
ret = da9052_group_write(rtc->da9052, DA9052_COUNT_S_REG, 6, v);
if (ret < 0)
rtc_err(rtc, "failed to set RTC time: %d\n", ret);
return ret;
}
static int da9052_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@@ -184,13 +182,13 @@ static int da9052_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
struct rtc_time *tm = &alrm->time;
struct da9052_rtc *rtc = dev_get_drvdata(dev);
ret = da9052_read_alarm(rtc->da9052, tm);
if (ret)
ret = da9052_read_alarm(rtc, tm);
if (ret < 0) {
rtc_err(rtc, "failed to read RTC alarm: %d\n", ret);
return ret;
}
alrm->enabled = da9052_rtc_get_alarm_status(rtc->da9052);
alrm->enabled = da9052_rtc_get_alarm_status(rtc);
return 0;
}
@@ -200,16 +198,15 @@ static int da9052_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
struct rtc_time *tm = &alrm->time;
struct da9052_rtc *rtc = dev_get_drvdata(dev);
ret = da9052_rtc_enable_alarm(rtc->da9052, 0);
ret = da9052_rtc_enable_alarm(rtc, 0);
if (ret < 0)
return ret;
ret = da9052_set_alarm(rtc->da9052, tm);
if (ret)
ret = da9052_set_alarm(rtc, tm);
if (ret < 0)
return ret;
ret = da9052_rtc_enable_alarm(rtc->da9052, 1);
ret = da9052_rtc_enable_alarm(rtc, 1);
return ret;
}
@@ -217,7 +214,7 @@ static int da9052_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct da9052_rtc *rtc = dev_get_drvdata(dev);
return da9052_rtc_enable_alarm(rtc->da9052, enabled);
return da9052_rtc_enable_alarm(rtc, enabled);
}
static const struct rtc_class_ops da9052_rtc_ops = {
@@ -239,10 +236,23 @@ static int da9052_rtc_probe(struct platform_device *pdev)
rtc->da9052 = dev_get_drvdata(pdev->dev.parent);
platform_set_drvdata(pdev, rtc);
ret = da9052_reg_write(rtc->da9052, DA9052_BBAT_CONT_REG, 0xFE);
if (ret < 0) {
rtc_err(rtc,
"Failed to setup RTC battery charging: %d\n", ret);
return ret;
}
ret = da9052_reg_update(rtc->da9052, DA9052_ALARM_Y_REG,
DA9052_ALARM_Y_TICK_ON, 0);
if (ret != 0)
rtc_err(rtc, "Failed to disable TICKS: %d\n", ret);
ret = da9052_request_irq(rtc->da9052, DA9052_IRQ_ALARM, "ALM",
da9052_rtc_irq, rtc);
if (ret != 0) {
rtc_err(rtc->da9052, "irq registration failed: %d\n", ret);
rtc_err(rtc, "irq registration failed: %d\n", ret);
return ret;
}
@@ -261,7 +271,7 @@ static struct platform_driver da9052_rtc_driver = {
module_platform_driver(da9052_rtc_driver);
MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
MODULE_AUTHOR("Anthony Olech <Anthony.Olech@diasemi.com>");
MODULE_DESCRIPTION("RTC driver for Dialog DA9052 PMIC");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:da9052-rtc");

333
drivers/rtc/rtc-da9063.c Normal file
View File

@@ -0,0 +1,333 @@
/* rtc-da9063.c - Real time clock device driver for DA9063
* Copyright (C) 2013-14 Dialog Semiconductor Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/rtc.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/regmap.h>
#include <linux/mfd/da9063/registers.h>
#include <linux/mfd/da9063/core.h>
#define YEARS_TO_DA9063(year) ((year) - 100)
#define MONTHS_TO_DA9063(month) ((month) + 1)
#define YEARS_FROM_DA9063(year) ((year) + 100)
#define MONTHS_FROM_DA9063(month) ((month) - 1)
#define RTC_DATA_LEN (DA9063_REG_COUNT_Y - DA9063_REG_COUNT_S + 1)
#define RTC_SEC 0
#define RTC_MIN 1
#define RTC_HOUR 2
#define RTC_DAY 3
#define RTC_MONTH 4
#define RTC_YEAR 5
struct da9063_rtc {
struct rtc_device *rtc_dev;
struct da9063 *hw;
struct rtc_time alarm_time;
bool rtc_sync;
};
static void da9063_data_to_tm(u8 *data, struct rtc_time *tm)
{
tm->tm_sec = data[RTC_SEC] & DA9063_COUNT_SEC_MASK;
tm->tm_min = data[RTC_MIN] & DA9063_COUNT_MIN_MASK;
tm->tm_hour = data[RTC_HOUR] & DA9063_COUNT_HOUR_MASK;
tm->tm_mday = data[RTC_DAY] & DA9063_COUNT_DAY_MASK;
tm->tm_mon = MONTHS_FROM_DA9063(data[RTC_MONTH] &
DA9063_COUNT_MONTH_MASK);
tm->tm_year = YEARS_FROM_DA9063(data[RTC_YEAR] &
DA9063_COUNT_YEAR_MASK);
}
static void da9063_tm_to_data(struct rtc_time *tm, u8 *data)
{
data[RTC_SEC] &= ~DA9063_COUNT_SEC_MASK;
data[RTC_SEC] |= tm->tm_sec & DA9063_COUNT_SEC_MASK;
data[RTC_MIN] &= ~DA9063_COUNT_MIN_MASK;
data[RTC_MIN] |= tm->tm_min & DA9063_COUNT_MIN_MASK;
data[RTC_HOUR] &= ~DA9063_COUNT_HOUR_MASK;
data[RTC_HOUR] |= tm->tm_hour & DA9063_COUNT_HOUR_MASK;
data[RTC_DAY] &= ~DA9063_COUNT_DAY_MASK;
data[RTC_DAY] |= tm->tm_mday & DA9063_COUNT_DAY_MASK;
data[RTC_MONTH] &= ~DA9063_COUNT_MONTH_MASK;
data[RTC_MONTH] |= MONTHS_TO_DA9063(tm->tm_mon) &
DA9063_COUNT_MONTH_MASK;
data[RTC_YEAR] &= ~DA9063_COUNT_YEAR_MASK;
data[RTC_YEAR] |= YEARS_TO_DA9063(tm->tm_year) &
DA9063_COUNT_YEAR_MASK;
}
static int da9063_rtc_stop_alarm(struct device *dev)
{
struct da9063_rtc *rtc = dev_get_drvdata(dev);
return regmap_update_bits(rtc->hw->regmap, DA9063_REG_ALARM_Y,
DA9063_ALARM_ON, 0);
}
static int da9063_rtc_start_alarm(struct device *dev)
{
struct da9063_rtc *rtc = dev_get_drvdata(dev);
return regmap_update_bits(rtc->hw->regmap, DA9063_REG_ALARM_Y,
DA9063_ALARM_ON, DA9063_ALARM_ON);
}
static int da9063_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct da9063_rtc *rtc = dev_get_drvdata(dev);
unsigned long tm_secs;
unsigned long al_secs;
u8 data[RTC_DATA_LEN];
int ret;
ret = regmap_bulk_read(rtc->hw->regmap, DA9063_REG_COUNT_S,
data, RTC_DATA_LEN);
if (ret < 0) {
dev_err(dev, "Failed to read RTC time data: %d\n", ret);
return ret;
}
if (!(data[RTC_SEC] & DA9063_RTC_READ)) {
dev_dbg(dev, "RTC not yet ready to be read by the host\n");
return -EINVAL;
}
da9063_data_to_tm(data, tm);
rtc_tm_to_time(tm, &tm_secs);
rtc_tm_to_time(&rtc->alarm_time, &al_secs);
/* handle the rtc synchronisation delay */
if (rtc->rtc_sync == true && al_secs - tm_secs == 1)
memcpy(tm, &rtc->alarm_time, sizeof(struct rtc_time));
else
rtc->rtc_sync = false;
return rtc_valid_tm(tm);
}
static int da9063_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct da9063_rtc *rtc = dev_get_drvdata(dev);
u8 data[RTC_DATA_LEN];
int ret;
da9063_tm_to_data(tm, data);
ret = regmap_bulk_write(rtc->hw->regmap, DA9063_REG_COUNT_S,
data, RTC_DATA_LEN);
if (ret < 0)
dev_err(dev, "Failed to set RTC time data: %d\n", ret);
return ret;
}
static int da9063_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct da9063_rtc *rtc = dev_get_drvdata(dev);
u8 data[RTC_DATA_LEN];
int ret;
unsigned int val;
ret = regmap_bulk_read(rtc->hw->regmap, DA9063_REG_ALARM_S,
&data[RTC_SEC], RTC_DATA_LEN);
if (ret < 0)
return ret;
da9063_data_to_tm(data, &alrm->time);
alrm->enabled = !!(data[RTC_YEAR] & DA9063_ALARM_ON);
ret = regmap_read(rtc->hw->regmap, DA9063_REG_EVENT_A, &val);
if (ret < 0)
return ret;
if (val & (DA9063_E_ALARM))
alrm->pending = 1;
else
alrm->pending = 0;
return 0;
}
static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct da9063_rtc *rtc = dev_get_drvdata(dev);
u8 data[RTC_DATA_LEN];
int ret;
da9063_tm_to_data(&alrm->time, data);
ret = da9063_rtc_stop_alarm(dev);
if (ret < 0) {
dev_err(dev, "Failed to stop alarm: %d\n", ret);
return ret;
}
ret = regmap_bulk_write(rtc->hw->regmap, DA9063_REG_ALARM_S,
data, RTC_DATA_LEN);
if (ret < 0) {
dev_err(dev, "Failed to write alarm: %d\n", ret);
return ret;
}
rtc->alarm_time = alrm->time;
if (alrm->enabled) {
ret = da9063_rtc_start_alarm(dev);
if (ret < 0) {
dev_err(dev, "Failed to start alarm: %d\n", ret);
return ret;
}
}
return ret;
}
static int da9063_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
if (enabled)
return da9063_rtc_start_alarm(dev);
else
return da9063_rtc_stop_alarm(dev);
}
static irqreturn_t da9063_alarm_event(int irq, void *data)
{
struct da9063_rtc *rtc = data;
regmap_update_bits(rtc->hw->regmap, DA9063_REG_ALARM_Y,
DA9063_ALARM_ON, 0);
rtc->rtc_sync = true;
rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
return IRQ_HANDLED;
}
static const struct rtc_class_ops da9063_rtc_ops = {
.read_time = da9063_rtc_read_time,
.set_time = da9063_rtc_set_time,
.read_alarm = da9063_rtc_read_alarm,
.set_alarm = da9063_rtc_set_alarm,
.alarm_irq_enable = da9063_rtc_alarm_irq_enable,
};
static int da9063_rtc_probe(struct platform_device *pdev)
{
struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent);
struct da9063_rtc *rtc;
int irq_alarm;
u8 data[RTC_DATA_LEN];
int ret;
ret = regmap_update_bits(da9063->regmap, DA9063_REG_CONTROL_E,
DA9063_RTC_EN, DA9063_RTC_EN);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to enable RTC\n");
goto err;
}
ret = regmap_update_bits(da9063->regmap, DA9063_REG_EN_32K,
DA9063_CRYSTAL, DA9063_CRYSTAL);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to run 32kHz oscillator\n");
goto err;
}
ret = regmap_update_bits(da9063->regmap, DA9063_REG_ALARM_S,
DA9063_ALARM_STATUS_TICK | DA9063_ALARM_STATUS_ALARM,
0);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to access RTC alarm register\n");
goto err;
}
ret = regmap_update_bits(da9063->regmap, DA9063_REG_ALARM_S,
DA9063_ALARM_STATUS_ALARM,
DA9063_ALARM_STATUS_ALARM);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to access RTC alarm register\n");
goto err;
}
ret = regmap_update_bits(da9063->regmap, DA9063_REG_ALARM_Y,
DA9063_TICK_ON, 0);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to disable TICKs\n");
goto err;
}
ret = regmap_bulk_read(da9063->regmap, DA9063_REG_ALARM_S,
data, RTC_DATA_LEN);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to read initial alarm data: %d\n",
ret);
goto err;
}
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return -ENOMEM;
platform_set_drvdata(pdev, rtc);
irq_alarm = platform_get_irq_byname(pdev, "ALARM");
ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL,
da9063_alarm_event,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"ALARM", rtc);
if (ret) {
dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n",
irq_alarm, ret);
goto err;
}
rtc->hw = da9063;
rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, DA9063_DRVNAME_RTC,
&da9063_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc->rtc_dev))
return PTR_ERR(rtc->rtc_dev);
da9063_data_to_tm(data, &rtc->alarm_time);
rtc->rtc_sync = false;
err:
return ret;
}
static struct platform_driver da9063_rtc_driver = {
.probe = da9063_rtc_probe,
.driver = {
.name = DA9063_DRVNAME_RTC,
.owner = THIS_MODULE,
},
};
module_platform_driver(da9063_rtc_driver);
MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
MODULE_DESCRIPTION("Real time clock device driver for Dialog DA9063");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DA9063_DRVNAME_RTC);

689
drivers/rtc/rtc-ds1343.c Normal file
View File

@@ -0,0 +1,689 @@
/* rtc-ds1343.c
*
* Driver for Dallas Semiconductor DS1343 Low Current, SPI Compatible
* Real Time Clock
*
* Author : Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <linux/pm.h>
#include <linux/slab.h>
#define DS1343_DRV_VERSION "01.00"
#define DALLAS_MAXIM_DS1343 0
#define DALLAS_MAXIM_DS1344 1
/* RTC DS1343 Registers */
#define DS1343_SECONDS_REG 0x00
#define DS1343_MINUTES_REG 0x01
#define DS1343_HOURS_REG 0x02
#define DS1343_DAY_REG 0x03
#define DS1343_DATE_REG 0x04
#define DS1343_MONTH_REG 0x05
#define DS1343_YEAR_REG 0x06
#define DS1343_ALM0_SEC_REG 0x07
#define DS1343_ALM0_MIN_REG 0x08
#define DS1343_ALM0_HOUR_REG 0x09
#define DS1343_ALM0_DAY_REG 0x0A
#define DS1343_ALM1_SEC_REG 0x0B
#define DS1343_ALM1_MIN_REG 0x0C
#define DS1343_ALM1_HOUR_REG 0x0D
#define DS1343_ALM1_DAY_REG 0x0E
#define DS1343_CONTROL_REG 0x0F
#define DS1343_STATUS_REG 0x10
#define DS1343_TRICKLE_REG 0x11
/* DS1343 Control Registers bits */
#define DS1343_EOSC 0x80
#define DS1343_DOSF 0x20
#define DS1343_EGFIL 0x10
#define DS1343_SQW 0x08
#define DS1343_INTCN 0x04
#define DS1343_A1IE 0x02
#define DS1343_A0IE 0x01
/* DS1343 Status Registers bits */
#define DS1343_OSF 0x80
#define DS1343_IRQF1 0x02
#define DS1343_IRQF0 0x01
/* DS1343 Trickle Charger Registers bits */
#define DS1343_TRICKLE_MAGIC 0xa0
#define DS1343_TRICKLE_DS1 0x08
#define DS1343_TRICKLE_1K 0x01
#define DS1343_TRICKLE_2K 0x02
#define DS1343_TRICKLE_4K 0x03
static const struct spi_device_id ds1343_id[] = {
{ "ds1343", DALLAS_MAXIM_DS1343 },
{ "ds1344", DALLAS_MAXIM_DS1344 },
{ }
};
MODULE_DEVICE_TABLE(spi, ds1343_id);
struct ds1343_priv {
struct spi_device *spi;
struct rtc_device *rtc;
struct regmap *map;
struct mutex mutex;
unsigned int irqen;
int irq;
int alarm_sec;
int alarm_min;
int alarm_hour;
int alarm_mday;
};
static int ds1343_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
switch (cmd) {
#ifdef RTC_SET_CHARGE
case RTC_SET_CHARGE:
{
int val;
if (copy_from_user(&val, (int __user *)arg, sizeof(int)))
return -EFAULT;
return regmap_write(priv->map, DS1343_TRICKLE_REG, val);
}
break;
#endif
}
return -ENOIOCTLCMD;
}
static ssize_t ds1343_show_glitchfilter(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ds1343_priv *priv = dev_get_drvdata(dev);
int glitch_filt_status, data;
regmap_read(priv->map, DS1343_CONTROL_REG, &data);
glitch_filt_status = !!(data & DS1343_EGFIL);
if (glitch_filt_status)
return sprintf(buf, "enabled\n");
else
return sprintf(buf, "disabled\n");
}
static ssize_t ds1343_store_glitchfilter(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct ds1343_priv *priv = dev_get_drvdata(dev);
int data;
regmap_read(priv->map, DS1343_CONTROL_REG, &data);
if (strncmp(buf, "enabled", 7) == 0)
data |= DS1343_EGFIL;
else if (strncmp(buf, "disabled", 8) == 0)
data &= ~(DS1343_EGFIL);
else
return -EINVAL;
regmap_write(priv->map, DS1343_CONTROL_REG, data);
return count;
}
static DEVICE_ATTR(glitch_filter, S_IRUGO | S_IWUSR, ds1343_show_glitchfilter,
ds1343_store_glitchfilter);
static ssize_t ds1343_show_alarmstatus(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ds1343_priv *priv = dev_get_drvdata(dev);
int alarmstatus, data;
regmap_read(priv->map, DS1343_CONTROL_REG, &data);
alarmstatus = !!(data & DS1343_A0IE);
if (alarmstatus)
return sprintf(buf, "enabled\n");
else
return sprintf(buf, "disabled\n");
}
static DEVICE_ATTR(alarm_status, S_IRUGO, ds1343_show_alarmstatus, NULL);
static ssize_t ds1343_show_alarmmode(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ds1343_priv *priv = dev_get_drvdata(dev);
int alarm_mode, data;
char *alarm_str;
regmap_read(priv->map, DS1343_ALM0_SEC_REG, &data);
alarm_mode = (data & 0x80) >> 4;
regmap_read(priv->map, DS1343_ALM0_MIN_REG, &data);
alarm_mode |= (data & 0x80) >> 5;
regmap_read(priv->map, DS1343_ALM0_HOUR_REG, &data);
alarm_mode |= (data & 0x80) >> 6;
regmap_read(priv->map, DS1343_ALM0_DAY_REG, &data);
alarm_mode |= (data & 0x80) >> 7;
switch (alarm_mode) {
case 15:
alarm_str = "each second";
break;
case 7:
alarm_str = "seconds match";
break;
case 3:
alarm_str = "minutes and seconds match";
break;
case 1:
alarm_str = "hours, minutes and seconds match";
break;
case 0:
alarm_str = "day, hours, minutes and seconds match";
break;
default:
alarm_str = "invalid";
break;
}
return sprintf(buf, "%s\n", alarm_str);
}
static DEVICE_ATTR(alarm_mode, S_IRUGO, ds1343_show_alarmmode, NULL);
static ssize_t ds1343_show_tricklecharger(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ds1343_priv *priv = dev_get_drvdata(dev);
int data;
char *diodes = "disabled", *resistors = " ";
regmap_read(priv->map, DS1343_TRICKLE_REG, &data);
if ((data & 0xf0) == DS1343_TRICKLE_MAGIC) {
switch (data & 0x0c) {
case DS1343_TRICKLE_DS1:
diodes = "one diode,";
break;
default:
diodes = "no diode,";
break;
}
switch (data & 0x03) {
case DS1343_TRICKLE_1K:
resistors = "1k Ohm";
break;
case DS1343_TRICKLE_2K:
resistors = "2k Ohm";
break;
case DS1343_TRICKLE_4K:
resistors = "4k Ohm";
break;
default:
diodes = "disabled";
break;
}
}
return sprintf(buf, "%s %s\n", diodes, resistors);
}
static DEVICE_ATTR(trickle_charger, S_IRUGO, ds1343_show_tricklecharger, NULL);
static int ds1343_sysfs_register(struct device *dev)
{
struct ds1343_priv *priv = dev_get_drvdata(dev);
int err;
err = device_create_file(dev, &dev_attr_glitch_filter);
if (err)
return err;
err = device_create_file(dev, &dev_attr_trickle_charger);
if (err)
goto error1;
if (priv->irq <= 0)
return err;
err = device_create_file(dev, &dev_attr_alarm_mode);
if (err)
goto error2;
err = device_create_file(dev, &dev_attr_alarm_status);
if (!err)
return err;
device_remove_file(dev, &dev_attr_alarm_mode);
error2:
device_remove_file(dev, &dev_attr_trickle_charger);
error1:
device_remove_file(dev, &dev_attr_glitch_filter);
return err;
}
static void ds1343_sysfs_unregister(struct device *dev)
{
struct ds1343_priv *priv = dev_get_drvdata(dev);
device_remove_file(dev, &dev_attr_glitch_filter);
device_remove_file(dev, &dev_attr_trickle_charger);
if (priv->irq <= 0)
return;
device_remove_file(dev, &dev_attr_alarm_status);
device_remove_file(dev, &dev_attr_alarm_mode);
}
static int ds1343_read_time(struct device *dev, struct rtc_time *dt)
{
struct ds1343_priv *priv = dev_get_drvdata(dev);
unsigned char buf[7];
int res;
res = regmap_bulk_read(priv->map, DS1343_SECONDS_REG, buf, 7);
if (res)
return res;
dt->tm_sec = bcd2bin(buf[0]);
dt->tm_min = bcd2bin(buf[1]);
dt->tm_hour = bcd2bin(buf[2] & 0x3F);
dt->tm_wday = bcd2bin(buf[3]) - 1;
dt->tm_mday = bcd2bin(buf[4]);
dt->tm_mon = bcd2bin(buf[5] & 0x1F) - 1;
dt->tm_year = bcd2bin(buf[6]) + 100; /* year offset from 1900 */
return rtc_valid_tm(dt);
}
static int ds1343_set_time(struct device *dev, struct rtc_time *dt)
{
struct ds1343_priv *priv = dev_get_drvdata(dev);
int res;
res = regmap_write(priv->map, DS1343_SECONDS_REG,
bin2bcd(dt->tm_sec));
if (res)
return res;
res = regmap_write(priv->map, DS1343_MINUTES_REG,
bin2bcd(dt->tm_min));
if (res)
return res;
res = regmap_write(priv->map, DS1343_HOURS_REG,
bin2bcd(dt->tm_hour) & 0x3F);
if (res)
return res;
res = regmap_write(priv->map, DS1343_DAY_REG,
bin2bcd(dt->tm_wday + 1));
if (res)
return res;
res = regmap_write(priv->map, DS1343_DATE_REG,
bin2bcd(dt->tm_mday));
if (res)
return res;
res = regmap_write(priv->map, DS1343_MONTH_REG,
bin2bcd(dt->tm_mon + 1));
if (res)
return res;
dt->tm_year %= 100;
res = regmap_write(priv->map, DS1343_YEAR_REG,
bin2bcd(dt->tm_year));
if (res)
return res;
return 0;
}
static int ds1343_update_alarm(struct device *dev)
{
struct ds1343_priv *priv = dev_get_drvdata(dev);
unsigned int control, stat;
unsigned char buf[4];
int res = 0;
res = regmap_read(priv->map, DS1343_CONTROL_REG, &control);
if (res)
return res;
res = regmap_read(priv->map, DS1343_STATUS_REG, &stat);
if (res)
return res;
control &= ~(DS1343_A0IE);
stat &= ~(DS1343_IRQF0);
res = regmap_write(priv->map, DS1343_CONTROL_REG, control);
if (res)
return res;
res = regmap_write(priv->map, DS1343_STATUS_REG, stat);
if (res)
return res;
buf[0] = priv->alarm_sec < 0 || (priv->irqen & RTC_UF) ?
0x80 : bin2bcd(priv->alarm_sec) & 0x7F;
buf[1] = priv->alarm_min < 0 || (priv->irqen & RTC_UF) ?
0x80 : bin2bcd(priv->alarm_min) & 0x7F;
buf[2] = priv->alarm_hour < 0 || (priv->irqen & RTC_UF) ?
0x80 : bin2bcd(priv->alarm_hour) & 0x3F;
buf[3] = priv->alarm_mday < 0 || (priv->irqen & RTC_UF) ?
0x80 : bin2bcd(priv->alarm_mday) & 0x7F;
res = regmap_bulk_write(priv->map, DS1343_ALM0_SEC_REG, buf, 4);
if (res)
return res;
if (priv->irqen) {
control |= DS1343_A0IE;
res = regmap_write(priv->map, DS1343_CONTROL_REG, control);
}
return res;
}
static int ds1343_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct ds1343_priv *priv = dev_get_drvdata(dev);
int res = 0;
unsigned int stat;
if (priv->irq <= 0)
return -EINVAL;
mutex_lock(&priv->mutex);
res = regmap_read(priv->map, DS1343_STATUS_REG, &stat);
if (res)
goto out;
alarm->enabled = !!(priv->irqen & RTC_AF);
alarm->pending = !!(stat & DS1343_IRQF0);
alarm->time.tm_sec = priv->alarm_sec < 0 ? 0 : priv->alarm_sec;
alarm->time.tm_min = priv->alarm_min < 0 ? 0 : priv->alarm_min;
alarm->time.tm_hour = priv->alarm_hour < 0 ? 0 : priv->alarm_hour;
alarm->time.tm_mday = priv->alarm_mday < 0 ? 0 : priv->alarm_mday;
alarm->time.tm_mon = -1;
alarm->time.tm_year = -1;
alarm->time.tm_wday = -1;
alarm->time.tm_yday = -1;
alarm->time.tm_isdst = -1;
out:
mutex_unlock(&priv->mutex);
return res;
}
static int ds1343_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct ds1343_priv *priv = dev_get_drvdata(dev);
int res = 0;
if (priv->irq <= 0)
return -EINVAL;
mutex_lock(&priv->mutex);
priv->alarm_sec = alarm->time.tm_sec;
priv->alarm_min = alarm->time.tm_min;
priv->alarm_hour = alarm->time.tm_hour;
priv->alarm_mday = alarm->time.tm_mday;
if (alarm->enabled)
priv->irqen |= RTC_AF;
res = ds1343_update_alarm(dev);
mutex_unlock(&priv->mutex);
return res;
}
static int ds1343_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct ds1343_priv *priv = dev_get_drvdata(dev);
int res = 0;
if (priv->irq <= 0)
return -EINVAL;
mutex_lock(&priv->mutex);
if (enabled)
priv->irqen |= RTC_AF;
else
priv->irqen &= ~RTC_AF;
res = ds1343_update_alarm(dev);
mutex_unlock(&priv->mutex);
return res;
}
static irqreturn_t ds1343_thread(int irq, void *dev_id)
{
struct ds1343_priv *priv = dev_id;
unsigned int stat, control;
int res = 0;
mutex_lock(&priv->mutex);
res = regmap_read(priv->map, DS1343_STATUS_REG, &stat);
if (res)
goto out;
if (stat & DS1343_IRQF0) {
stat &= ~DS1343_IRQF0;
regmap_write(priv->map, DS1343_STATUS_REG, stat);
res = regmap_read(priv->map, DS1343_CONTROL_REG, &control);
if (res)
goto out;
control &= ~DS1343_A0IE;
regmap_write(priv->map, DS1343_CONTROL_REG, control);
rtc_update_irq(priv->rtc, 1, RTC_AF | RTC_IRQF);
}
out:
mutex_unlock(&priv->mutex);
return IRQ_HANDLED;
}
static const struct rtc_class_ops ds1343_rtc_ops = {
.ioctl = ds1343_ioctl,
.read_time = ds1343_read_time,
.set_time = ds1343_set_time,
.read_alarm = ds1343_read_alarm,
.set_alarm = ds1343_set_alarm,
.alarm_irq_enable = ds1343_alarm_irq_enable,
};
static int ds1343_probe(struct spi_device *spi)
{
struct ds1343_priv *priv;
struct regmap_config config;
unsigned int data;
int res;
memset(&config, 0, sizeof(config));
config.reg_bits = 8;
config.val_bits = 8;
config.write_flag_mask = 0x80;
priv = devm_kzalloc(&spi->dev, sizeof(struct ds1343_priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->spi = spi;
mutex_init(&priv->mutex);
/* RTC DS1347 works in spi mode 3 and
* its chip select is active high
*/
spi->mode = SPI_MODE_3 | SPI_CS_HIGH;
spi->bits_per_word = 8;
res = spi_setup(spi);
if (res)
return res;
spi_set_drvdata(spi, priv);
priv->map = devm_regmap_init_spi(spi, &config);
if (IS_ERR(priv->map)) {
dev_err(&spi->dev, "spi regmap init failed for rtc ds1343\n");
return PTR_ERR(priv->map);
}
res = regmap_read(priv->map, DS1343_SECONDS_REG, &data);
if (res)
return res;
regmap_read(priv->map, DS1343_CONTROL_REG, &data);
data |= DS1343_INTCN;
data &= ~(DS1343_EOSC | DS1343_A1IE | DS1343_A0IE);
regmap_write(priv->map, DS1343_CONTROL_REG, data);
regmap_read(priv->map, DS1343_STATUS_REG, &data);
data &= ~(DS1343_OSF | DS1343_IRQF1 | DS1343_IRQF0);
regmap_write(priv->map, DS1343_STATUS_REG, data);
priv->rtc = devm_rtc_device_register(&spi->dev, "ds1343",
&ds1343_rtc_ops, THIS_MODULE);
if (IS_ERR(priv->rtc)) {
dev_err(&spi->dev, "unable to register rtc ds1343\n");
return PTR_ERR(priv->rtc);
}
priv->irq = spi->irq;
if (priv->irq >= 0) {
res = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
ds1343_thread,
IRQF_NO_SUSPEND | IRQF_ONESHOT,
"ds1343", priv);
if (res) {
priv->irq = -1;
dev_err(&spi->dev,
"unable to request irq for rtc ds1343\n");
} else {
device_set_wakeup_capable(&spi->dev, 1);
}
}
res = ds1343_sysfs_register(&spi->dev);
if (res)
dev_err(&spi->dev,
"unable to create sysfs entries for rtc ds1343\n");
return 0;
}
static int ds1343_remove(struct spi_device *spi)
{
struct ds1343_priv *priv = spi_get_drvdata(spi);
if (spi->irq) {
mutex_lock(&priv->mutex);
priv->irqen &= ~RTC_AF;
mutex_unlock(&priv->mutex);
devm_free_irq(&spi->dev, spi->irq, priv);
}
spi_set_drvdata(spi, NULL);
ds1343_sysfs_unregister(&spi->dev);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int ds1343_suspend(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
if (spi->irq >= 0 && device_may_wakeup(dev))
enable_irq_wake(spi->irq);
return 0;
}
static int ds1343_resume(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
if (spi->irq >= 0 && device_may_wakeup(dev))
disable_irq_wake(spi->irq);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(ds1343_pm, ds1343_suspend, ds1343_resume);
static struct spi_driver ds1343_driver = {
.driver = {
.name = "ds1343",
.owner = THIS_MODULE,
.pm = &ds1343_pm,
},
.probe = ds1343_probe,
.remove = ds1343_remove,
.id_table = ds1343_id,
};
module_spi_driver(ds1343_driver);
MODULE_DESCRIPTION("DS1343 RTC SPI Driver");
MODULE_AUTHOR("Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com>");
MODULE_LICENSE("GPL v2");
MODULE_VERSION(DS1343_DRV_VERSION);

View File

@@ -219,7 +219,7 @@ static int ds1742_rtc_remove(struct platform_device *pdev)
return 0;
}
static struct of_device_id __maybe_unused ds1742_rtc_of_match[] = {
static const struct of_device_id __maybe_unused ds1742_rtc_of_match[] = {
{ .compatible = "maxim,ds1742", },
{ }
};

View File

@@ -35,7 +35,7 @@ static inline int
compute_yday(efi_time_t *eft)
{
/* efi_time_t.month is in the [1-12] so, we need -1 */
return rtc_year_days(eft->day - 1, eft->month - 1, eft->year);
return rtc_year_days(eft->day, eft->month - 1, eft->year);
}
/*
* returns day of the week [0-6] 0=Sunday

View File

@@ -418,6 +418,9 @@ static struct clk *hym8563_clkout_register_clk(struct hym8563 *hym8563)
init.num_parents = 0;
hym8563->clkout_hw.init = &init;
/* optional override of the clockname */
of_property_read_string(node, "clock-output-names", &init.name);
/* register the clock */
clk = clk_register(&client->dev, &hym8563->clkout_hw);
@@ -585,7 +588,7 @@ static const struct i2c_device_id hym8563_id[] = {
};
MODULE_DEVICE_TABLE(i2c, hym8563_id);
static struct of_device_id hym8563_dt_idtable[] = {
static const struct of_device_id hym8563_dt_idtable[] = {
{ .compatible = "haoyu,hym8563" },
{},
};

View File

@@ -278,7 +278,7 @@ static int isl12057_probe(struct i2c_client *client,
}
#ifdef CONFIG_OF
static struct of_device_id isl12057_dt_match[] = {
static const struct of_device_id isl12057_dt_match[] = {
{ .compatible = "isl,isl12057" },
{ },
};

View File

@@ -66,8 +66,6 @@
#define M41T80_FEATURE_WD (1 << 3) /* Extra watchdog resolution */
#define M41T80_FEATURE_SQ_ALT (1 << 4) /* RSx bits are in reg 4 */
#define DRV_VERSION "0.05"
static DEFINE_MUTEX(m41t80_rtc_mutex);
static const struct i2c_device_id m41t80_id[] = {
{ "m41t62", M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT },
@@ -80,6 +78,7 @@ static const struct i2c_device_id m41t80_id[] = {
{ "m41st84", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
{ "m41st85", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
{ "m41st87", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
{ "rv4162", M41T80_FEATURE_SQ | M41T80_FEATURE_WD | M41T80_FEATURE_SQ_ALT },
{ }
};
MODULE_DEVICE_TABLE(i2c, m41t80_id);
@@ -232,7 +231,7 @@ static ssize_t m41t80_sysfs_show_flags(struct device *dev,
val = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
if (val < 0)
return -EIO;
return val;
return sprintf(buf, "%#x\n", val);
}
static DEVICE_ATTR(flags, S_IRUGO, m41t80_sysfs_show_flags, NULL);
@@ -252,7 +251,7 @@ static ssize_t m41t80_sysfs_show_sqwfreq(struct device *dev,
reg_sqw = M41T80_REG_WDAY;
val = i2c_smbus_read_byte_data(client, reg_sqw);
if (val < 0)
return -EIO;
return val;
val = (val >> 4) & 0xf;
switch (val) {
case 0:
@@ -271,7 +270,7 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev,
{
struct i2c_client *client = to_i2c_client(dev);
struct m41t80_data *clientdata = i2c_get_clientdata(client);
int almon, sqw, reg_sqw;
int almon, sqw, reg_sqw, rc;
int val = simple_strtoul(buf, NULL, 0);
if (!(clientdata->features & M41T80_FEATURE_SQ))
@@ -291,21 +290,30 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev,
/* disable SQW, set SQW frequency & re-enable */
almon = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
if (almon < 0)
return -EIO;
return almon;
reg_sqw = M41T80_REG_SQW;
if (clientdata->features & M41T80_FEATURE_SQ_ALT)
reg_sqw = M41T80_REG_WDAY;
sqw = i2c_smbus_read_byte_data(client, reg_sqw);
if (sqw < 0)
return -EIO;
return sqw;
sqw = (sqw & 0x0f) | (val << 4);
if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
almon & ~M41T80_ALMON_SQWE) < 0 ||
i2c_smbus_write_byte_data(client, reg_sqw, sqw) < 0)
return -EIO;
if (val && i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
almon | M41T80_ALMON_SQWE) < 0)
return -EIO;
rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
almon & ~M41T80_ALMON_SQWE);
if (rc < 0)
return rc;
if (val) {
rc = i2c_smbus_write_byte_data(client, reg_sqw, sqw);
if (rc < 0)
return rc;
rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
almon | M41T80_ALMON_SQWE);
if (rc <0)
return rc;
}
return count;
}
static DEVICE_ATTR(sqwfreq, S_IRUGO | S_IWUSR,
@@ -629,40 +637,28 @@ static int m41t80_probe(struct i2c_client *client,
struct m41t80_data *clientdata = NULL;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C
| I2C_FUNC_SMBUS_BYTE_DATA)) {
rc = -ENODEV;
goto exit;
}
dev_info(&client->dev,
"chip found, driver version " DRV_VERSION "\n");
| I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
clientdata = devm_kzalloc(&client->dev, sizeof(*clientdata),
GFP_KERNEL);
if (!clientdata) {
rc = -ENOMEM;
goto exit;
}
if (!clientdata)
return -ENOMEM;
clientdata->features = id->driver_data;
i2c_set_clientdata(client, clientdata);
rtc = devm_rtc_device_register(&client->dev, client->name,
&m41t80_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
rc = PTR_ERR(rtc);
rtc = NULL;
goto exit;
}
if (IS_ERR(rtc))
return PTR_ERR(rtc);
clientdata->rtc = rtc;
/* Make sure HT (Halt Update) bit is cleared */
rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_HOUR);
if (rc < 0)
goto ht_err;
if (rc & M41T80_ALHOUR_HT) {
if (rc >= 0 && rc & M41T80_ALHOUR_HT) {
if (clientdata->features & M41T80_FEATURE_HT) {
m41t80_get_datetime(client, &tm);
dev_info(&client->dev, "HT bit was set!\n");
@@ -673,53 +669,44 @@ static int m41t80_probe(struct i2c_client *client,
tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
tm.tm_min, tm.tm_sec);
}
if (i2c_smbus_write_byte_data(client,
M41T80_REG_ALARM_HOUR,
rc & ~M41T80_ALHOUR_HT) < 0)
goto ht_err;
rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_HOUR,
rc & ~M41T80_ALHOUR_HT);
}
if (rc < 0) {
dev_err(&client->dev, "Can't clear HT bit\n");
return rc;
}
/* Make sure ST (stop) bit is cleared */
rc = i2c_smbus_read_byte_data(client, M41T80_REG_SEC);
if (rc < 0)
goto st_err;
if (rc & M41T80_SEC_ST) {
if (i2c_smbus_write_byte_data(client, M41T80_REG_SEC,
rc & ~M41T80_SEC_ST) < 0)
goto st_err;
if (rc >= 0 && rc & M41T80_SEC_ST)
rc = i2c_smbus_write_byte_data(client, M41T80_REG_SEC,
rc & ~M41T80_SEC_ST);
if (rc < 0) {
dev_err(&client->dev, "Can't clear ST bit\n");
return rc;
}
rc = m41t80_sysfs_register(&client->dev);
if (rc)
goto exit;
return rc;
#ifdef CONFIG_RTC_DRV_M41T80_WDT
if (clientdata->features & M41T80_FEATURE_HT) {
save_client = client;
rc = misc_register(&wdt_dev);
if (rc)
goto exit;
return rc;
rc = register_reboot_notifier(&wdt_notifier);
if (rc) {
misc_deregister(&wdt_dev);
goto exit;
return rc;
}
}
#endif
return 0;
st_err:
rc = -EIO;
dev_err(&client->dev, "Can't clear ST bit\n");
goto exit;
ht_err:
rc = -EIO;
dev_err(&client->dev, "Can't clear HT bit\n");
goto exit;
exit:
return rc;
}
static int m41t80_remove(struct i2c_client *client)
@@ -750,4 +737,3 @@ module_i2c_driver(m41t80_driver);
MODULE_AUTHOR("Alexander Bigga <ab@mycable.de>");
MODULE_DESCRIPTION("ST Microelectronics M41T80 series RTC I2C Client Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);

199
drivers/rtc/rtc-mcp795.c Normal file
View File

@@ -0,0 +1,199 @@
/*
* SPI Driver for Microchip MCP795 RTC
*
* Copyright (C) Josef Gajdusek <atx@atx.name>
*
* based on other Linux RTC drivers
*
* Device datasheet:
* http://ww1.microchip.com/downloads/en/DeviceDoc/22280A.pdf
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/printk.h>
#include <linux/spi/spi.h>
#include <linux/rtc.h>
/* MCP795 Instructions, see datasheet table 3-1 */
#define MCP795_EEREAD 0x03
#define MCP795_EEWRITE 0x02
#define MCP795_EEWRDI 0x04
#define MCP795_EEWREN 0x06
#define MCP795_SRREAD 0x05
#define MCP795_SRWRITE 0x01
#define MCP795_READ 0x13
#define MCP795_WRITE 0x12
#define MCP795_UNLOCK 0x14
#define MCP795_IDWRITE 0x32
#define MCP795_IDREAD 0x33
#define MCP795_CLRWDT 0x44
#define MCP795_CLRRAM 0x54
#define MCP795_ST_BIT 0x80
#define MCP795_24_BIT 0x40
static int mcp795_rtcc_read(struct device *dev, u8 addr, u8 *buf, u8 count)
{
struct spi_device *spi = to_spi_device(dev);
int ret;
u8 tx[2];
tx[0] = MCP795_READ;
tx[1] = addr;
ret = spi_write_then_read(spi, tx, sizeof(tx), buf, count);
if (ret)
dev_err(dev, "Failed reading %d bytes from address %x.\n",
count, addr);
return ret;
}
static int mcp795_rtcc_write(struct device *dev, u8 addr, u8 *data, u8 count)
{
struct spi_device *spi = to_spi_device(dev);
int ret;
u8 tx[2 + count];
tx[0] = MCP795_WRITE;
tx[1] = addr;
memcpy(&tx[2], data, count);
ret = spi_write(spi, tx, 2 + count);
if (ret)
dev_err(dev, "Failed to write %d bytes to address %x.\n",
count, addr);
return ret;
}
static int mcp795_rtcc_set_bits(struct device *dev, u8 addr, u8 mask, u8 state)
{
int ret;
u8 tmp;
ret = mcp795_rtcc_read(dev, addr, &tmp, 1);
if (ret)
return ret;
if ((tmp & mask) != state) {
tmp = (tmp & ~mask) | state;
ret = mcp795_rtcc_write(dev, addr, &tmp, 1);
}
return ret;
}
static int mcp795_set_time(struct device *dev, struct rtc_time *tim)
{
int ret;
u8 data[7];
/* Read first, so we can leave config bits untouched */
ret = mcp795_rtcc_read(dev, 0x01, data, sizeof(data));
if (ret)
return ret;
data[0] = (data[0] & 0x80) | ((tim->tm_sec / 10) << 4) | (tim->tm_sec % 10);
data[1] = (data[1] & 0x80) | ((tim->tm_min / 10) << 4) | (tim->tm_min % 10);
data[2] = ((tim->tm_hour / 10) << 4) | (tim->tm_hour % 10);
data[4] = ((tim->tm_mday / 10) << 4) | ((tim->tm_mday) % 10);
data[5] = (data[5] & 0x10) | (tim->tm_mon / 10) | (tim->tm_mon % 10);
if (tim->tm_year > 100)
tim->tm_year -= 100;
data[6] = ((tim->tm_year / 10) << 4) | (tim->tm_year % 10);
ret = mcp795_rtcc_write(dev, 0x01, data, sizeof(data));
if (ret)
return ret;
dev_dbg(dev, "Set mcp795: %04d-%02d-%02d %02d:%02d:%02d\n",
tim->tm_year + 1900, tim->tm_mon, tim->tm_mday,
tim->tm_hour, tim->tm_min, tim->tm_sec);
return 0;
}
static int mcp795_read_time(struct device *dev, struct rtc_time *tim)
{
int ret;
u8 data[7];
ret = mcp795_rtcc_read(dev, 0x01, data, sizeof(data));
if (ret)
return ret;
tim->tm_sec = ((data[0] & 0x70) >> 4) * 10 + (data[0] & 0x0f);
tim->tm_min = ((data[1] & 0x70) >> 4) * 10 + (data[1] & 0x0f);
tim->tm_hour = ((data[2] & 0x30) >> 4) * 10 + (data[2] & 0x0f);
tim->tm_mday = ((data[4] & 0x30) >> 4) * 10 + (data[4] & 0x0f);
tim->tm_mon = ((data[5] & 0x10) >> 4) * 10 + (data[5] & 0x0f);
tim->tm_year = ((data[6] & 0xf0) >> 4) * 10 + (data[6] & 0x0f) + 100; /* Assume we are in 20xx */
dev_dbg(dev, "Read from mcp795: %04d-%02d-%02d %02d:%02d:%02d\n",
tim->tm_year + 1900, tim->tm_mon, tim->tm_mday,
tim->tm_hour, tim->tm_min, tim->tm_sec);
return rtc_valid_tm(tim);
}
static struct rtc_class_ops mcp795_rtc_ops = {
.read_time = mcp795_read_time,
.set_time = mcp795_set_time
};
static int mcp795_probe(struct spi_device *spi)
{
struct rtc_device *rtc;
int ret;
spi->mode = SPI_MODE_0;
spi->bits_per_word = 8;
ret = spi_setup(spi);
if (ret) {
dev_err(&spi->dev, "Unable to setup SPI\n");
return ret;
}
/* Start the oscillator */
mcp795_rtcc_set_bits(&spi->dev, 0x01, MCP795_ST_BIT, MCP795_ST_BIT);
/* Clear the 12 hour mode flag*/
mcp795_rtcc_set_bits(&spi->dev, 0x03, MCP795_24_BIT, 0);
rtc = devm_rtc_device_register(&spi->dev, "rtc-mcp795",
&mcp795_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
spi_set_drvdata(spi, rtc);
return 0;
}
static struct spi_driver mcp795_driver = {
.driver = {
.name = "rtc-mcp795",
.owner = THIS_MODULE,
},
.probe = mcp795_probe,
};
module_spi_driver(mcp795_driver);
MODULE_DESCRIPTION("MCP795 RTC SPI Driver");
MODULE_AUTHOR("Josef Gajdusek <atx@atx.name>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:mcp795");

View File

@@ -319,7 +319,7 @@ static int __exit mv_rtc_remove(struct platform_device *pdev)
}
#ifdef CONFIG_OF
static struct of_device_id rtc_mv_of_match_table[] = {
static const struct of_device_id rtc_mv_of_match_table[] = {
{ .compatible = "marvell,orion-rtc", },
{}
};

View File

@@ -73,43 +73,52 @@
#define OMAP_RTC_IRQWAKEEN 0x7c
/* OMAP_RTC_CTRL_REG bit fields: */
#define OMAP_RTC_CTRL_SPLIT (1<<7)
#define OMAP_RTC_CTRL_DISABLE (1<<6)
#define OMAP_RTC_CTRL_SET_32_COUNTER (1<<5)
#define OMAP_RTC_CTRL_TEST (1<<4)
#define OMAP_RTC_CTRL_MODE_12_24 (1<<3)
#define OMAP_RTC_CTRL_AUTO_COMP (1<<2)
#define OMAP_RTC_CTRL_ROUND_30S (1<<1)
#define OMAP_RTC_CTRL_STOP (1<<0)
#define OMAP_RTC_CTRL_SPLIT BIT(7)
#define OMAP_RTC_CTRL_DISABLE BIT(6)
#define OMAP_RTC_CTRL_SET_32_COUNTER BIT(5)
#define OMAP_RTC_CTRL_TEST BIT(4)
#define OMAP_RTC_CTRL_MODE_12_24 BIT(3)
#define OMAP_RTC_CTRL_AUTO_COMP BIT(2)
#define OMAP_RTC_CTRL_ROUND_30S BIT(1)
#define OMAP_RTC_CTRL_STOP BIT(0)
/* OMAP_RTC_STATUS_REG bit fields: */
#define OMAP_RTC_STATUS_POWER_UP (1<<7)
#define OMAP_RTC_STATUS_ALARM (1<<6)
#define OMAP_RTC_STATUS_1D_EVENT (1<<5)
#define OMAP_RTC_STATUS_1H_EVENT (1<<4)
#define OMAP_RTC_STATUS_1M_EVENT (1<<3)
#define OMAP_RTC_STATUS_1S_EVENT (1<<2)
#define OMAP_RTC_STATUS_RUN (1<<1)
#define OMAP_RTC_STATUS_BUSY (1<<0)
#define OMAP_RTC_STATUS_POWER_UP BIT(7)
#define OMAP_RTC_STATUS_ALARM BIT(6)
#define OMAP_RTC_STATUS_1D_EVENT BIT(5)
#define OMAP_RTC_STATUS_1H_EVENT BIT(4)
#define OMAP_RTC_STATUS_1M_EVENT BIT(3)
#define OMAP_RTC_STATUS_1S_EVENT BIT(2)
#define OMAP_RTC_STATUS_RUN BIT(1)
#define OMAP_RTC_STATUS_BUSY BIT(0)
/* OMAP_RTC_INTERRUPTS_REG bit fields: */
#define OMAP_RTC_INTERRUPTS_IT_ALARM (1<<3)
#define OMAP_RTC_INTERRUPTS_IT_TIMER (1<<2)
#define OMAP_RTC_INTERRUPTS_IT_ALARM BIT(3)
#define OMAP_RTC_INTERRUPTS_IT_TIMER BIT(2)
/* OMAP_RTC_OSC_REG bit fields: */
#define OMAP_RTC_OSC_32KCLK_EN BIT(6)
/* OMAP_RTC_IRQWAKEEN bit fields: */
#define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN (1<<1)
#define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN BIT(1)
/* OMAP_RTC_KICKER values */
#define KICK0_VALUE 0x83e70b13
#define KICK1_VALUE 0x95a4f1e0
#define OMAP_RTC_HAS_KICKER 0x1
#define OMAP_RTC_HAS_KICKER BIT(0)
/*
* Few RTC IP revisions has special WAKE-EN Register to enable Wakeup
* generation for event Alarm.
*/
#define OMAP_RTC_HAS_IRQWAKEEN 0x2
#define OMAP_RTC_HAS_IRQWAKEEN BIT(1)
/*
* Some RTC IP revisions (like those in AM335x and DRA7x) need
* the 32KHz clock to be explicitly enabled.
*/
#define OMAP_RTC_HAS_32KCLK_EN BIT(2)
static void __iomem *rtc_base;
@@ -162,17 +171,28 @@ static irqreturn_t rtc_irq(int irq, void *rtc)
static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
u8 reg;
u8 reg, irqwake_reg = 0;
struct platform_device *pdev = to_platform_device(dev);
const struct platform_device_id *id_entry =
platform_get_device_id(pdev);
local_irq_disable();
rtc_wait_not_busy();
reg = rtc_read(OMAP_RTC_INTERRUPTS_REG);
if (enabled)
if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN)
irqwake_reg = rtc_read(OMAP_RTC_IRQWAKEEN);
if (enabled) {
reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
else
irqwake_reg |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
} else {
reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
}
rtc_wait_not_busy();
rtc_write(reg, OMAP_RTC_INTERRUPTS_REG);
if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN)
rtc_write(irqwake_reg, OMAP_RTC_IRQWAKEEN);
local_irq_enable();
return 0;
@@ -272,7 +292,10 @@ static int omap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
u8 reg;
u8 reg, irqwake_reg = 0;
struct platform_device *pdev = to_platform_device(dev);
const struct platform_device_id *id_entry =
platform_get_device_id(pdev);
if (tm2bcd(&alm->time) < 0)
return -EINVAL;
@@ -288,11 +311,19 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
rtc_write(alm->time.tm_sec, OMAP_RTC_ALARM_SECONDS_REG);
reg = rtc_read(OMAP_RTC_INTERRUPTS_REG);
if (alm->enabled)
if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN)
irqwake_reg = rtc_read(OMAP_RTC_IRQWAKEEN);
if (alm->enabled) {
reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
else
irqwake_reg |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
} else {
reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
}
rtc_write(reg, OMAP_RTC_INTERRUPTS_REG);
if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN)
rtc_write(irqwake_reg, OMAP_RTC_IRQWAKEEN);
local_irq_enable();
@@ -319,7 +350,8 @@ static struct platform_device_id omap_rtc_devtype[] = {
},
[OMAP_RTC_DATA_AM3352_IDX] = {
.name = "am3352-rtc",
.driver_data = OMAP_RTC_HAS_KICKER | OMAP_RTC_HAS_IRQWAKEEN,
.driver_data = OMAP_RTC_HAS_KICKER | OMAP_RTC_HAS_IRQWAKEEN |
OMAP_RTC_HAS_32KCLK_EN,
},
[OMAP_RTC_DATA_DA830_IDX] = {
.name = "da830-rtc",
@@ -352,6 +384,12 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
if (of_id)
pdev->id_entry = of_id->data;
id_entry = platform_get_device_id(pdev);
if (!id_entry) {
dev_err(&pdev->dev, "no matching device entry\n");
return -ENODEV;
}
omap_rtc_timer = platform_get_irq(pdev, 0);
if (omap_rtc_timer <= 0) {
pr_debug("%s: no update irq?\n", pdev->name);
@@ -373,8 +411,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
id_entry = platform_get_device_id(pdev);
if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER)) {
if (id_entry->driver_data & OMAP_RTC_HAS_KICKER) {
rtc_writel(KICK0_VALUE, OMAP_RTC_KICK0_REG);
rtc_writel(KICK1_VALUE, OMAP_RTC_KICK1_REG);
}
@@ -393,6 +430,10 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
*/
rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
/* enable RTC functional clock */
if (id_entry->driver_data & OMAP_RTC_HAS_32KCLK_EN)
rtc_writel(OMAP_RTC_OSC_32KCLK_EN, OMAP_RTC_OSC_REG);
/* clear old status */
reg = rtc_read(OMAP_RTC_STATUS_REG);
if (reg & (u8) OMAP_RTC_STATUS_POWER_UP) {
@@ -452,7 +493,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
return 0;
fail0:
if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER))
if (id_entry->driver_data & OMAP_RTC_HAS_KICKER)
rtc_writel(0, OMAP_RTC_KICK0_REG);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
@@ -469,7 +510,7 @@ static int __exit omap_rtc_remove(struct platform_device *pdev)
/* leave rtc running, but disable irqs */
rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER))
if (id_entry->driver_data & OMAP_RTC_HAS_KICKER)
rtc_writel(0, OMAP_RTC_KICK0_REG);
/* Disable the clock/module */
@@ -484,28 +525,16 @@ static u8 irqstat;
static int omap_rtc_suspend(struct device *dev)
{
u8 irqwake_stat;
struct platform_device *pdev = to_platform_device(dev);
const struct platform_device_id *id_entry =
platform_get_device_id(pdev);
irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG);
/* FIXME the RTC alarm is not currently acting as a wakeup event
* source on some platforms, and in fact this enable() call is just
* saving a flag that's never used...
*/
if (device_may_wakeup(dev)) {
if (device_may_wakeup(dev))
enable_irq_wake(omap_rtc_alarm);
if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) {
irqwake_stat = rtc_read(OMAP_RTC_IRQWAKEEN);
irqwake_stat |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
rtc_write(irqwake_stat, OMAP_RTC_IRQWAKEEN);
}
} else {
else
rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
}
/* Disable the clock/module */
pm_runtime_put_sync(dev);
@@ -515,25 +544,14 @@ static int omap_rtc_suspend(struct device *dev)
static int omap_rtc_resume(struct device *dev)
{
u8 irqwake_stat;
struct platform_device *pdev = to_platform_device(dev);
const struct platform_device_id *id_entry =
platform_get_device_id(pdev);
/* Enable the clock/module so that we can access the registers */
pm_runtime_get_sync(dev);
if (device_may_wakeup(dev)) {
if (device_may_wakeup(dev))
disable_irq_wake(omap_rtc_alarm);
if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) {
irqwake_stat = rtc_read(OMAP_RTC_IRQWAKEEN);
irqwake_stat &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
rtc_write(irqwake_stat, OMAP_RTC_IRQWAKEEN);
}
} else {
else
rtc_write(irqstat, OMAP_RTC_INTERRUPTS_REG);
}
return 0;
}
#endif

View File

@@ -352,7 +352,7 @@ static SIMPLE_DEV_PM_OPS(palmas_rtc_pm_ops, palmas_rtc_suspend,
palmas_rtc_resume);
#ifdef CONFIG_OF
static struct of_device_id of_palmas_rtc_match[] = {
static const struct of_device_id of_palmas_rtc_match[] = {
{ .compatible = "ti,palmas-rtc"},
{ },
};

View File

@@ -389,7 +389,7 @@ static int __exit pxa_rtc_remove(struct platform_device *pdev)
}
#ifdef CONFIG_OF
static struct of_device_id pxa_rtc_dt_ids[] = {
static const struct of_device_id pxa_rtc_dt_ids[] = {
{ .compatible = "marvell,pxa-rtc" },
{}
};

View File

@@ -338,7 +338,7 @@ static SIMPLE_DEV_PM_OPS(sa1100_rtc_pm_ops, sa1100_rtc_suspend,
sa1100_rtc_resume);
#ifdef CONFIG_OF
static struct of_device_id sa1100_rtc_dt_ids[] = {
static const struct of_device_id sa1100_rtc_dt_ids[] = {
{ .compatible = "mrvl,sa1100-rtc", },
{ .compatible = "mrvl,mmp-rtc", },
{}

278
drivers/rtc/rtc-xgene.c Normal file
View File

@@ -0,0 +1,278 @@
/*
* APM X-Gene SoC Real Time Clock Driver
*
* Copyright (c) 2014, Applied Micro Circuits Corporation
* Author: Rameshwar Prasad Sahu <rsahu@apm.com>
* Loc Ho <lho@apm.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/rtc.h>
/* RTC CSR Registers */
#define RTC_CCVR 0x00
#define RTC_CMR 0x04
#define RTC_CLR 0x08
#define RTC_CCR 0x0C
#define RTC_CCR_IE BIT(0)
#define RTC_CCR_MASK BIT(1)
#define RTC_CCR_EN BIT(2)
#define RTC_CCR_WEN BIT(3)
#define RTC_STAT 0x10
#define RTC_STAT_BIT BIT(0)
#define RTC_RSTAT 0x14
#define RTC_EOI 0x18
#define RTC_VER 0x1C
struct xgene_rtc_dev {
struct rtc_device *rtc;
struct device *dev;
unsigned long alarm_time;
void __iomem *csr_base;
struct clk *clk;
unsigned int irq_wake;
};
static int xgene_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
rtc_time_to_tm(readl(pdata->csr_base + RTC_CCVR), tm);
return rtc_valid_tm(tm);
}
static int xgene_rtc_set_mmss(struct device *dev, unsigned long secs)
{
struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
/*
* NOTE: After the following write, the RTC_CCVR is only reflected
* after the update cycle of 1 seconds.
*/
writel((u32) secs, pdata->csr_base + RTC_CLR);
readl(pdata->csr_base + RTC_CLR); /* Force a barrier */
return 0;
}
static int xgene_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
rtc_time_to_tm(pdata->alarm_time, &alrm->time);
alrm->enabled = readl(pdata->csr_base + RTC_CCR) & RTC_CCR_IE;
return 0;
}
static int xgene_rtc_alarm_irq_enable(struct device *dev, u32 enabled)
{
struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
u32 ccr;
ccr = readl(pdata->csr_base + RTC_CCR);
if (enabled) {
ccr &= ~RTC_CCR_MASK;
ccr |= RTC_CCR_IE;
} else {
ccr &= ~RTC_CCR_IE;
ccr |= RTC_CCR_MASK;
}
writel(ccr, pdata->csr_base + RTC_CCR);
return 0;
}
static int xgene_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
unsigned long rtc_time;
unsigned long alarm_time;
rtc_time = readl(pdata->csr_base + RTC_CCVR);
rtc_tm_to_time(&alrm->time, &alarm_time);
pdata->alarm_time = alarm_time;
writel((u32) pdata->alarm_time, pdata->csr_base + RTC_CMR);
xgene_rtc_alarm_irq_enable(dev, alrm->enabled);
return 0;
}
static const struct rtc_class_ops xgene_rtc_ops = {
.read_time = xgene_rtc_read_time,
.set_mmss = xgene_rtc_set_mmss,
.read_alarm = xgene_rtc_read_alarm,
.set_alarm = xgene_rtc_set_alarm,
.alarm_irq_enable = xgene_rtc_alarm_irq_enable,
};
static irqreturn_t xgene_rtc_interrupt(int irq, void *id)
{
struct xgene_rtc_dev *pdata = (struct xgene_rtc_dev *) id;
/* Check if interrupt asserted */
if (!(readl(pdata->csr_base + RTC_STAT) & RTC_STAT_BIT))
return IRQ_NONE;
/* Clear interrupt */
readl(pdata->csr_base + RTC_EOI);
rtc_update_irq(pdata->rtc, 1, RTC_IRQF | RTC_AF);
return IRQ_HANDLED;
}
static int xgene_rtc_probe(struct platform_device *pdev)
{
struct xgene_rtc_dev *pdata;
struct resource *res;
int ret;
int irq;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
platform_set_drvdata(pdev, pdata);
pdata->dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
pdata->csr_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(pdata->csr_base))
return PTR_ERR(pdata->csr_base);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "No IRQ resource\n");
return irq;
}
ret = devm_request_irq(&pdev->dev, irq, xgene_rtc_interrupt, 0,
dev_name(&pdev->dev), pdata);
if (ret) {
dev_err(&pdev->dev, "Could not request IRQ\n");
return ret;
}
pdata->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(pdata->clk)) {
dev_err(&pdev->dev, "Couldn't get the clock for RTC\n");
return -ENODEV;
}
clk_prepare_enable(pdata->clk);
/* Turn on the clock and the crystal */
writel(RTC_CCR_EN, pdata->csr_base + RTC_CCR);
device_init_wakeup(&pdev->dev, 1);
pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&xgene_rtc_ops, THIS_MODULE);
if (IS_ERR(pdata->rtc)) {
clk_disable_unprepare(pdata->clk);
return PTR_ERR(pdata->rtc);
}
/* HW does not support update faster than 1 seconds */
pdata->rtc->uie_unsupported = 1;
return 0;
}
static int xgene_rtc_remove(struct platform_device *pdev)
{
struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev);
xgene_rtc_alarm_irq_enable(&pdev->dev, 0);
device_init_wakeup(&pdev->dev, 0);
clk_disable_unprepare(pdata->clk);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int xgene_rtc_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev);
int irq;
irq = platform_get_irq(pdev, 0);
if (device_may_wakeup(&pdev->dev)) {
if (!enable_irq_wake(irq))
pdata->irq_wake = 1;
} else {
xgene_rtc_alarm_irq_enable(dev, 0);
clk_disable(pdata->clk);
}
return 0;
}
static int xgene_rtc_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev);
int irq;
irq = platform_get_irq(pdev, 0);
if (device_may_wakeup(&pdev->dev)) {
if (pdata->irq_wake) {
disable_irq_wake(irq);
pdata->irq_wake = 0;
}
} else {
clk_enable(pdata->clk);
xgene_rtc_alarm_irq_enable(dev, 1);
}
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(xgene_rtc_pm_ops, xgene_rtc_suspend, xgene_rtc_resume);
#ifdef CONFIG_OF
static const struct of_device_id xgene_rtc_of_match[] = {
{.compatible = "apm,xgene-rtc" },
{ }
};
MODULE_DEVICE_TABLE(of, xgene_rtc_of_match);
#endif
static struct platform_driver xgene_rtc_driver = {
.probe = xgene_rtc_probe,
.remove = xgene_rtc_remove,
.driver = {
.owner = THIS_MODULE,
.name = "xgene-rtc",
.pm = &xgene_rtc_pm_ops,
.of_match_table = of_match_ptr(xgene_rtc_of_match),
},
};
module_platform_driver(xgene_rtc_driver);
MODULE_DESCRIPTION("APM X-Gene SoC RTC driver");
MODULE_AUTHOR("Rameshwar Sahu <rsahu@apm.com>");
MODULE_LICENSE("GPL");