Merge tag 'mfd-next-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones: "Core Frameworks: - Set 'struct device' fwnode when registering a new device New Drivers: - Add support for ROHM BD70528 PMIC New Device Support: - Add support for LP87561 4-Phase Regulator to TI LP87565 PMIC - Add support for RK809 and RK817 to Rockchip RK808 - Add support for Lid Angle to ChromeOS core - Add support for CS47L15 CODEC to Madera core - Add support for CS47L92 CODEC to Madera core - Add support for ChromeOS (legacy) Accelerometers in ChromeOS core - Add support for Add Intel Elkhart Lake PCH to Intel LPSS New Functionality: - Provide regulator supply information when registering; madera-core - Additional Device Tree support; lp87565, madera, cros-ec, rohm,bd71837-pmic - Allow over-riding power button press via Device Tree; rohm-bd718x7 - Differentiate between running processors; cros_ec_dev Fix-ups: - Big header file update; cros_ec_commands.h - Split header per-subsystem; rohm-bd718x7 - Remove superfluous code; menelaus, cs5535-mfd, cs47lXX-tables - Trivial; sorting, coding style; intel-lpss-pci - Only remove Power Off functionality if set locally; rk808 - Make use for Power Off Prepare(); rk808 - Fix spelling mistake in header guards; stmfx - Properly free IDA resources - SPDX fixups; cs47lXX-tables, madera - Error path fixups; hi655x-pmic Bug Fixes: - Add missing break in case() statement - Repair undefined behaviour when not initialising variables; arizona-core, madera-core - Fix reference to Device Tree documentation; madera" * tag 'mfd-next-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (45 commits) mfd: hi655x-pmic: Fix missing return value check for devm_regmap_init_mmio_clk mfd: madera: Fixup SPDX headers mfd: madera: Remove some unused registers and fix some defaults mfd: intel-lpss: Release IDA resources mfd: intel-lpss: Add Intel Elkhart Lake PCH PCI IDs mfd: cs5535-mfd: Remove ifdef OLPC noise mfd: stmfx: Fix macro definition spelling dt-bindings: mfd: Add link to ROHM BD71847 Datasheet MAINAINERS: Swap words in INTEL PMIC MULTIFUNCTION DEVICE DRIVERS mfd: cros_ec_dev: Register cros_ec_accel_legacy driver as a subdevice mfd: rk808: Prepare rk805 for poweroff mfd: rk808: Check pm_power_off pointer mfd: cros_ec: differentiate SCP from EC by feature bit dt-bindings: Add binding for cros-ec-rpmsg mfd: madera: Add Madera core support for CS47L92 mfd: madera: Add Madera core support for CS47L15 mfd: madera: Update DT bindings to add additional CODECs mfd: madera: Add supply mapping for MICVDD mfd: madera: Fix potential uninitialised use of variable mfd: madera: Fix bad reference to pinctrl.txt file ...
此提交包含在:
@@ -374,11 +374,11 @@ config RTC_DRV_MAX77686
|
||||
will be called rtc-max77686.
|
||||
|
||||
config RTC_DRV_RK808
|
||||
tristate "Rockchip RK805/RK808/RK818 RTC"
|
||||
tristate "Rockchip RK805/RK808/RK809/RK817/RK818 RTC"
|
||||
depends on MFD_RK808
|
||||
help
|
||||
If you say yes here you will get support for the
|
||||
RTC of RK805, RK808 and RK818 PMIC.
|
||||
RTC of RK805, RK809 and RK817, RK808 and RK818 PMIC.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rk808-rtc.
|
||||
@@ -498,6 +498,14 @@ config RTC_DRV_M41T80_WDT
|
||||
help
|
||||
If you say Y here you will get support for the
|
||||
watchdog timer in the ST M41T60 and M41T80 RTC chips series.
|
||||
config RTC_DRV_BD70528
|
||||
tristate "ROHM BD70528 PMIC RTC"
|
||||
help
|
||||
If you say Y here you will get support for the RTC
|
||||
on ROHM BD70528 Power Management IC.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-bd70528.
|
||||
|
||||
config RTC_DRV_BQ32K
|
||||
tristate "TI BQ32000"
|
||||
|
@@ -38,6 +38,7 @@ obj-$(CONFIG_RTC_DRV_ASPEED) += rtc-aspeed.o
|
||||
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
|
||||
obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
|
||||
obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o
|
||||
obj-$(CONFIG_RTC_DRV_BD70528) += rtc-bd70528.o
|
||||
obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o
|
||||
obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o
|
||||
obj-$(CONFIG_RTC_DRV_BRCMSTB) += rtc-brcmstb-waketimer.o
|
||||
|
500
drivers/rtc/rtc-bd70528.c
一般檔案
500
drivers/rtc/rtc-bd70528.c
一般檔案
@@ -0,0 +1,500 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
//
|
||||
// Copyright (C) 2018 ROHM Semiconductors
|
||||
//
|
||||
// RTC driver for ROHM BD70528 PMIC
|
||||
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/mfd/rohm-bd70528.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
/*
|
||||
* We read regs RTC_SEC => RTC_YEAR
|
||||
* this struct is ordered according to chip registers.
|
||||
* Keep it u8 only to avoid padding issues.
|
||||
*/
|
||||
struct bd70528_rtc_day {
|
||||
u8 sec;
|
||||
u8 min;
|
||||
u8 hour;
|
||||
} __packed;
|
||||
|
||||
struct bd70528_rtc_data {
|
||||
struct bd70528_rtc_day time;
|
||||
u8 week;
|
||||
u8 day;
|
||||
u8 month;
|
||||
u8 year;
|
||||
} __packed;
|
||||
|
||||
struct bd70528_rtc_wake {
|
||||
struct bd70528_rtc_day time;
|
||||
u8 ctrl;
|
||||
} __packed;
|
||||
|
||||
struct bd70528_rtc_alm {
|
||||
struct bd70528_rtc_data data;
|
||||
u8 alm_mask;
|
||||
u8 alm_repeat;
|
||||
} __packed;
|
||||
|
||||
struct bd70528_rtc {
|
||||
struct rohm_regmap_dev *mfd;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static int bd70528_set_wake(struct rohm_regmap_dev *bd70528,
|
||||
int enable, int *old_state)
|
||||
{
|
||||
int ret;
|
||||
unsigned int ctrl_reg;
|
||||
|
||||
ret = regmap_read(bd70528->regmap, BD70528_REG_WAKE_EN, &ctrl_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (old_state) {
|
||||
if (ctrl_reg & BD70528_MASK_WAKE_EN)
|
||||
*old_state |= BD70528_WAKE_STATE_BIT;
|
||||
else
|
||||
*old_state &= ~BD70528_WAKE_STATE_BIT;
|
||||
|
||||
if (!enable == !(*old_state & BD70528_WAKE_STATE_BIT))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (enable)
|
||||
ctrl_reg |= BD70528_MASK_WAKE_EN;
|
||||
else
|
||||
ctrl_reg &= ~BD70528_MASK_WAKE_EN;
|
||||
|
||||
return regmap_write(bd70528->regmap, BD70528_REG_WAKE_EN,
|
||||
ctrl_reg);
|
||||
}
|
||||
|
||||
static int bd70528_set_elapsed_tmr(struct rohm_regmap_dev *bd70528,
|
||||
int enable, int *old_state)
|
||||
{
|
||||
int ret;
|
||||
unsigned int ctrl_reg;
|
||||
|
||||
/*
|
||||
* TBD
|
||||
* What is the purpose of elapsed timer ?
|
||||
* Is the timeout registers counting down, or is the disable - re-enable
|
||||
* going to restart the elapsed-time counting? If counting is restarted
|
||||
* the timeout should be decreased by the amount of time that has
|
||||
* elapsed since starting the timer. Maybe we should store the monotonic
|
||||
* clock value when timer is started so that if RTC is set while timer
|
||||
* is armed we could do the compensation. This is a hack if RTC/system
|
||||
* clk are drifting. OTOH, RTC controlled via I2C is in any case
|
||||
* inaccurate...
|
||||
*/
|
||||
ret = regmap_read(bd70528->regmap, BD70528_REG_ELAPSED_TIMER_EN,
|
||||
&ctrl_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (old_state) {
|
||||
if (ctrl_reg & BD70528_MASK_ELAPSED_TIMER_EN)
|
||||
*old_state |= BD70528_ELAPSED_STATE_BIT;
|
||||
else
|
||||
*old_state &= ~BD70528_ELAPSED_STATE_BIT;
|
||||
|
||||
if ((!enable) == (!(*old_state & BD70528_ELAPSED_STATE_BIT)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (enable)
|
||||
ctrl_reg |= BD70528_MASK_ELAPSED_TIMER_EN;
|
||||
else
|
||||
ctrl_reg &= ~BD70528_MASK_ELAPSED_TIMER_EN;
|
||||
|
||||
return regmap_write(bd70528->regmap, BD70528_REG_ELAPSED_TIMER_EN,
|
||||
ctrl_reg);
|
||||
}
|
||||
|
||||
static int bd70528_set_rtc_based_timers(struct bd70528_rtc *r, int new_state,
|
||||
int *old_state)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = bd70528_wdt_set(r->mfd, new_state & BD70528_WDT_STATE_BIT,
|
||||
old_state);
|
||||
if (ret) {
|
||||
dev_err(r->dev,
|
||||
"Failed to disable WDG for RTC setting (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = bd70528_set_elapsed_tmr(r->mfd,
|
||||
new_state & BD70528_ELAPSED_STATE_BIT,
|
||||
old_state);
|
||||
if (ret) {
|
||||
dev_err(r->dev,
|
||||
"Failed to disable 'elapsed timer' for RTC setting\n");
|
||||
return ret;
|
||||
}
|
||||
ret = bd70528_set_wake(r->mfd, new_state & BD70528_WAKE_STATE_BIT,
|
||||
old_state);
|
||||
if (ret) {
|
||||
dev_err(r->dev,
|
||||
"Failed to disable 'wake timer' for RTC setting\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bd70528_re_enable_rtc_based_timers(struct bd70528_rtc *r,
|
||||
int old_state)
|
||||
{
|
||||
return bd70528_set_rtc_based_timers(r, old_state, NULL);
|
||||
}
|
||||
|
||||
static int bd70528_disable_rtc_based_timers(struct bd70528_rtc *r,
|
||||
int *old_state)
|
||||
{
|
||||
return bd70528_set_rtc_based_timers(r, 0, old_state);
|
||||
}
|
||||
|
||||
static inline void tmday2rtc(struct rtc_time *t, struct bd70528_rtc_day *d)
|
||||
{
|
||||
d->sec &= ~BD70528_MASK_RTC_SEC;
|
||||
d->min &= ~BD70528_MASK_RTC_MINUTE;
|
||||
d->hour &= ~BD70528_MASK_RTC_HOUR;
|
||||
d->sec |= bin2bcd(t->tm_sec);
|
||||
d->min |= bin2bcd(t->tm_min);
|
||||
d->hour |= bin2bcd(t->tm_hour);
|
||||
}
|
||||
|
||||
static inline void tm2rtc(struct rtc_time *t, struct bd70528_rtc_data *r)
|
||||
{
|
||||
r->day &= ~BD70528_MASK_RTC_DAY;
|
||||
r->week &= ~BD70528_MASK_RTC_WEEK;
|
||||
r->month &= ~BD70528_MASK_RTC_MONTH;
|
||||
/*
|
||||
* PM and 24H bits are not used by Wake - thus we clear them
|
||||
* here and not in tmday2rtc() which is also used by wake.
|
||||
*/
|
||||
r->time.hour &= ~(BD70528_MASK_RTC_HOUR_PM | BD70528_MASK_RTC_HOUR_24H);
|
||||
|
||||
tmday2rtc(t, &r->time);
|
||||
/*
|
||||
* We do always set time in 24H mode.
|
||||
*/
|
||||
r->time.hour |= BD70528_MASK_RTC_HOUR_24H;
|
||||
r->day |= bin2bcd(t->tm_mday);
|
||||
r->week |= bin2bcd(t->tm_wday);
|
||||
r->month |= bin2bcd(t->tm_mon + 1);
|
||||
r->year = bin2bcd(t->tm_year - 100);
|
||||
}
|
||||
|
||||
static inline void rtc2tm(struct bd70528_rtc_data *r, struct rtc_time *t)
|
||||
{
|
||||
t->tm_sec = bcd2bin(r->time.sec & BD70528_MASK_RTC_SEC);
|
||||
t->tm_min = bcd2bin(r->time.min & BD70528_MASK_RTC_MINUTE);
|
||||
t->tm_hour = bcd2bin(r->time.hour & BD70528_MASK_RTC_HOUR);
|
||||
/*
|
||||
* If RTC is in 12H mode, then bit BD70528_MASK_RTC_HOUR_PM
|
||||
* is not BCD value but tells whether it is AM or PM
|
||||
*/
|
||||
if (!(r->time.hour & BD70528_MASK_RTC_HOUR_24H)) {
|
||||
t->tm_hour %= 12;
|
||||
if (r->time.hour & BD70528_MASK_RTC_HOUR_PM)
|
||||
t->tm_hour += 12;
|
||||
}
|
||||
t->tm_mday = bcd2bin(r->day & BD70528_MASK_RTC_DAY);
|
||||
t->tm_mon = bcd2bin(r->month & BD70528_MASK_RTC_MONTH) - 1;
|
||||
t->tm_year = 100 + bcd2bin(r->year & BD70528_MASK_RTC_YEAR);
|
||||
t->tm_wday = bcd2bin(r->week & BD70528_MASK_RTC_WEEK);
|
||||
}
|
||||
|
||||
static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a)
|
||||
{
|
||||
struct bd70528_rtc_wake wake;
|
||||
struct bd70528_rtc_alm alm;
|
||||
int ret;
|
||||
struct bd70528_rtc *r = dev_get_drvdata(dev);
|
||||
struct rohm_regmap_dev *bd70528 = r->mfd;
|
||||
|
||||
ret = regmap_bulk_read(bd70528->regmap, BD70528_REG_RTC_WAKE_START,
|
||||
&wake, sizeof(wake));
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read wake regs\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_bulk_read(bd70528->regmap, BD70528_REG_RTC_ALM_START,
|
||||
&alm, sizeof(alm));
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read alarm regs\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
tm2rtc(&a->time, &alm.data);
|
||||
tmday2rtc(&a->time, &wake.time);
|
||||
|
||||
if (a->enabled) {
|
||||
alm.alm_mask &= ~BD70528_MASK_ALM_EN;
|
||||
wake.ctrl |= BD70528_MASK_WAKE_EN;
|
||||
} else {
|
||||
alm.alm_mask |= BD70528_MASK_ALM_EN;
|
||||
wake.ctrl &= ~BD70528_MASK_WAKE_EN;
|
||||
}
|
||||
|
||||
ret = regmap_bulk_write(bd70528->regmap,
|
||||
BD70528_REG_RTC_WAKE_START, &wake,
|
||||
sizeof(wake));
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to set wake time\n");
|
||||
return ret;
|
||||
}
|
||||
ret = regmap_bulk_write(bd70528->regmap, BD70528_REG_RTC_ALM_START,
|
||||
&alm, sizeof(alm));
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to set alarm time\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bd70528_read_alarm(struct device *dev, struct rtc_wkalrm *a)
|
||||
{
|
||||
struct bd70528_rtc_alm alm;
|
||||
int ret;
|
||||
struct bd70528_rtc *r = dev_get_drvdata(dev);
|
||||
struct rohm_regmap_dev *bd70528 = r->mfd;
|
||||
|
||||
ret = regmap_bulk_read(bd70528->regmap, BD70528_REG_RTC_ALM_START,
|
||||
&alm, sizeof(alm));
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read alarm regs\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtc2tm(&alm.data, &a->time);
|
||||
a->time.tm_mday = -1;
|
||||
a->time.tm_mon = -1;
|
||||
a->time.tm_year = -1;
|
||||
a->enabled = !(alm.alm_mask & BD70528_MASK_ALM_EN);
|
||||
a->pending = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t)
|
||||
{
|
||||
int ret, tmpret, old_states;
|
||||
struct bd70528_rtc_data rtc_data;
|
||||
struct bd70528_rtc *r = dev_get_drvdata(dev);
|
||||
struct rohm_regmap_dev *bd70528 = r->mfd;
|
||||
|
||||
ret = bd70528_disable_rtc_based_timers(r, &old_states);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tmpret = regmap_bulk_read(bd70528->regmap,
|
||||
BD70528_REG_RTC_START, &rtc_data,
|
||||
sizeof(rtc_data));
|
||||
if (tmpret) {
|
||||
dev_err(dev, "Failed to read RTC time registers\n");
|
||||
goto renable_out;
|
||||
}
|
||||
tm2rtc(t, &rtc_data);
|
||||
|
||||
tmpret = regmap_bulk_write(bd70528->regmap,
|
||||
BD70528_REG_RTC_START, &rtc_data,
|
||||
sizeof(rtc_data));
|
||||
if (tmpret) {
|
||||
dev_err(dev, "Failed to set RTC time\n");
|
||||
goto renable_out;
|
||||
}
|
||||
|
||||
renable_out:
|
||||
ret = bd70528_re_enable_rtc_based_timers(r, old_states);
|
||||
if (tmpret)
|
||||
ret = tmpret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bd70528_set_time(struct device *dev, struct rtc_time *t)
|
||||
{
|
||||
int ret;
|
||||
struct bd70528_rtc *r = dev_get_drvdata(dev);
|
||||
|
||||
bd70528_wdt_lock(r->mfd);
|
||||
ret = bd70528_set_time_locked(dev, t);
|
||||
bd70528_wdt_unlock(r->mfd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bd70528_get_time(struct device *dev, struct rtc_time *t)
|
||||
{
|
||||
struct bd70528_rtc *r = dev_get_drvdata(dev);
|
||||
struct rohm_regmap_dev *bd70528 = r->mfd;
|
||||
struct bd70528_rtc_data rtc_data;
|
||||
int ret;
|
||||
|
||||
/* read the RTC date and time registers all at once */
|
||||
ret = regmap_bulk_read(bd70528->regmap,
|
||||
BD70528_REG_RTC_START, &rtc_data,
|
||||
sizeof(rtc_data));
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read RTC time (err %d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtc2tm(&rtc_data, t);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bd70528_alm_enable(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
int ret;
|
||||
unsigned int enableval = BD70528_MASK_ALM_EN;
|
||||
struct bd70528_rtc *r = dev_get_drvdata(dev);
|
||||
|
||||
if (enabled)
|
||||
enableval = 0;
|
||||
|
||||
bd70528_wdt_lock(r->mfd);
|
||||
ret = bd70528_set_wake(r->mfd, enabled, NULL);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to change wake state\n");
|
||||
goto out_unlock;
|
||||
}
|
||||
ret = regmap_update_bits(r->mfd->regmap, BD70528_REG_RTC_ALM_MASK,
|
||||
BD70528_MASK_ALM_EN, enableval);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to change alarm state\n");
|
||||
|
||||
out_unlock:
|
||||
bd70528_wdt_unlock(r->mfd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops bd70528_rtc_ops = {
|
||||
.read_time = bd70528_get_time,
|
||||
.set_time = bd70528_set_time,
|
||||
.read_alarm = bd70528_read_alarm,
|
||||
.set_alarm = bd70528_set_alarm,
|
||||
.alarm_irq_enable = bd70528_alm_enable,
|
||||
};
|
||||
|
||||
static irqreturn_t alm_hndlr(int irq, void *data)
|
||||
{
|
||||
struct rtc_device *rtc = data;
|
||||
|
||||
rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF | RTC_PF);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int bd70528_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bd70528_rtc *bd_rtc;
|
||||
struct rohm_regmap_dev *mfd;
|
||||
int ret;
|
||||
struct rtc_device *rtc;
|
||||
int irq;
|
||||
unsigned int hr;
|
||||
|
||||
mfd = dev_get_drvdata(pdev->dev.parent);
|
||||
if (!mfd) {
|
||||
dev_err(&pdev->dev, "No MFD driver data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
bd_rtc = devm_kzalloc(&pdev->dev, sizeof(*bd_rtc), GFP_KERNEL);
|
||||
if (!bd_rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
bd_rtc->mfd = mfd;
|
||||
bd_rtc->dev = &pdev->dev;
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "bd70528-rtc-alm");
|
||||
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get irq\n");
|
||||
return irq;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, bd_rtc);
|
||||
|
||||
ret = regmap_read(mfd->regmap, BD70528_REG_RTC_HOUR, &hr);
|
||||
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to reag RTC clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!(hr & BD70528_MASK_RTC_HOUR_24H)) {
|
||||
struct rtc_time t;
|
||||
|
||||
ret = bd70528_get_time(&pdev->dev, &t);
|
||||
|
||||
if (!ret)
|
||||
ret = bd70528_set_time(&pdev->dev, &t);
|
||||
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Setting 24H clock for RTC failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
device_set_wakeup_capable(&pdev->dev, true);
|
||||
device_wakeup_enable(&pdev->dev);
|
||||
|
||||
rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc)) {
|
||||
dev_err(&pdev->dev, "RTC device creation failed\n");
|
||||
return PTR_ERR(rtc);
|
||||
}
|
||||
|
||||
rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
rtc->ops = &bd70528_rtc_ops;
|
||||
|
||||
/* Request alarm IRQ prior to registerig the RTC */
|
||||
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, &alm_hndlr,
|
||||
IRQF_ONESHOT, "bd70528-rtc", rtc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* BD70528 irq controller is not touching the main mask register.
|
||||
* So enable the RTC block interrupts at main level. We can just
|
||||
* leave them enabled as irq-controller should disable irqs
|
||||
* from sub-registers when IRQ is disabled or freed.
|
||||
*/
|
||||
ret = regmap_update_bits(mfd->regmap,
|
||||
BD70528_REG_INT_MAIN_MASK,
|
||||
BD70528_INT_RTC_MASK, 0);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to enable RTC interrupts\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = rtc_register_device(rtc);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "Registering RTC failed\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct platform_driver bd70528_rtc = {
|
||||
.driver = {
|
||||
.name = "bd70528-rtc"
|
||||
},
|
||||
.probe = bd70528_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(bd70528_rtc);
|
||||
|
||||
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
|
||||
MODULE_DESCRIPTION("BD70528 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
@@ -42,9 +42,18 @@
|
||||
#define NUM_TIME_REGS (RK808_WEEKS_REG - RK808_SECONDS_REG + 1)
|
||||
#define NUM_ALARM_REGS (RK808_ALARM_YEARS_REG - RK808_ALARM_SECONDS_REG + 1)
|
||||
|
||||
struct rk_rtc_compat_reg {
|
||||
unsigned int ctrl_reg;
|
||||
unsigned int status_reg;
|
||||
unsigned int alarm_seconds_reg;
|
||||
unsigned int int_reg;
|
||||
unsigned int seconds_reg;
|
||||
};
|
||||
|
||||
struct rk808_rtc {
|
||||
struct rk808 *rk808;
|
||||
struct rtc_device *rtc;
|
||||
struct rk_rtc_compat_reg *creg;
|
||||
int irq;
|
||||
};
|
||||
|
||||
@@ -93,7 +102,7 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
|
||||
int ret;
|
||||
|
||||
/* Force an update of the shadowed registers right now */
|
||||
ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
|
||||
ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg,
|
||||
BIT_RTC_CTRL_REG_RTC_GET_TIME,
|
||||
BIT_RTC_CTRL_REG_RTC_GET_TIME);
|
||||
if (ret) {
|
||||
@@ -107,7 +116,7 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
|
||||
* 32khz. If we clear the GET_TIME bit here, the time of i2c transfer
|
||||
* certainly more than 31.25us: 16 * 2.5us at 400kHz bus frequency.
|
||||
*/
|
||||
ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
|
||||
ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg,
|
||||
BIT_RTC_CTRL_REG_RTC_GET_TIME,
|
||||
0);
|
||||
if (ret) {
|
||||
@@ -115,7 +124,7 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_bulk_read(rk808->regmap, RK808_SECONDS_REG,
|
||||
ret = regmap_bulk_read(rk808->regmap, rk808_rtc->creg->seconds_reg,
|
||||
rtc_data, NUM_TIME_REGS);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to bulk read rtc_data: %d\n", ret);
|
||||
@@ -154,7 +163,7 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
rtc_data[6] = bin2bcd(tm->tm_wday);
|
||||
|
||||
/* Stop RTC while updating the RTC registers */
|
||||
ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
|
||||
ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg,
|
||||
BIT_RTC_CTRL_REG_STOP_RTC_M,
|
||||
BIT_RTC_CTRL_REG_STOP_RTC_M);
|
||||
if (ret) {
|
||||
@@ -162,14 +171,14 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_bulk_write(rk808->regmap, RK808_SECONDS_REG,
|
||||
ret = regmap_bulk_write(rk808->regmap, rk808_rtc->creg->seconds_reg,
|
||||
rtc_data, NUM_TIME_REGS);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to bull write rtc_data: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
/* Start RTC again */
|
||||
ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
|
||||
ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg,
|
||||
BIT_RTC_CTRL_REG_STOP_RTC_M, 0);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to update RTC control: %d\n", ret);
|
||||
@@ -187,8 +196,13 @@ static int rk808_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
uint32_t int_reg;
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(rk808->regmap, RK808_ALARM_SECONDS_REG,
|
||||
ret = regmap_bulk_read(rk808->regmap,
|
||||
rk808_rtc->creg->alarm_seconds_reg,
|
||||
alrm_data, NUM_ALARM_REGS);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read RTC alarm date REG: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
alrm->time.tm_sec = bcd2bin(alrm_data[0] & SECONDS_REG_MSK);
|
||||
alrm->time.tm_min = bcd2bin(alrm_data[1] & MINUTES_REG_MAK);
|
||||
@@ -198,7 +212,7 @@ static int rk808_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
alrm->time.tm_year = (bcd2bin(alrm_data[5] & YEARS_REG_MSK)) + 100;
|
||||
rockchip_to_gregorian(&alrm->time);
|
||||
|
||||
ret = regmap_read(rk808->regmap, RK808_RTC_INT_REG, &int_reg);
|
||||
ret = regmap_read(rk808->regmap, rk808_rtc->creg->int_reg, &int_reg);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read RTC INT REG: %d\n", ret);
|
||||
return ret;
|
||||
@@ -217,7 +231,7 @@ static int rk808_rtc_stop_alarm(struct rk808_rtc *rk808_rtc)
|
||||
struct rk808 *rk808 = rk808_rtc->rk808;
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(rk808->regmap, RK808_RTC_INT_REG,
|
||||
ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->int_reg,
|
||||
BIT_RTC_INTERRUPTS_REG_IT_ALARM_M, 0);
|
||||
|
||||
return ret;
|
||||
@@ -228,7 +242,7 @@ static int rk808_rtc_start_alarm(struct rk808_rtc *rk808_rtc)
|
||||
struct rk808 *rk808 = rk808_rtc->rk808;
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(rk808->regmap, RK808_RTC_INT_REG,
|
||||
ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->int_reg,
|
||||
BIT_RTC_INTERRUPTS_REG_IT_ALARM_M,
|
||||
BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
|
||||
|
||||
@@ -258,7 +272,8 @@ static int rk808_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
alrm_data[4] = bin2bcd(alrm->time.tm_mon + 1);
|
||||
alrm_data[5] = bin2bcd(alrm->time.tm_year - 100);
|
||||
|
||||
ret = regmap_bulk_write(rk808->regmap, RK808_ALARM_SECONDS_REG,
|
||||
ret = regmap_bulk_write(rk808->regmap,
|
||||
rk808_rtc->creg->alarm_seconds_reg,
|
||||
alrm_data, NUM_ALARM_REGS);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to bulk write: %d\n", ret);
|
||||
@@ -302,7 +317,7 @@ static irqreturn_t rk808_alarm_irq(int irq, void *data)
|
||||
struct i2c_client *client = rk808->i2c;
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(rk808->regmap, RK808_RTC_STATUS_REG,
|
||||
ret = regmap_write(rk808->regmap, rk808_rtc->creg->status_reg,
|
||||
RTC_STATUS_MASK);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
@@ -353,6 +368,22 @@ static int rk808_rtc_resume(struct device *dev)
|
||||
static SIMPLE_DEV_PM_OPS(rk808_rtc_pm_ops,
|
||||
rk808_rtc_suspend, rk808_rtc_resume);
|
||||
|
||||
static struct rk_rtc_compat_reg rk808_creg = {
|
||||
.ctrl_reg = RK808_RTC_CTRL_REG,
|
||||
.status_reg = RK808_RTC_STATUS_REG,
|
||||
.alarm_seconds_reg = RK808_ALARM_SECONDS_REG,
|
||||
.int_reg = RK808_RTC_INT_REG,
|
||||
.seconds_reg = RK808_SECONDS_REG,
|
||||
};
|
||||
|
||||
static struct rk_rtc_compat_reg rk817_creg = {
|
||||
.ctrl_reg = RK817_RTC_CTRL_REG,
|
||||
.status_reg = RK817_RTC_STATUS_REG,
|
||||
.alarm_seconds_reg = RK817_ALARM_SECONDS_REG,
|
||||
.int_reg = RK817_RTC_INT_REG,
|
||||
.seconds_reg = RK817_SECONDS_REG,
|
||||
};
|
||||
|
||||
static int rk808_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
|
||||
@@ -363,11 +394,20 @@ static int rk808_rtc_probe(struct platform_device *pdev)
|
||||
if (rk808_rtc == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
switch (rk808->variant) {
|
||||
case RK809_ID:
|
||||
case RK817_ID:
|
||||
rk808_rtc->creg = &rk817_creg;
|
||||
break;
|
||||
default:
|
||||
rk808_rtc->creg = &rk808_creg;
|
||||
break;
|
||||
}
|
||||
platform_set_drvdata(pdev, rk808_rtc);
|
||||
rk808_rtc->rk808 = rk808;
|
||||
|
||||
/* start rtc running by default, and use shadowed timer. */
|
||||
ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
|
||||
ret = regmap_update_bits(rk808->regmap, rk808_rtc->creg->ctrl_reg,
|
||||
BIT_RTC_CTRL_REG_STOP_RTC_M |
|
||||
BIT_RTC_CTRL_REG_RTC_READSEL_M,
|
||||
BIT_RTC_CTRL_REG_RTC_READSEL_M);
|
||||
@@ -377,7 +417,7 @@ static int rk808_rtc_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_write(rk808->regmap, RK808_RTC_STATUS_REG,
|
||||
ret = regmap_write(rk808->regmap, rk808_rtc->creg->status_reg,
|
||||
RTC_STATUS_MASK);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
|
新增問題並參考
封鎖使用者