RTC for 4.19
Subsystem: - new helpers to add custom sysfs attributes - struct rtc_task removal along with rtc_irq_register/rtc_irq_unregister - rtc_irq_set_state and rtc_irq_set_freq are not exported anymore Drivers: - armada38x: reset after rtc power loss - ds1307: now supports m41t11 - isl1208: now supports isl1219 and tamper detection - pcf2127: internal SRAM support -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEXx9Viay1+e7J/aM4AyWl4gNJNJIFAlt7L0oACgkQAyWl4gNJ NJIB3w/+Mo5moMRnjDe+MiFzbLxe9lv3Wtdmqq0AdHQpxxOVu7LQ2O5oHQBjdMsz nCYPy7sIWBXzJWI+X5OByukZheWmhmsORtZw14MrmhMCY7Xt0lCHAsmHzs0yyqXT KnF0RL9HtSfYr4ftcOGrnY/8VZCPjI0I08AP1naVYTcX34PPGRL7KWwyxYBuwyOL Za2eH8snhI/QkEKx9enPsXeMvB87hkhCEFM0oTyyS5bY6L68PGzErWO4J8mWvFSH w1GWOvaNAg74lSe1Kgq9QtXRmhl67vwPLUX3QdxKb0HRuEInfdwDifdwU14HixE/ t2Vj0HNpn9xZwRhCvC/LnwtQGr+53R2Ase5NSwpZvpvM8e2LgoN/W7NxoD4BGSMi Aal0lPUFLbzayFQC5MOIZVazrf7PzWowSFNWO66uQR3Cmt/voGtRDGbfTPHn6nvs kLl5kb8j0KdJOsVeDDmnVmEU0ZEmGZSqxX7oE0QiL8QMim76yZtqwy1Y13xE5nI9 6fDA2MyQADNn5JDFMC/deL/d8hgI4Yv19tNOxNuj9yW/wFbctCG4tkremQoXHZ4n zLg/pdS2/iHSGKYW6ejWIS7VxwEWDbJp60Tx02LWQz40xXiUtgYh0/eYCzdfBVU/ wXla023DFerg1irguOrSPTLLDddvOz8fW6Gh7DMT+nxjuxdh+lw= =cAQ9 -----END PGP SIGNATURE----- Merge tag 'rtc-4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux Pull RTC updates from Alexandre Belloni: "It is now possible to add custom sysfs attributes while avoiding a possible race condition. Unused code has been removed resulting in a nice reduction of the code base. And more drivers have been switched to SPDX by their maintainers. Summary: Subsystem: - new helpers to add custom sysfs attributes - struct rtc_task removal along with rtc_irq_[un]register() - rtc_irq_set_state and rtc_irq_set_freq are not exported anymore Drivers: - armada38x: reset after rtc power loss - ds1307: now supports m41t11 - isl1208: now supports isl1219 and tamper detection - pcf2127: internal SRAM support" * tag 'rtc-4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (34 commits) rtc: ds1307: simplify hwmon config rtc: s5m: Add SPDX license identifier rtc: maxim: Add SPDX license identifiers rtc: isl1219: add device tree documentation rtc: isl1208: set ev-evienb bit from device tree rtc: isl1208: Add "evdet" interrupt source for isl1219 rtc: isl1208: add support for isl1219 with tamper detection rtc: sysfs: facilitate attribute add to rtc device rtc: remove struct rtc_task char: rtc: remove task handling rtc: pcf85063: preserve control register value between stop and start rtc: sh: remove unused variable rtc_dev rtc: unexport rtc_irq_set_* rtc: simplify rtc_irq_set_state/rtc_irq_set_freq rtc: remove irq_task and irq_task_lock rtc: remove rtc_irq_register/rtc_irq_unregister rtc: sh: remove dead code rtc: sa1100: don't set PIE frequency rtc: ds1307: support m41t11 variant rtc: ds1307: fix data pointer to m41t0 ...
This commit is contained in:
commit
bfebeb1672
28 changed files with 523 additions and 970 deletions
29
Documentation/devicetree/bindings/rtc/isil,isl1219.txt
Normal file
29
Documentation/devicetree/bindings/rtc/isil,isl1219.txt
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
Intersil ISL1219 I2C RTC/Alarm chip with event in
|
||||||
|
|
||||||
|
ISL1219 has additional pins EVIN and #EVDET for tamper detection.
|
||||||
|
|
||||||
|
Required properties supported by the device:
|
||||||
|
|
||||||
|
- "compatible": must be "isil,isl1219"
|
||||||
|
- "reg": I2C bus address of the device
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
|
||||||
|
- "interrupt-names": list which may contains "irq" and "evdet"
|
||||||
|
- "interrupts": list of interrupts for "irq" and "evdet"
|
||||||
|
- "isil,ev-evienb": if present EV.EVIENB bit is set to the specified
|
||||||
|
value for proper operation.
|
||||||
|
|
||||||
|
|
||||||
|
Example isl1219 node with #IRQ pin connected to SoC gpio1 pin12
|
||||||
|
and #EVDET pin connected to SoC gpio2 pin 24:
|
||||||
|
|
||||||
|
isl1219: rtc@68 {
|
||||||
|
compatible = "isil,isl1219";
|
||||||
|
reg = <0x68>;
|
||||||
|
interrupt-names = "irq", "evdet";
|
||||||
|
interrupts-extended = <&gpio1 12 IRQ_TYPE_EDGE_FALLING>,
|
||||||
|
<&gpio2 24 IRQ_TYPE_EDGE_FALLING>;
|
||||||
|
isil,ev-evienb = <1>;
|
||||||
|
};
|
||||||
|
|
|
@ -13,6 +13,7 @@ Required properties:
|
||||||
"maxim,ds3231",
|
"maxim,ds3231",
|
||||||
"st,m41t0",
|
"st,m41t0",
|
||||||
"st,m41t00",
|
"st,m41t00",
|
||||||
|
"st,m41t11",
|
||||||
"microchip,mcp7940x",
|
"microchip,mcp7940x",
|
||||||
"microchip,mcp7941x",
|
"microchip,mcp7941x",
|
||||||
"pericom,pt7c4338",
|
"pericom,pt7c4338",
|
||||||
|
|
|
@ -193,14 +193,6 @@ static unsigned long rtc_freq; /* Current periodic IRQ rate */
|
||||||
static unsigned long rtc_irq_data; /* our output to the world */
|
static unsigned long rtc_irq_data; /* our output to the world */
|
||||||
static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */
|
static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */
|
||||||
|
|
||||||
#ifdef RTC_IRQ
|
|
||||||
/*
|
|
||||||
* rtc_task_lock nests inside rtc_lock.
|
|
||||||
*/
|
|
||||||
static DEFINE_SPINLOCK(rtc_task_lock);
|
|
||||||
static rtc_task_t *rtc_callback;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this driver ever becomes modularised, it will be really nice
|
* If this driver ever becomes modularised, it will be really nice
|
||||||
* to make the epoch retain its value across module reload...
|
* to make the epoch retain its value across module reload...
|
||||||
|
@ -264,11 +256,6 @@ static irqreturn_t rtc_interrupt(int irq, void *dev_id)
|
||||||
|
|
||||||
spin_unlock(&rtc_lock);
|
spin_unlock(&rtc_lock);
|
||||||
|
|
||||||
/* Now do the rest of the actions */
|
|
||||||
spin_lock(&rtc_task_lock);
|
|
||||||
if (rtc_callback)
|
|
||||||
rtc_callback->func(rtc_callback->private_data);
|
|
||||||
spin_unlock(&rtc_task_lock);
|
|
||||||
wake_up_interruptible(&rtc_wait);
|
wake_up_interruptible(&rtc_wait);
|
||||||
|
|
||||||
kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
|
kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
|
||||||
|
|
|
@ -244,15 +244,6 @@ config RTC_DRV_DS1307
|
||||||
This driver can also be built as a module. If so, the module
|
This driver can also be built as a module. If so, the module
|
||||||
will be called rtc-ds1307.
|
will be called rtc-ds1307.
|
||||||
|
|
||||||
config RTC_DRV_DS1307_HWMON
|
|
||||||
bool "HWMON support for rtc-ds1307"
|
|
||||||
depends on RTC_DRV_DS1307 && HWMON
|
|
||||||
depends on !(RTC_DRV_DS1307=y && HWMON=m)
|
|
||||||
default y
|
|
||||||
help
|
|
||||||
Say Y here if you want to expose temperature sensor data on
|
|
||||||
rtc-ds1307 (only DS3231)
|
|
||||||
|
|
||||||
config RTC_DRV_DS1307_CENTURY
|
config RTC_DRV_DS1307_CENTURY
|
||||||
bool "Century bit support for rtc-ds1307"
|
bool "Century bit support for rtc-ds1307"
|
||||||
depends on RTC_DRV_DS1307
|
depends on RTC_DRV_DS1307
|
||||||
|
@ -1027,18 +1018,6 @@ config RTC_DS1685_PROC_REGS
|
||||||
|
|
||||||
Unless you are debugging this driver, choose N.
|
Unless you are debugging this driver, choose N.
|
||||||
|
|
||||||
config RTC_DS1685_SYSFS_REGS
|
|
||||||
bool "SysFS access to RTC register bits"
|
|
||||||
depends on RTC_DRV_DS1685_FAMILY && SYSFS
|
|
||||||
help
|
|
||||||
Enable this to provide access to the RTC control register bits
|
|
||||||
in /sys. Some of the bits are read-write, others are read-only.
|
|
||||||
|
|
||||||
Keep in mind that reading Control C's bits automatically clears
|
|
||||||
all pending IRQ flags - this can cause lost interrupts.
|
|
||||||
|
|
||||||
If you know that you need access to these bits, choose Y, Else N.
|
|
||||||
|
|
||||||
config RTC_DRV_DS1742
|
config RTC_DRV_DS1742
|
||||||
tristate "Maxim/Dallas DS1742/1743"
|
tristate "Maxim/Dallas DS1742/1743"
|
||||||
depends on HAS_IOMEM
|
depends on HAS_IOMEM
|
||||||
|
|
|
@ -68,7 +68,7 @@ static int rtc_suspend(struct device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
getnstimeofday64(&old_system);
|
ktime_get_real_ts64(&old_system);
|
||||||
old_rtc.tv_sec = rtc_tm_to_time64(&tm);
|
old_rtc.tv_sec = rtc_tm_to_time64(&tm);
|
||||||
|
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ static int rtc_resume(struct device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* snapshot the current rtc and system time at resume */
|
/* snapshot the current rtc and system time at resume */
|
||||||
getnstimeofday64(&new_system);
|
ktime_get_real_ts64(&new_system);
|
||||||
err = rtc_read_time(rtc, &tm);
|
err = rtc_read_time(rtc, &tm);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
pr_debug("%s: fail to read rtc time\n", dev_name(&rtc->dev));
|
pr_debug("%s: fail to read rtc time\n", dev_name(&rtc->dev));
|
||||||
|
@ -172,7 +172,6 @@ static struct rtc_device *rtc_allocate_device(void)
|
||||||
|
|
||||||
mutex_init(&rtc->ops_lock);
|
mutex_init(&rtc->ops_lock);
|
||||||
spin_lock_init(&rtc->irq_lock);
|
spin_lock_init(&rtc->irq_lock);
|
||||||
spin_lock_init(&rtc->irq_task_lock);
|
|
||||||
init_waitqueue_head(&rtc->irq_queue);
|
init_waitqueue_head(&rtc->irq_queue);
|
||||||
|
|
||||||
/* Init timerqueue */
|
/* Init timerqueue */
|
||||||
|
|
|
@ -607,12 +607,6 @@ void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode)
|
||||||
rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF|mode);
|
rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF|mode);
|
||||||
spin_unlock_irqrestore(&rtc->irq_lock, flags);
|
spin_unlock_irqrestore(&rtc->irq_lock, flags);
|
||||||
|
|
||||||
/* call the task func */
|
|
||||||
spin_lock_irqsave(&rtc->irq_task_lock, flags);
|
|
||||||
if (rtc->irq_task)
|
|
||||||
rtc->irq_task->func(rtc->irq_task->private_data);
|
|
||||||
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
|
|
||||||
|
|
||||||
wake_up_interruptible(&rtc->irq_queue);
|
wake_up_interruptible(&rtc->irq_queue);
|
||||||
kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
|
kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
|
||||||
}
|
}
|
||||||
|
@ -721,39 +715,6 @@ void rtc_class_close(struct rtc_device *rtc)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rtc_class_close);
|
EXPORT_SYMBOL_GPL(rtc_class_close);
|
||||||
|
|
||||||
int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task)
|
|
||||||
{
|
|
||||||
int retval = -EBUSY;
|
|
||||||
|
|
||||||
if (task == NULL || task->func == NULL)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Cannot register while the char dev is in use */
|
|
||||||
if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags))
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
spin_lock_irq(&rtc->irq_task_lock);
|
|
||||||
if (rtc->irq_task == NULL) {
|
|
||||||
rtc->irq_task = task;
|
|
||||||
retval = 0;
|
|
||||||
}
|
|
||||||
spin_unlock_irq(&rtc->irq_task_lock);
|
|
||||||
|
|
||||||
clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(rtc_irq_register);
|
|
||||||
|
|
||||||
void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task)
|
|
||||||
{
|
|
||||||
spin_lock_irq(&rtc->irq_task_lock);
|
|
||||||
if (rtc->irq_task == task)
|
|
||||||
rtc->irq_task = NULL;
|
|
||||||
spin_unlock_irq(&rtc->irq_task_lock);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(rtc_irq_unregister);
|
|
||||||
|
|
||||||
static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled)
|
static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -785,71 +746,45 @@ static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled)
|
||||||
* Context: any
|
* Context: any
|
||||||
*
|
*
|
||||||
* Note that rtc_irq_set_freq() should previously have been used to
|
* Note that rtc_irq_set_freq() should previously have been used to
|
||||||
* specify the desired frequency of periodic IRQ task->func() callbacks.
|
* specify the desired frequency of periodic IRQ.
|
||||||
*/
|
*/
|
||||||
int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled)
|
int rtc_irq_set_state(struct rtc_device *rtc, int enabled)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
retry:
|
while (rtc_update_hrtimer(rtc, enabled) < 0)
|
||||||
spin_lock_irqsave(&rtc->irq_task_lock, flags);
|
cpu_relax();
|
||||||
if (rtc->irq_task != NULL && task == NULL)
|
|
||||||
err = -EBUSY;
|
rtc->pie_enabled = enabled;
|
||||||
else if (rtc->irq_task != task)
|
|
||||||
err = -EACCES;
|
|
||||||
else {
|
|
||||||
if (rtc_update_hrtimer(rtc, enabled) < 0) {
|
|
||||||
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
|
|
||||||
cpu_relax();
|
|
||||||
goto retry;
|
|
||||||
}
|
|
||||||
rtc->pie_enabled = enabled;
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
|
|
||||||
|
|
||||||
trace_rtc_irq_set_state(enabled, err);
|
trace_rtc_irq_set_state(enabled, err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rtc_irq_set_state);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ
|
* rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ
|
||||||
* @rtc: the rtc device
|
* @rtc: the rtc device
|
||||||
* @task: currently registered with rtc_irq_register()
|
* @task: currently registered with rtc_irq_register()
|
||||||
* @freq: positive frequency with which task->func() will be called
|
* @freq: positive frequency
|
||||||
* Context: any
|
* Context: any
|
||||||
*
|
*
|
||||||
* Note that rtc_irq_set_state() is used to enable or disable the
|
* Note that rtc_irq_set_state() is used to enable or disable the
|
||||||
* periodic IRQs.
|
* periodic IRQs.
|
||||||
*/
|
*/
|
||||||
int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
|
int rtc_irq_set_freq(struct rtc_device *rtc, int freq)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (freq <= 0 || freq > RTC_MAX_FREQ)
|
if (freq <= 0 || freq > RTC_MAX_FREQ)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
retry:
|
|
||||||
spin_lock_irqsave(&rtc->irq_task_lock, flags);
|
rtc->irq_freq = freq;
|
||||||
if (rtc->irq_task != NULL && task == NULL)
|
while (rtc->pie_enabled && rtc_update_hrtimer(rtc, 1) < 0)
|
||||||
err = -EBUSY;
|
cpu_relax();
|
||||||
else if (rtc->irq_task != task)
|
|
||||||
err = -EACCES;
|
|
||||||
else {
|
|
||||||
rtc->irq_freq = freq;
|
|
||||||
if (rtc->pie_enabled && rtc_update_hrtimer(rtc, 1) < 0) {
|
|
||||||
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
|
|
||||||
cpu_relax();
|
|
||||||
goto retry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
|
|
||||||
|
|
||||||
trace_rtc_irq_set_freq(freq, err);
|
trace_rtc_irq_set_freq(freq, err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rtc_irq_set_freq);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rtc_timer_enqueue - Adds a rtc_timer to the rtc_device timerqueue
|
* rtc_timer_enqueue - Adds a rtc_timer to the rtc_device timerqueue
|
||||||
|
@ -979,8 +914,8 @@ void rtc_timer_do_work(struct work_struct *work)
|
||||||
timerqueue_del(&rtc->timerqueue, &timer->node);
|
timerqueue_del(&rtc->timerqueue, &timer->node);
|
||||||
trace_rtc_timer_dequeue(timer);
|
trace_rtc_timer_dequeue(timer);
|
||||||
timer->enabled = 0;
|
timer->enabled = 0;
|
||||||
if (timer->task.func)
|
if (timer->func)
|
||||||
timer->task.func(timer->task.private_data);
|
timer->func(timer->private_data);
|
||||||
|
|
||||||
trace_rtc_timer_fired(timer);
|
trace_rtc_timer_fired(timer);
|
||||||
/* Re-add/fwd periodic timers */
|
/* Re-add/fwd periodic timers */
|
||||||
|
@ -1035,8 +970,8 @@ void rtc_timer_init(struct rtc_timer *timer, void (*f)(void *p), void *data)
|
||||||
{
|
{
|
||||||
timerqueue_init(&timer->node);
|
timerqueue_init(&timer->node);
|
||||||
timer->enabled = 0;
|
timer->enabled = 0;
|
||||||
timer->task.func = f;
|
timer->func = f;
|
||||||
timer->task.private_data = data;
|
timer->private_data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* rtc_timer_start - Sets an rtc_timer to fire in the future
|
/* rtc_timer_start - Sets an rtc_timer to fire in the future
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
#define RTC_IRQ_FREQ_1HZ BIT(2)
|
#define RTC_IRQ_FREQ_1HZ BIT(2)
|
||||||
#define RTC_CCR 0x18
|
#define RTC_CCR 0x18
|
||||||
#define RTC_CCR_MODE BIT(15)
|
#define RTC_CCR_MODE BIT(15)
|
||||||
|
#define RTC_CONF_TEST 0x1C
|
||||||
|
#define RTC_NOMINAL_TIMING BIT(13)
|
||||||
|
|
||||||
#define RTC_TIME 0xC
|
#define RTC_TIME 0xC
|
||||||
#define RTC_ALARM1 0x10
|
#define RTC_ALARM1 0x10
|
||||||
|
@ -75,6 +77,7 @@ struct armada38x_rtc {
|
||||||
void __iomem *regs_soc;
|
void __iomem *regs_soc;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
int irq;
|
int irq;
|
||||||
|
bool initialized;
|
||||||
struct value_to_freq *val_to_freq;
|
struct value_to_freq *val_to_freq;
|
||||||
struct armada38x_rtc_data *data;
|
struct armada38x_rtc_data *data;
|
||||||
};
|
};
|
||||||
|
@ -226,6 +229,23 @@ static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void armada38x_rtc_reset(struct armada38x_rtc *rtc)
|
||||||
|
{
|
||||||
|
u32 reg;
|
||||||
|
|
||||||
|
reg = rtc->data->read_rtc_reg(rtc, RTC_CONF_TEST);
|
||||||
|
/* If bits [7:0] are non-zero, assume RTC was uninitialized */
|
||||||
|
if (reg & 0xff) {
|
||||||
|
rtc_delayed_write(0, rtc, RTC_CONF_TEST);
|
||||||
|
msleep(500); /* Oscillator startup time */
|
||||||
|
rtc_delayed_write(0, rtc, RTC_TIME);
|
||||||
|
rtc_delayed_write(SOC_RTC_ALARM1 | SOC_RTC_ALARM2, rtc,
|
||||||
|
RTC_STATUS);
|
||||||
|
rtc_delayed_write(RTC_NOMINAL_TIMING, rtc, RTC_CCR);
|
||||||
|
}
|
||||||
|
rtc->initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||||
{
|
{
|
||||||
struct armada38x_rtc *rtc = dev_get_drvdata(dev);
|
struct armada38x_rtc *rtc = dev_get_drvdata(dev);
|
||||||
|
@ -237,6 +257,9 @@ static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (!rtc->initialized)
|
||||||
|
armada38x_rtc_reset(rtc);
|
||||||
|
|
||||||
spin_lock_irqsave(&rtc->lock, flags);
|
spin_lock_irqsave(&rtc->lock, flags);
|
||||||
rtc_delayed_write(time, rtc, RTC_TIME);
|
rtc_delayed_write(time, rtc, RTC_TIME);
|
||||||
spin_unlock_irqrestore(&rtc->lock, flags);
|
spin_unlock_irqrestore(&rtc->lock, flags);
|
||||||
|
|
|
@ -162,6 +162,10 @@ static int bq4802_probe(struct platform_device *pdev)
|
||||||
} else if (p->r->flags & IORESOURCE_MEM) {
|
} else if (p->r->flags & IORESOURCE_MEM) {
|
||||||
p->regs = devm_ioremap(&pdev->dev, p->r->start,
|
p->regs = devm_ioremap(&pdev->dev, p->r->start,
|
||||||
resource_size(p->r));
|
resource_size(p->r));
|
||||||
|
if (!p->regs){
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
p->read = bq4802_read_mem;
|
p->read = bq4802_read_mem;
|
||||||
p->write = bq4802_write_mem;
|
p->write = bq4802_write_mem;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -40,9 +40,23 @@ static inline void rtc_proc_del_device(struct rtc_device *rtc)
|
||||||
|
|
||||||
#ifdef CONFIG_RTC_INTF_SYSFS
|
#ifdef CONFIG_RTC_INTF_SYSFS
|
||||||
const struct attribute_group **rtc_get_dev_attribute_groups(void);
|
const struct attribute_group **rtc_get_dev_attribute_groups(void);
|
||||||
|
int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp);
|
||||||
|
int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps);
|
||||||
#else
|
#else
|
||||||
static inline const struct attribute_group **rtc_get_dev_attribute_groups(void)
|
static inline const struct attribute_group **rtc_get_dev_attribute_groups(void)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -341,11 +341,11 @@ static long rtc_dev_ioctl(struct file *file,
|
||||||
return rtc_set_time(rtc, &tm);
|
return rtc_set_time(rtc, &tm);
|
||||||
|
|
||||||
case RTC_PIE_ON:
|
case RTC_PIE_ON:
|
||||||
err = rtc_irq_set_state(rtc, NULL, 1);
|
err = rtc_irq_set_state(rtc, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTC_PIE_OFF:
|
case RTC_PIE_OFF:
|
||||||
err = rtc_irq_set_state(rtc, NULL, 0);
|
err = rtc_irq_set_state(rtc, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTC_AIE_ON:
|
case RTC_AIE_ON:
|
||||||
|
@ -365,7 +365,7 @@ static long rtc_dev_ioctl(struct file *file,
|
||||||
return rtc_update_irq_enable(rtc, 0);
|
return rtc_update_irq_enable(rtc, 0);
|
||||||
|
|
||||||
case RTC_IRQP_SET:
|
case RTC_IRQP_SET:
|
||||||
err = rtc_irq_set_freq(rtc, NULL, arg);
|
err = rtc_irq_set_freq(rtc, arg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTC_IRQP_READ:
|
case RTC_IRQP_READ:
|
||||||
|
@ -427,7 +427,7 @@ static int rtc_dev_release(struct inode *inode, struct file *file)
|
||||||
/* Keep ioctl until all drivers are converted */
|
/* Keep ioctl until all drivers are converted */
|
||||||
rtc_dev_ioctl(file, RTC_UIE_OFF, 0);
|
rtc_dev_ioctl(file, RTC_UIE_OFF, 0);
|
||||||
rtc_update_irq_enable(rtc, 0);
|
rtc_update_irq_enable(rtc, 0);
|
||||||
rtc_irq_set_state(rtc, NULL, 0);
|
rtc_irq_set_state(rtc, 0);
|
||||||
|
|
||||||
clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
|
clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -44,6 +44,7 @@ enum ds_type {
|
||||||
ds_3231,
|
ds_3231,
|
||||||
m41t0,
|
m41t0,
|
||||||
m41t00,
|
m41t00,
|
||||||
|
m41t11,
|
||||||
mcp794xx,
|
mcp794xx,
|
||||||
rx_8025,
|
rx_8025,
|
||||||
rx_8130,
|
rx_8130,
|
||||||
|
@ -227,6 +228,11 @@ static const struct chip_desc chips[last_ds_type] = {
|
||||||
.irq_handler = rx8130_irq,
|
.irq_handler = rx8130_irq,
|
||||||
.rtc_ops = &rx8130_rtc_ops,
|
.rtc_ops = &rx8130_rtc_ops,
|
||||||
},
|
},
|
||||||
|
[m41t11] = {
|
||||||
|
/* this is battery backed SRAM */
|
||||||
|
.nvram_offset = 8,
|
||||||
|
.nvram_size = 56,
|
||||||
|
},
|
||||||
[mcp794xx] = {
|
[mcp794xx] = {
|
||||||
.alarm = 1,
|
.alarm = 1,
|
||||||
/* this is battery backed SRAM */
|
/* this is battery backed SRAM */
|
||||||
|
@ -249,6 +255,7 @@ static const struct i2c_device_id ds1307_id[] = {
|
||||||
{ "ds3231", ds_3231 },
|
{ "ds3231", ds_3231 },
|
||||||
{ "m41t0", m41t0 },
|
{ "m41t0", m41t0 },
|
||||||
{ "m41t00", m41t00 },
|
{ "m41t00", m41t00 },
|
||||||
|
{ "m41t11", m41t11 },
|
||||||
{ "mcp7940x", mcp794xx },
|
{ "mcp7940x", mcp794xx },
|
||||||
{ "mcp7941x", mcp794xx },
|
{ "mcp7941x", mcp794xx },
|
||||||
{ "pt7c4338", ds_1307 },
|
{ "pt7c4338", ds_1307 },
|
||||||
|
@ -299,12 +306,16 @@ static const struct of_device_id ds1307_of_match[] = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.compatible = "st,m41t0",
|
.compatible = "st,m41t0",
|
||||||
.data = (void *)m41t00
|
.data = (void *)m41t0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.compatible = "st,m41t00",
|
.compatible = "st,m41t00",
|
||||||
.data = (void *)m41t00
|
.data = (void *)m41t00
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.compatible = "st,m41t11",
|
||||||
|
.data = (void *)m41t11
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.compatible = "microchip,mcp7940x",
|
.compatible = "microchip,mcp7940x",
|
||||||
.data = (void *)mcp794xx
|
.data = (void *)mcp794xx
|
||||||
|
@ -347,6 +358,7 @@ static const struct acpi_device_id ds1307_acpi_ids[] = {
|
||||||
{ .id = "DS3231", .driver_data = ds_3231 },
|
{ .id = "DS3231", .driver_data = ds_3231 },
|
||||||
{ .id = "M41T0", .driver_data = m41t0 },
|
{ .id = "M41T0", .driver_data = m41t0 },
|
||||||
{ .id = "M41T00", .driver_data = m41t00 },
|
{ .id = "M41T00", .driver_data = m41t00 },
|
||||||
|
{ .id = "M41T11", .driver_data = m41t11 },
|
||||||
{ .id = "MCP7940X", .driver_data = mcp794xx },
|
{ .id = "MCP7940X", .driver_data = mcp794xx },
|
||||||
{ .id = "MCP7941X", .driver_data = mcp794xx },
|
{ .id = "MCP7941X", .driver_data = mcp794xx },
|
||||||
{ .id = "PT7C4338", .driver_data = ds_1307 },
|
{ .id = "PT7C4338", .driver_data = ds_1307 },
|
||||||
|
@ -1030,7 +1042,7 @@ static u8 ds1307_trickle_init(struct ds1307 *ds1307,
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
|
|
||||||
#ifdef CONFIG_RTC_DRV_DS1307_HWMON
|
#if IS_REACHABLE(CONFIG_HWMON)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Temperature sensor support for ds3231 devices.
|
* Temperature sensor support for ds3231 devices.
|
||||||
|
@ -1576,6 +1588,7 @@ static int ds1307_probe(struct i2c_client *client,
|
||||||
case ds_1307:
|
case ds_1307:
|
||||||
case m41t0:
|
case m41t0:
|
||||||
case m41t00:
|
case m41t00:
|
||||||
|
case m41t11:
|
||||||
/* clock halted? turn it on, so clock can tick. */
|
/* clock halted? turn it on, so clock can tick. */
|
||||||
if (tmp & DS1307_BIT_CH) {
|
if (tmp & DS1307_BIT_CH) {
|
||||||
regmap_write(ds1307->regmap, DS1307_REG_SECS, 0);
|
regmap_write(ds1307->regmap, DS1307_REG_SECS, 0);
|
||||||
|
@ -1641,6 +1654,7 @@ static int ds1307_probe(struct i2c_client *client,
|
||||||
case ds_1340:
|
case ds_1340:
|
||||||
case m41t0:
|
case m41t0:
|
||||||
case m41t00:
|
case m41t00:
|
||||||
|
case m41t11:
|
||||||
/*
|
/*
|
||||||
* NOTE: ignores century bits; fix before deploying
|
* NOTE: ignores century bits; fix before deploying
|
||||||
* systems that will run through year 2100.
|
* systems that will run through year 2100.
|
||||||
|
|
|
@ -1188,552 +1188,6 @@ ds1685_rtc_sysfs_misc_grp = {
|
||||||
.attrs = ds1685_rtc_sysfs_misc_attrs,
|
.attrs = ds1685_rtc_sysfs_misc_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_RTC_DS1685_SYSFS_REGS
|
|
||||||
/**
|
|
||||||
* struct ds1685_rtc_ctrl_regs.
|
|
||||||
* @name: char pointer for the bit name.
|
|
||||||
* @reg: control register the bit is in.
|
|
||||||
* @bit: the bit's offset in the register.
|
|
||||||
*/
|
|
||||||
struct ds1685_rtc_ctrl_regs {
|
|
||||||
const char *name;
|
|
||||||
const u8 reg;
|
|
||||||
const u8 bit;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Ctrl register bit lookup table.
|
|
||||||
*/
|
|
||||||
static const struct ds1685_rtc_ctrl_regs
|
|
||||||
ds1685_ctrl_regs_table[] = {
|
|
||||||
{ "uip", RTC_CTRL_A, RTC_CTRL_A_UIP },
|
|
||||||
{ "dv2", RTC_CTRL_A, RTC_CTRL_A_DV2 },
|
|
||||||
{ "dv1", RTC_CTRL_A, RTC_CTRL_A_DV1 },
|
|
||||||
{ "dv0", RTC_CTRL_A, RTC_CTRL_A_DV0 },
|
|
||||||
{ "rs3", RTC_CTRL_A, RTC_CTRL_A_RS3 },
|
|
||||||
{ "rs2", RTC_CTRL_A, RTC_CTRL_A_RS2 },
|
|
||||||
{ "rs1", RTC_CTRL_A, RTC_CTRL_A_RS1 },
|
|
||||||
{ "rs0", RTC_CTRL_A, RTC_CTRL_A_RS0 },
|
|
||||||
{ "set", RTC_CTRL_B, RTC_CTRL_B_SET },
|
|
||||||
{ "pie", RTC_CTRL_B, RTC_CTRL_B_PIE },
|
|
||||||
{ "aie", RTC_CTRL_B, RTC_CTRL_B_AIE },
|
|
||||||
{ "uie", RTC_CTRL_B, RTC_CTRL_B_UIE },
|
|
||||||
{ "sqwe", RTC_CTRL_B, RTC_CTRL_B_SQWE },
|
|
||||||
{ "dm", RTC_CTRL_B, RTC_CTRL_B_DM },
|
|
||||||
{ "2412", RTC_CTRL_B, RTC_CTRL_B_2412 },
|
|
||||||
{ "dse", RTC_CTRL_B, RTC_CTRL_B_DSE },
|
|
||||||
{ "irqf", RTC_CTRL_C, RTC_CTRL_C_IRQF },
|
|
||||||
{ "pf", RTC_CTRL_C, RTC_CTRL_C_PF },
|
|
||||||
{ "af", RTC_CTRL_C, RTC_CTRL_C_AF },
|
|
||||||
{ "uf", RTC_CTRL_C, RTC_CTRL_C_UF },
|
|
||||||
{ "vrt", RTC_CTRL_D, RTC_CTRL_D_VRT },
|
|
||||||
{ "vrt2", RTC_EXT_CTRL_4A, RTC_CTRL_4A_VRT2 },
|
|
||||||
{ "incr", RTC_EXT_CTRL_4A, RTC_CTRL_4A_INCR },
|
|
||||||
{ "pab", RTC_EXT_CTRL_4A, RTC_CTRL_4A_PAB },
|
|
||||||
{ "rf", RTC_EXT_CTRL_4A, RTC_CTRL_4A_RF },
|
|
||||||
{ "wf", RTC_EXT_CTRL_4A, RTC_CTRL_4A_WF },
|
|
||||||
{ "kf", RTC_EXT_CTRL_4A, RTC_CTRL_4A_KF },
|
|
||||||
#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689)
|
|
||||||
{ "bme", RTC_EXT_CTRL_4A, RTC_CTRL_4A_BME },
|
|
||||||
#endif
|
|
||||||
{ "abe", RTC_EXT_CTRL_4B, RTC_CTRL_4B_ABE },
|
|
||||||
{ "e32k", RTC_EXT_CTRL_4B, RTC_CTRL_4B_E32K },
|
|
||||||
{ "cs", RTC_EXT_CTRL_4B, RTC_CTRL_4B_CS },
|
|
||||||
{ "rce", RTC_EXT_CTRL_4B, RTC_CTRL_4B_RCE },
|
|
||||||
{ "prs", RTC_EXT_CTRL_4B, RTC_CTRL_4B_PRS },
|
|
||||||
{ "rie", RTC_EXT_CTRL_4B, RTC_CTRL_4B_RIE },
|
|
||||||
{ "wie", RTC_EXT_CTRL_4B, RTC_CTRL_4B_WIE },
|
|
||||||
{ "kse", RTC_EXT_CTRL_4B, RTC_CTRL_4B_KSE },
|
|
||||||
{ NULL, 0, 0 },
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ds1685_rtc_sysfs_ctrl_regs_lookup - ctrl register bit lookup function.
|
|
||||||
* @name: ctrl register bit to look up in ds1685_ctrl_regs_table.
|
|
||||||
*/
|
|
||||||
static const struct ds1685_rtc_ctrl_regs*
|
|
||||||
ds1685_rtc_sysfs_ctrl_regs_lookup(const char *name)
|
|
||||||
{
|
|
||||||
const struct ds1685_rtc_ctrl_regs *p = ds1685_ctrl_regs_table;
|
|
||||||
|
|
||||||
for (; p->name != NULL; ++p)
|
|
||||||
if (strcmp(p->name, name) == 0)
|
|
||||||
return p;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ds1685_rtc_sysfs_ctrl_regs_show - reads a ctrl register bit via sysfs.
|
|
||||||
* @dev: pointer to device structure.
|
|
||||||
* @attr: pointer to device_attribute structure.
|
|
||||||
* @buf: pointer to char array to hold the output.
|
|
||||||
*/
|
|
||||||
static ssize_t
|
|
||||||
ds1685_rtc_sysfs_ctrl_regs_show(struct device *dev,
|
|
||||||
struct device_attribute *attr, char *buf)
|
|
||||||
{
|
|
||||||
u8 tmp;
|
|
||||||
struct ds1685_priv *rtc = dev_get_drvdata(dev);
|
|
||||||
const struct ds1685_rtc_ctrl_regs *reg_info =
|
|
||||||
ds1685_rtc_sysfs_ctrl_regs_lookup(attr->attr.name);
|
|
||||||
|
|
||||||
/* Make sure we actually matched something. */
|
|
||||||
if (!reg_info)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* No spinlock during a read -- mutex is already held. */
|
|
||||||
ds1685_rtc_switch_to_bank1(rtc);
|
|
||||||
tmp = rtc->read(rtc, reg_info->reg) & reg_info->bit;
|
|
||||||
ds1685_rtc_switch_to_bank0(rtc);
|
|
||||||
|
|
||||||
return sprintf(buf, "%d\n", (tmp ? 1 : 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ds1685_rtc_sysfs_ctrl_regs_store - writes a ctrl register bit via sysfs.
|
|
||||||
* @dev: pointer to device structure.
|
|
||||||
* @attr: pointer to device_attribute structure.
|
|
||||||
* @buf: pointer to char array to hold the output.
|
|
||||||
* @count: number of bytes written.
|
|
||||||
*/
|
|
||||||
static ssize_t
|
|
||||||
ds1685_rtc_sysfs_ctrl_regs_store(struct device *dev,
|
|
||||||
struct device_attribute *attr,
|
|
||||||
const char *buf, size_t count)
|
|
||||||
{
|
|
||||||
struct ds1685_priv *rtc = dev_get_drvdata(dev);
|
|
||||||
u8 reg = 0, bit = 0, tmp;
|
|
||||||
unsigned long flags;
|
|
||||||
long int val = 0;
|
|
||||||
const struct ds1685_rtc_ctrl_regs *reg_info =
|
|
||||||
ds1685_rtc_sysfs_ctrl_regs_lookup(attr->attr.name);
|
|
||||||
|
|
||||||
/* We only accept numbers. */
|
|
||||||
if (kstrtol(buf, 10, &val) < 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* bits are binary, 0 or 1 only. */
|
|
||||||
if ((val != 0) && (val != 1))
|
|
||||||
return -ERANGE;
|
|
||||||
|
|
||||||
/* Make sure we actually matched something. */
|
|
||||||
if (!reg_info)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
reg = reg_info->reg;
|
|
||||||
bit = reg_info->bit;
|
|
||||||
|
|
||||||
/* Safe to spinlock during a write. */
|
|
||||||
ds1685_rtc_begin_ctrl_access(rtc, &flags);
|
|
||||||
tmp = rtc->read(rtc, reg);
|
|
||||||
rtc->write(rtc, reg, (val ? (tmp | bit) : (tmp & ~(bit))));
|
|
||||||
ds1685_rtc_end_ctrl_access(rtc, flags);
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DS1685_RTC_SYSFS_CTRL_REG_RO - device_attribute for read-only register bit.
|
|
||||||
* @bit: bit to read.
|
|
||||||
*/
|
|
||||||
#define DS1685_RTC_SYSFS_CTRL_REG_RO(bit) \
|
|
||||||
static DEVICE_ATTR(bit, S_IRUGO, \
|
|
||||||
ds1685_rtc_sysfs_ctrl_regs_show, NULL)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DS1685_RTC_SYSFS_CTRL_REG_RW - device_attribute for read-write register bit.
|
|
||||||
* @bit: bit to read or write.
|
|
||||||
*/
|
|
||||||
#define DS1685_RTC_SYSFS_CTRL_REG_RW(bit) \
|
|
||||||
static DEVICE_ATTR(bit, S_IRUGO | S_IWUSR, \
|
|
||||||
ds1685_rtc_sysfs_ctrl_regs_show, \
|
|
||||||
ds1685_rtc_sysfs_ctrl_regs_store)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Control Register A bits.
|
|
||||||
*/
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RO(uip);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(dv2);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(dv1);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RO(dv0);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(rs3);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(rs2);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(rs1);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(rs0);
|
|
||||||
|
|
||||||
static struct attribute*
|
|
||||||
ds1685_rtc_sysfs_ctrla_attrs[] = {
|
|
||||||
&dev_attr_uip.attr,
|
|
||||||
&dev_attr_dv2.attr,
|
|
||||||
&dev_attr_dv1.attr,
|
|
||||||
&dev_attr_dv0.attr,
|
|
||||||
&dev_attr_rs3.attr,
|
|
||||||
&dev_attr_rs2.attr,
|
|
||||||
&dev_attr_rs1.attr,
|
|
||||||
&dev_attr_rs0.attr,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct attribute_group
|
|
||||||
ds1685_rtc_sysfs_ctrla_grp = {
|
|
||||||
.name = "ctrla",
|
|
||||||
.attrs = ds1685_rtc_sysfs_ctrla_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Control Register B bits.
|
|
||||||
*/
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RO(set);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(pie);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(aie);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(uie);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(sqwe);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RO(dm);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RO(2412);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RO(dse);
|
|
||||||
|
|
||||||
static struct attribute*
|
|
||||||
ds1685_rtc_sysfs_ctrlb_attrs[] = {
|
|
||||||
&dev_attr_set.attr,
|
|
||||||
&dev_attr_pie.attr,
|
|
||||||
&dev_attr_aie.attr,
|
|
||||||
&dev_attr_uie.attr,
|
|
||||||
&dev_attr_sqwe.attr,
|
|
||||||
&dev_attr_dm.attr,
|
|
||||||
&dev_attr_2412.attr,
|
|
||||||
&dev_attr_dse.attr,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct attribute_group
|
|
||||||
ds1685_rtc_sysfs_ctrlb_grp = {
|
|
||||||
.name = "ctrlb",
|
|
||||||
.attrs = ds1685_rtc_sysfs_ctrlb_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Control Register C bits.
|
|
||||||
*
|
|
||||||
* Reading Control C clears these bits! Reading them individually can
|
|
||||||
* possibly cause an interrupt to be missed. Use the /proc interface
|
|
||||||
* to see all the bits in this register simultaneously.
|
|
||||||
*/
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RO(irqf);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RO(pf);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RO(af);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RO(uf);
|
|
||||||
|
|
||||||
static struct attribute*
|
|
||||||
ds1685_rtc_sysfs_ctrlc_attrs[] = {
|
|
||||||
&dev_attr_irqf.attr,
|
|
||||||
&dev_attr_pf.attr,
|
|
||||||
&dev_attr_af.attr,
|
|
||||||
&dev_attr_uf.attr,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct attribute_group
|
|
||||||
ds1685_rtc_sysfs_ctrlc_grp = {
|
|
||||||
.name = "ctrlc",
|
|
||||||
.attrs = ds1685_rtc_sysfs_ctrlc_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Control Register D bits.
|
|
||||||
*/
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RO(vrt);
|
|
||||||
|
|
||||||
static struct attribute*
|
|
||||||
ds1685_rtc_sysfs_ctrld_attrs[] = {
|
|
||||||
&dev_attr_vrt.attr,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct attribute_group
|
|
||||||
ds1685_rtc_sysfs_ctrld_grp = {
|
|
||||||
.name = "ctrld",
|
|
||||||
.attrs = ds1685_rtc_sysfs_ctrld_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Control Register 4A bits.
|
|
||||||
*/
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RO(vrt2);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RO(incr);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(pab);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(rf);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(wf);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(kf);
|
|
||||||
#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689)
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RO(bme);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static struct attribute*
|
|
||||||
ds1685_rtc_sysfs_ctrl4a_attrs[] = {
|
|
||||||
&dev_attr_vrt2.attr,
|
|
||||||
&dev_attr_incr.attr,
|
|
||||||
&dev_attr_pab.attr,
|
|
||||||
&dev_attr_rf.attr,
|
|
||||||
&dev_attr_wf.attr,
|
|
||||||
&dev_attr_kf.attr,
|
|
||||||
#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689)
|
|
||||||
&dev_attr_bme.attr,
|
|
||||||
#endif
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct attribute_group
|
|
||||||
ds1685_rtc_sysfs_ctrl4a_grp = {
|
|
||||||
.name = "ctrl4a",
|
|
||||||
.attrs = ds1685_rtc_sysfs_ctrl4a_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Control Register 4B bits.
|
|
||||||
*/
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(abe);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(e32k);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RO(cs);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(rce);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(prs);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(rie);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(wie);
|
|
||||||
DS1685_RTC_SYSFS_CTRL_REG_RW(kse);
|
|
||||||
|
|
||||||
static struct attribute*
|
|
||||||
ds1685_rtc_sysfs_ctrl4b_attrs[] = {
|
|
||||||
&dev_attr_abe.attr,
|
|
||||||
&dev_attr_e32k.attr,
|
|
||||||
&dev_attr_cs.attr,
|
|
||||||
&dev_attr_rce.attr,
|
|
||||||
&dev_attr_prs.attr,
|
|
||||||
&dev_attr_rie.attr,
|
|
||||||
&dev_attr_wie.attr,
|
|
||||||
&dev_attr_kse.attr,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct attribute_group
|
|
||||||
ds1685_rtc_sysfs_ctrl4b_grp = {
|
|
||||||
.name = "ctrl4b",
|
|
||||||
.attrs = ds1685_rtc_sysfs_ctrl4b_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* struct ds1685_rtc_ctrl_regs.
|
|
||||||
* @name: char pointer for the bit name.
|
|
||||||
* @reg: control register the bit is in.
|
|
||||||
* @bit: the bit's offset in the register.
|
|
||||||
*/
|
|
||||||
struct ds1685_rtc_time_regs {
|
|
||||||
const char *name;
|
|
||||||
const u8 reg;
|
|
||||||
const u8 mask;
|
|
||||||
const u8 min;
|
|
||||||
const u8 max;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Time/Date register lookup tables.
|
|
||||||
*/
|
|
||||||
static const struct ds1685_rtc_time_regs
|
|
||||||
ds1685_time_regs_bcd_table[] = {
|
|
||||||
{ "seconds", RTC_SECS, RTC_SECS_BCD_MASK, 0, 59 },
|
|
||||||
{ "minutes", RTC_MINS, RTC_MINS_BCD_MASK, 0, 59 },
|
|
||||||
{ "hours", RTC_HRS, RTC_HRS_24_BCD_MASK, 0, 23 },
|
|
||||||
{ "wday", RTC_WDAY, RTC_WDAY_MASK, 1, 7 },
|
|
||||||
{ "mday", RTC_MDAY, RTC_MDAY_BCD_MASK, 1, 31 },
|
|
||||||
{ "month", RTC_MONTH, RTC_MONTH_BCD_MASK, 1, 12 },
|
|
||||||
{ "year", RTC_YEAR, RTC_YEAR_BCD_MASK, 0, 99 },
|
|
||||||
{ "century", RTC_CENTURY, RTC_CENTURY_MASK, 0, 99 },
|
|
||||||
{ "alarm_seconds", RTC_SECS_ALARM, RTC_SECS_BCD_MASK, 0, 59 },
|
|
||||||
{ "alarm_minutes", RTC_MINS_ALARM, RTC_MINS_BCD_MASK, 0, 59 },
|
|
||||||
{ "alarm_hours", RTC_HRS_ALARM, RTC_HRS_24_BCD_MASK, 0, 23 },
|
|
||||||
{ "alarm_mday", RTC_MDAY_ALARM, RTC_MDAY_ALARM_MASK, 1, 31 },
|
|
||||||
{ NULL, 0, 0, 0, 0 },
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct ds1685_rtc_time_regs
|
|
||||||
ds1685_time_regs_bin_table[] = {
|
|
||||||
{ "seconds", RTC_SECS, RTC_SECS_BIN_MASK, 0x00, 0x3b },
|
|
||||||
{ "minutes", RTC_MINS, RTC_MINS_BIN_MASK, 0x00, 0x3b },
|
|
||||||
{ "hours", RTC_HRS, RTC_HRS_24_BIN_MASK, 0x00, 0x17 },
|
|
||||||
{ "wday", RTC_WDAY, RTC_WDAY_MASK, 0x01, 0x07 },
|
|
||||||
{ "mday", RTC_MDAY, RTC_MDAY_BIN_MASK, 0x01, 0x1f },
|
|
||||||
{ "month", RTC_MONTH, RTC_MONTH_BIN_MASK, 0x01, 0x0c },
|
|
||||||
{ "year", RTC_YEAR, RTC_YEAR_BIN_MASK, 0x00, 0x63 },
|
|
||||||
{ "century", RTC_CENTURY, RTC_CENTURY_MASK, 0x00, 0x63 },
|
|
||||||
{ "alarm_seconds", RTC_SECS_ALARM, RTC_SECS_BIN_MASK, 0x00, 0x3b },
|
|
||||||
{ "alarm_minutes", RTC_MINS_ALARM, RTC_MINS_BIN_MASK, 0x00, 0x3b },
|
|
||||||
{ "alarm_hours", RTC_HRS_ALARM, RTC_HRS_24_BIN_MASK, 0x00, 0x17 },
|
|
||||||
{ "alarm_mday", RTC_MDAY_ALARM, RTC_MDAY_ALARM_MASK, 0x01, 0x1f },
|
|
||||||
{ NULL, 0, 0, 0x00, 0x00 },
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ds1685_rtc_sysfs_time_regs_bcd_lookup - time/date reg bit lookup function.
|
|
||||||
* @name: register bit to look up in ds1685_time_regs_bcd_table.
|
|
||||||
*/
|
|
||||||
static const struct ds1685_rtc_time_regs*
|
|
||||||
ds1685_rtc_sysfs_time_regs_lookup(const char *name, bool bcd_mode)
|
|
||||||
{
|
|
||||||
const struct ds1685_rtc_time_regs *p;
|
|
||||||
|
|
||||||
if (bcd_mode)
|
|
||||||
p = ds1685_time_regs_bcd_table;
|
|
||||||
else
|
|
||||||
p = ds1685_time_regs_bin_table;
|
|
||||||
|
|
||||||
for (; p->name != NULL; ++p)
|
|
||||||
if (strcmp(p->name, name) == 0)
|
|
||||||
return p;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ds1685_rtc_sysfs_time_regs_show - reads a time/date register via sysfs.
|
|
||||||
* @dev: pointer to device structure.
|
|
||||||
* @attr: pointer to device_attribute structure.
|
|
||||||
* @buf: pointer to char array to hold the output.
|
|
||||||
*/
|
|
||||||
static ssize_t
|
|
||||||
ds1685_rtc_sysfs_time_regs_show(struct device *dev,
|
|
||||||
struct device_attribute *attr, char *buf)
|
|
||||||
{
|
|
||||||
u8 tmp;
|
|
||||||
struct ds1685_priv *rtc = dev_get_drvdata(dev);
|
|
||||||
const struct ds1685_rtc_time_regs *bcd_reg_info =
|
|
||||||
ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, true);
|
|
||||||
const struct ds1685_rtc_time_regs *bin_reg_info =
|
|
||||||
ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, false);
|
|
||||||
|
|
||||||
/* Make sure we actually matched something. */
|
|
||||||
if (!bcd_reg_info || !bin_reg_info)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* bcd_reg_info->reg == bin_reg_info->reg. */
|
|
||||||
ds1685_rtc_begin_data_access(rtc);
|
|
||||||
tmp = rtc->read(rtc, bcd_reg_info->reg);
|
|
||||||
ds1685_rtc_end_data_access(rtc);
|
|
||||||
|
|
||||||
tmp = ds1685_rtc_bcd2bin(rtc, tmp, bcd_reg_info->mask,
|
|
||||||
bin_reg_info->mask);
|
|
||||||
|
|
||||||
return sprintf(buf, "%d\n", tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ds1685_rtc_sysfs_time_regs_store - writes a time/date register via sysfs.
|
|
||||||
* @dev: pointer to device structure.
|
|
||||||
* @attr: pointer to device_attribute structure.
|
|
||||||
* @buf: pointer to char array to hold the output.
|
|
||||||
* @count: number of bytes written.
|
|
||||||
*/
|
|
||||||
static ssize_t
|
|
||||||
ds1685_rtc_sysfs_time_regs_store(struct device *dev,
|
|
||||||
struct device_attribute *attr,
|
|
||||||
const char *buf, size_t count)
|
|
||||||
{
|
|
||||||
long int val = 0;
|
|
||||||
struct ds1685_priv *rtc = dev_get_drvdata(dev);
|
|
||||||
const struct ds1685_rtc_time_regs *bcd_reg_info =
|
|
||||||
ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, true);
|
|
||||||
const struct ds1685_rtc_time_regs *bin_reg_info =
|
|
||||||
ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, false);
|
|
||||||
|
|
||||||
/* We only accept numbers. */
|
|
||||||
if (kstrtol(buf, 10, &val) < 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Make sure we actually matched something. */
|
|
||||||
if (!bcd_reg_info || !bin_reg_info)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Check for a valid range. */
|
|
||||||
if (rtc->bcd_mode) {
|
|
||||||
if ((val < bcd_reg_info->min) || (val > bcd_reg_info->max))
|
|
||||||
return -ERANGE;
|
|
||||||
} else {
|
|
||||||
if ((val < bin_reg_info->min) || (val > bin_reg_info->max))
|
|
||||||
return -ERANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
val = ds1685_rtc_bin2bcd(rtc, val, bin_reg_info->mask,
|
|
||||||
bcd_reg_info->mask);
|
|
||||||
|
|
||||||
/* bcd_reg_info->reg == bin_reg_info->reg. */
|
|
||||||
ds1685_rtc_begin_data_access(rtc);
|
|
||||||
rtc->write(rtc, bcd_reg_info->reg, val);
|
|
||||||
ds1685_rtc_end_data_access(rtc);
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DS1685_RTC_SYSFS_REG_RW - device_attribute for a read-write time register.
|
|
||||||
* @reg: time/date register to read or write.
|
|
||||||
*/
|
|
||||||
#define DS1685_RTC_SYSFS_TIME_REG_RW(reg) \
|
|
||||||
static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, \
|
|
||||||
ds1685_rtc_sysfs_time_regs_show, \
|
|
||||||
ds1685_rtc_sysfs_time_regs_store)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Time/Date Register bits.
|
|
||||||
*/
|
|
||||||
DS1685_RTC_SYSFS_TIME_REG_RW(seconds);
|
|
||||||
DS1685_RTC_SYSFS_TIME_REG_RW(minutes);
|
|
||||||
DS1685_RTC_SYSFS_TIME_REG_RW(hours);
|
|
||||||
DS1685_RTC_SYSFS_TIME_REG_RW(wday);
|
|
||||||
DS1685_RTC_SYSFS_TIME_REG_RW(mday);
|
|
||||||
DS1685_RTC_SYSFS_TIME_REG_RW(month);
|
|
||||||
DS1685_RTC_SYSFS_TIME_REG_RW(year);
|
|
||||||
DS1685_RTC_SYSFS_TIME_REG_RW(century);
|
|
||||||
DS1685_RTC_SYSFS_TIME_REG_RW(alarm_seconds);
|
|
||||||
DS1685_RTC_SYSFS_TIME_REG_RW(alarm_minutes);
|
|
||||||
DS1685_RTC_SYSFS_TIME_REG_RW(alarm_hours);
|
|
||||||
DS1685_RTC_SYSFS_TIME_REG_RW(alarm_mday);
|
|
||||||
|
|
||||||
static struct attribute*
|
|
||||||
ds1685_rtc_sysfs_time_attrs[] = {
|
|
||||||
&dev_attr_seconds.attr,
|
|
||||||
&dev_attr_minutes.attr,
|
|
||||||
&dev_attr_hours.attr,
|
|
||||||
&dev_attr_wday.attr,
|
|
||||||
&dev_attr_mday.attr,
|
|
||||||
&dev_attr_month.attr,
|
|
||||||
&dev_attr_year.attr,
|
|
||||||
&dev_attr_century.attr,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct attribute_group
|
|
||||||
ds1685_rtc_sysfs_time_grp = {
|
|
||||||
.name = "datetime",
|
|
||||||
.attrs = ds1685_rtc_sysfs_time_attrs,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct attribute*
|
|
||||||
ds1685_rtc_sysfs_alarm_attrs[] = {
|
|
||||||
&dev_attr_alarm_seconds.attr,
|
|
||||||
&dev_attr_alarm_minutes.attr,
|
|
||||||
&dev_attr_alarm_hours.attr,
|
|
||||||
&dev_attr_alarm_mday.attr,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct attribute_group
|
|
||||||
ds1685_rtc_sysfs_alarm_grp = {
|
|
||||||
.name = "alarm",
|
|
||||||
.attrs = ds1685_rtc_sysfs_alarm_attrs,
|
|
||||||
};
|
|
||||||
#endif /* CONFIG_RTC_DS1685_SYSFS_REGS */
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ds1685_rtc_sysfs_register - register sysfs files.
|
* ds1685_rtc_sysfs_register - register sysfs files.
|
||||||
* @dev: pointer to device structure.
|
* @dev: pointer to device structure.
|
||||||
|
@ -1752,39 +1206,6 @@ ds1685_rtc_sysfs_register(struct device *dev)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
#ifdef CONFIG_RTC_DS1685_SYSFS_REGS
|
|
||||||
ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrla_grp);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlb_grp);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlc_grp);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrld_grp);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4a_grp);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4b_grp);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_time_grp);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_alarm_grp);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1798,17 +1219,6 @@ ds1685_rtc_sysfs_unregister(struct device *dev)
|
||||||
sysfs_remove_bin_file(&dev->kobj, &ds1685_rtc_sysfs_nvram_attr);
|
sysfs_remove_bin_file(&dev->kobj, &ds1685_rtc_sysfs_nvram_attr);
|
||||||
sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_misc_grp);
|
sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_misc_grp);
|
||||||
|
|
||||||
#ifdef CONFIG_RTC_DS1685_SYSFS_REGS
|
|
||||||
sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrla_grp);
|
|
||||||
sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlb_grp);
|
|
||||||
sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlc_grp);
|
|
||||||
sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrld_grp);
|
|
||||||
sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4a_grp);
|
|
||||||
sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4b_grp);
|
|
||||||
sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_time_grp);
|
|
||||||
sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_alarm_grp);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SYSFS */
|
#endif /* CONFIG_SYSFS */
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/bcd.h>
|
#include <linux/bcd.h>
|
||||||
#include <linux/rtc.h>
|
#include <linux/rtc.h>
|
||||||
|
#include "rtc-core.h"
|
||||||
|
#include <linux/of_irq.h>
|
||||||
|
|
||||||
/* Register map */
|
/* Register map */
|
||||||
/* rtc section */
|
/* rtc section */
|
||||||
|
@ -33,13 +35,16 @@
|
||||||
#define ISL1208_REG_SR_ARST (1<<7) /* auto reset */
|
#define ISL1208_REG_SR_ARST (1<<7) /* auto reset */
|
||||||
#define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */
|
#define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */
|
||||||
#define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */
|
#define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */
|
||||||
|
#define ISL1208_REG_SR_EVT (1<<3) /* event */
|
||||||
#define ISL1208_REG_SR_ALM (1<<2) /* alarm */
|
#define ISL1208_REG_SR_ALM (1<<2) /* alarm */
|
||||||
#define ISL1208_REG_SR_BAT (1<<1) /* battery */
|
#define ISL1208_REG_SR_BAT (1<<1) /* battery */
|
||||||
#define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */
|
#define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */
|
||||||
#define ISL1208_REG_INT 0x08
|
#define ISL1208_REG_INT 0x08
|
||||||
#define ISL1208_REG_INT_ALME (1<<6) /* alarm enable */
|
#define ISL1208_REG_INT_ALME (1<<6) /* alarm enable */
|
||||||
#define ISL1208_REG_INT_IM (1<<7) /* interrupt/alarm mode */
|
#define ISL1208_REG_INT_IM (1<<7) /* interrupt/alarm mode */
|
||||||
#define ISL1208_REG_09 0x09 /* reserved */
|
#define ISL1219_REG_EV 0x09
|
||||||
|
#define ISL1219_REG_EV_EVEN (1<<4) /* event detection enable */
|
||||||
|
#define ISL1219_REG_EV_EVIENB (1<<7) /* event in pull-up disable */
|
||||||
#define ISL1208_REG_ATR 0x0a
|
#define ISL1208_REG_ATR 0x0a
|
||||||
#define ISL1208_REG_DTR 0x0b
|
#define ISL1208_REG_DTR 0x0b
|
||||||
|
|
||||||
|
@ -57,8 +62,24 @@
|
||||||
#define ISL1208_REG_USR2 0x13
|
#define ISL1208_REG_USR2 0x13
|
||||||
#define ISL1208_USR_SECTION_LEN 2
|
#define ISL1208_USR_SECTION_LEN 2
|
||||||
|
|
||||||
|
/* event section */
|
||||||
|
#define ISL1219_REG_SCT 0x14
|
||||||
|
#define ISL1219_REG_MNT 0x15
|
||||||
|
#define ISL1219_REG_HRT 0x16
|
||||||
|
#define ISL1219_REG_DTT 0x17
|
||||||
|
#define ISL1219_REG_MOT 0x18
|
||||||
|
#define ISL1219_REG_YRT 0x19
|
||||||
|
#define ISL1219_EVT_SECTION_LEN 6
|
||||||
|
|
||||||
static struct i2c_driver isl1208_driver;
|
static struct i2c_driver isl1208_driver;
|
||||||
|
|
||||||
|
/* ISL1208 various variants */
|
||||||
|
enum {
|
||||||
|
TYPE_ISL1208 = 0,
|
||||||
|
TYPE_ISL1218,
|
||||||
|
TYPE_ISL1219,
|
||||||
|
};
|
||||||
|
|
||||||
/* block read */
|
/* block read */
|
||||||
static int
|
static int
|
||||||
isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[],
|
isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[],
|
||||||
|
@ -80,8 +101,8 @@ isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[],
|
||||||
};
|
};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
BUG_ON(reg > ISL1208_REG_USR2);
|
WARN_ON(reg > ISL1219_REG_YRT);
|
||||||
BUG_ON(reg + len > ISL1208_REG_USR2 + 1);
|
WARN_ON(reg + len > ISL1219_REG_YRT + 1);
|
||||||
|
|
||||||
ret = i2c_transfer(client->adapter, msgs, 2);
|
ret = i2c_transfer(client->adapter, msgs, 2);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
|
@ -104,8 +125,8 @@ isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[],
|
||||||
};
|
};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
BUG_ON(reg > ISL1208_REG_USR2);
|
WARN_ON(reg > ISL1219_REG_YRT);
|
||||||
BUG_ON(reg + len > ISL1208_REG_USR2 + 1);
|
WARN_ON(reg + len > ISL1219_REG_YRT + 1);
|
||||||
|
|
||||||
i2c_buf[0] = reg;
|
i2c_buf[0] = reg;
|
||||||
memcpy(&i2c_buf[1], &buf[0], len);
|
memcpy(&i2c_buf[1], &buf[0], len);
|
||||||
|
@ -493,6 +514,73 @@ isl1208_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||||
return isl1208_i2c_set_alarm(to_i2c_client(dev), alarm);
|
return isl1208_i2c_set_alarm(to_i2c_client(dev), alarm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t timestamp0_store(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = dev_get_drvdata(dev);
|
||||||
|
int sr;
|
||||||
|
|
||||||
|
sr = isl1208_i2c_get_sr(client);
|
||||||
|
if (sr < 0) {
|
||||||
|
dev_err(dev, "%s: reading SR failed\n", __func__);
|
||||||
|
return sr;
|
||||||
|
}
|
||||||
|
|
||||||
|
sr &= ~ISL1208_REG_SR_EVT;
|
||||||
|
|
||||||
|
sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr);
|
||||||
|
if (sr < 0)
|
||||||
|
dev_err(dev, "%s: writing SR failed\n",
|
||||||
|
__func__);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t timestamp0_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = dev_get_drvdata(dev);
|
||||||
|
u8 regs[ISL1219_EVT_SECTION_LEN] = { 0, };
|
||||||
|
struct rtc_time tm;
|
||||||
|
int sr;
|
||||||
|
|
||||||
|
sr = isl1208_i2c_get_sr(client);
|
||||||
|
if (sr < 0) {
|
||||||
|
dev_err(dev, "%s: reading SR failed\n", __func__);
|
||||||
|
return sr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(sr & ISL1208_REG_SR_EVT))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
sr = isl1208_i2c_read_regs(client, ISL1219_REG_SCT, regs,
|
||||||
|
ISL1219_EVT_SECTION_LEN);
|
||||||
|
if (sr < 0) {
|
||||||
|
dev_err(dev, "%s: reading event section failed\n",
|
||||||
|
__func__);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MSB of each alarm register is an enable bit */
|
||||||
|
tm.tm_sec = bcd2bin(regs[ISL1219_REG_SCT - ISL1219_REG_SCT] & 0x7f);
|
||||||
|
tm.tm_min = bcd2bin(regs[ISL1219_REG_MNT - ISL1219_REG_SCT] & 0x7f);
|
||||||
|
tm.tm_hour = bcd2bin(regs[ISL1219_REG_HRT - ISL1219_REG_SCT] & 0x3f);
|
||||||
|
tm.tm_mday = bcd2bin(regs[ISL1219_REG_DTT - ISL1219_REG_SCT] & 0x3f);
|
||||||
|
tm.tm_mon =
|
||||||
|
bcd2bin(regs[ISL1219_REG_MOT - ISL1219_REG_SCT] & 0x1f) - 1;
|
||||||
|
tm.tm_year = bcd2bin(regs[ISL1219_REG_YRT - ISL1219_REG_SCT]) + 100;
|
||||||
|
|
||||||
|
sr = rtc_valid_tm(&tm);
|
||||||
|
if (sr)
|
||||||
|
return sr;
|
||||||
|
|
||||||
|
return sprintf(buf, "%llu\n",
|
||||||
|
(unsigned long long)rtc_tm_to_time64(&tm));
|
||||||
|
};
|
||||||
|
|
||||||
|
static DEVICE_ATTR_RW(timestamp0);
|
||||||
|
|
||||||
static irqreturn_t
|
static irqreturn_t
|
||||||
isl1208_rtc_interrupt(int irq, void *data)
|
isl1208_rtc_interrupt(int irq, void *data)
|
||||||
{
|
{
|
||||||
|
@ -538,6 +626,13 @@ isl1208_rtc_interrupt(int irq, void *data)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sr & ISL1208_REG_SR_EVT) {
|
||||||
|
sysfs_notify(&rtc->dev.kobj, NULL,
|
||||||
|
dev_attr_timestamp0.attr.name);
|
||||||
|
dev_warn(&client->dev, "event detected");
|
||||||
|
handled = 1;
|
||||||
|
}
|
||||||
|
|
||||||
return handled ? IRQ_HANDLED : IRQ_NONE;
|
return handled ? IRQ_HANDLED : IRQ_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,11 +718,39 @@ static const struct attribute_group isl1208_rtc_sysfs_files = {
|
||||||
.attrs = isl1208_rtc_attrs,
|
.attrs = isl1208_rtc_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct attribute *isl1219_rtc_attrs[] = {
|
||||||
|
&dev_attr_timestamp0.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group isl1219_rtc_sysfs_files = {
|
||||||
|
.attrs = isl1219_rtc_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int isl1208_setup_irq(struct i2c_client *client, int irq)
|
||||||
|
{
|
||||||
|
int rc = devm_request_threaded_irq(&client->dev, irq, NULL,
|
||||||
|
isl1208_rtc_interrupt,
|
||||||
|
IRQF_SHARED | IRQF_ONESHOT,
|
||||||
|
isl1208_driver.driver.name,
|
||||||
|
client);
|
||||||
|
if (!rc) {
|
||||||
|
device_init_wakeup(&client->dev, 1);
|
||||||
|
enable_irq_wake(irq);
|
||||||
|
} else {
|
||||||
|
dev_err(&client->dev,
|
||||||
|
"Unable to request irq %d, no alarm support\n",
|
||||||
|
irq);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct rtc_device *rtc;
|
struct rtc_device *rtc;
|
||||||
|
int evdet_irq = -1;
|
||||||
|
|
||||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
|
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
@ -642,6 +765,7 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
rtc->ops = &isl1208_rtc_ops;
|
rtc->ops = &isl1208_rtc_ops;
|
||||||
|
|
||||||
i2c_set_clientdata(client, rtc);
|
i2c_set_clientdata(client, rtc);
|
||||||
|
dev_set_drvdata(&rtc->dev, client);
|
||||||
|
|
||||||
rc = isl1208_i2c_get_sr(client);
|
rc = isl1208_i2c_get_sr(client);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
|
@ -653,26 +777,46 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
dev_warn(&client->dev, "rtc power failure detected, "
|
dev_warn(&client->dev, "rtc power failure detected, "
|
||||||
"please set clock.\n");
|
"please set clock.\n");
|
||||||
|
|
||||||
|
if (id->driver_data == TYPE_ISL1219) {
|
||||||
|
struct device_node *np = client->dev.of_node;
|
||||||
|
u32 evienb;
|
||||||
|
|
||||||
|
rc = i2c_smbus_read_byte_data(client, ISL1219_REG_EV);
|
||||||
|
if (rc < 0) {
|
||||||
|
dev_err(&client->dev, "failed to read EV reg\n");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
rc |= ISL1219_REG_EV_EVEN;
|
||||||
|
if (!of_property_read_u32(np, "isil,ev-evienb", &evienb)) {
|
||||||
|
if (evienb)
|
||||||
|
rc |= ISL1219_REG_EV_EVIENB;
|
||||||
|
else
|
||||||
|
rc &= ~ISL1219_REG_EV_EVIENB;
|
||||||
|
}
|
||||||
|
rc = i2c_smbus_write_byte_data(client, ISL1219_REG_EV, rc);
|
||||||
|
if (rc < 0) {
|
||||||
|
dev_err(&client->dev, "could not enable tamper detection\n");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
rc = rtc_add_group(rtc, &isl1219_rtc_sysfs_files);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
evdet_irq = of_irq_get_byname(np, "evdet");
|
||||||
|
}
|
||||||
|
|
||||||
rc = sysfs_create_group(&client->dev.kobj, &isl1208_rtc_sysfs_files);
|
rc = sysfs_create_group(&client->dev.kobj, &isl1208_rtc_sysfs_files);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if (client->irq > 0) {
|
if (client->irq > 0)
|
||||||
rc = devm_request_threaded_irq(&client->dev, client->irq, NULL,
|
rc = isl1208_setup_irq(client, client->irq);
|
||||||
isl1208_rtc_interrupt,
|
if (rc)
|
||||||
IRQF_SHARED | IRQF_ONESHOT,
|
return rc;
|
||||||
isl1208_driver.driver.name,
|
|
||||||
client);
|
if (evdet_irq > 0 && evdet_irq != client->irq)
|
||||||
if (!rc) {
|
rc = isl1208_setup_irq(client, evdet_irq);
|
||||||
device_init_wakeup(&client->dev, 1);
|
if (rc)
|
||||||
enable_irq_wake(client->irq);
|
return rc;
|
||||||
} else {
|
|
||||||
dev_err(&client->dev,
|
|
||||||
"Unable to request irq %d, no alarm support\n",
|
|
||||||
client->irq);
|
|
||||||
client->irq = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rtc_register_device(rtc);
|
return rtc_register_device(rtc);
|
||||||
}
|
}
|
||||||
|
@ -686,8 +830,9 @@ isl1208_remove(struct i2c_client *client)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct i2c_device_id isl1208_id[] = {
|
static const struct i2c_device_id isl1208_id[] = {
|
||||||
{ "isl1208", 0 },
|
{ "isl1208", TYPE_ISL1208 },
|
||||||
{ "isl1218", 0 },
|
{ "isl1218", TYPE_ISL1218 },
|
||||||
|
{ "isl1219", TYPE_ISL1219 },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(i2c, isl1208_id);
|
MODULE_DEVICE_TABLE(i2c, isl1208_id);
|
||||||
|
@ -695,6 +840,7 @@ MODULE_DEVICE_TABLE(i2c, isl1208_id);
|
||||||
static const struct of_device_id isl1208_of_match[] = {
|
static const struct of_device_id isl1208_of_match[] = {
|
||||||
{ .compatible = "isil,isl1208" },
|
{ .compatible = "isil,isl1208" },
|
||||||
{ .compatible = "isil,isl1218" },
|
{ .compatible = "isil,isl1218" },
|
||||||
|
{ .compatible = "isil,isl1219" },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, isl1208_of_match);
|
MODULE_DEVICE_TABLE(of, isl1208_of_match);
|
||||||
|
|
|
@ -373,7 +373,6 @@ static int m48t59_rtc_probe(struct platform_device *pdev)
|
||||||
struct m48t59_private *m48t59 = NULL;
|
struct m48t59_private *m48t59 = NULL;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
int ret = -ENOMEM;
|
int ret = -ENOMEM;
|
||||||
char *name;
|
|
||||||
const struct rtc_class_ops *ops;
|
const struct rtc_class_ops *ops;
|
||||||
struct nvmem_config nvmem_cfg = {
|
struct nvmem_config nvmem_cfg = {
|
||||||
.name = "m48t59-",
|
.name = "m48t59-",
|
||||||
|
@ -448,17 +447,14 @@ static int m48t59_rtc_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
switch (pdata->type) {
|
switch (pdata->type) {
|
||||||
case M48T59RTC_TYPE_M48T59:
|
case M48T59RTC_TYPE_M48T59:
|
||||||
name = "m48t59";
|
|
||||||
ops = &m48t59_rtc_ops;
|
ops = &m48t59_rtc_ops;
|
||||||
pdata->offset = 0x1ff0;
|
pdata->offset = 0x1ff0;
|
||||||
break;
|
break;
|
||||||
case M48T59RTC_TYPE_M48T02:
|
case M48T59RTC_TYPE_M48T02:
|
||||||
name = "m48t02";
|
|
||||||
ops = &m48t02_rtc_ops;
|
ops = &m48t02_rtc_ops;
|
||||||
pdata->offset = 0x7f0;
|
pdata->offset = 0x7f0;
|
||||||
break;
|
break;
|
||||||
case M48T59RTC_TYPE_M48T08:
|
case M48T59RTC_TYPE_M48T08:
|
||||||
name = "m48t08";
|
|
||||||
ops = &m48t02_rtc_ops;
|
ops = &m48t02_rtc_ops;
|
||||||
pdata->offset = 0x1ff0;
|
pdata->offset = 0x1ff0;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,16 +1,10 @@
|
||||||
/*
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
* RTC driver for Maxim MAX77686 and MAX77802
|
//
|
||||||
*
|
// RTC driver for Maxim MAX77686 and MAX77802
|
||||||
* Copyright (C) 2012 Samsung Electronics Co.Ltd
|
//
|
||||||
*
|
// Copyright (C) 2012 Samsung Electronics Co.Ltd
|
||||||
* based on rtc-max8997.c
|
//
|
||||||
*
|
// based on rtc-max8997.c
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
|
@ -1,16 +1,10 @@
|
||||||
/*
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
* RTC driver for Maxim MAX8997
|
//
|
||||||
*
|
// RTC driver for Maxim MAX8997
|
||||||
* Copyright (C) 2013 Samsung Electronics Co.Ltd
|
//
|
||||||
*
|
// Copyright (C) 2013 Samsung Electronics Co.Ltd
|
||||||
* based on rtc-max8998.c
|
//
|
||||||
*
|
// based on rtc-max8998.c
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,10 @@
|
||||||
/*
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
* RTC driver for Maxim MAX8998
|
//
|
||||||
*
|
// RTC driver for Maxim MAX8998
|
||||||
* Copyright (C) 2010 Samsung Electronics Co.Ltd
|
//
|
||||||
* Author: Minkyu Kang <mk7.kang@samsung.com>
|
// Copyright (C) 2010 Samsung Electronics Co.Ltd
|
||||||
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
|
// Author: Minkyu Kang <mk7.kang@samsung.com>
|
||||||
*
|
// Author: Joonyoung Shim <jy0922.shim@samsung.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.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
|
|
|
@ -449,6 +449,7 @@ static void omap_rtc_power_off(void)
|
||||||
|
|
||||||
if (tm2bcd(&tm) < 0) {
|
if (tm2bcd(&tm) < 0) {
|
||||||
dev_err(&rtc->rtc->dev, "power off failed\n");
|
dev_err(&rtc->rtc->dev, "power off failed\n");
|
||||||
|
rtc->type->lock(rtc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,9 +583,7 @@ static int rtc_pinconf_get(struct pinctrl_dev *pctldev,
|
||||||
u32 val;
|
u32 val;
|
||||||
u16 arg = 0;
|
u16 arg = 0;
|
||||||
|
|
||||||
rtc->type->unlock(rtc);
|
|
||||||
val = rtc_readl(rtc, OMAP_RTC_PMIC_REG);
|
val = rtc_readl(rtc, OMAP_RTC_PMIC_REG);
|
||||||
rtc->type->lock(rtc);
|
|
||||||
|
|
||||||
switch (param) {
|
switch (param) {
|
||||||
case PIN_CONFIG_INPUT_ENABLE:
|
case PIN_CONFIG_INPUT_ENABLE:
|
||||||
|
@ -614,9 +613,7 @@ static int rtc_pinconf_set(struct pinctrl_dev *pctldev,
|
||||||
u32 param_val;
|
u32 param_val;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
rtc->type->unlock(rtc);
|
|
||||||
val = rtc_readl(rtc, OMAP_RTC_PMIC_REG);
|
val = rtc_readl(rtc, OMAP_RTC_PMIC_REG);
|
||||||
rtc->type->lock(rtc);
|
|
||||||
|
|
||||||
/* active low by default */
|
/* active low by default */
|
||||||
val |= OMAP_RTC_PMIC_EXT_WKUP_POL(pin);
|
val |= OMAP_RTC_PMIC_EXT_WKUP_POL(pin);
|
||||||
|
@ -861,13 +858,6 @@ static int omap_rtc_probe(struct platform_device *pdev)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rtc->is_pmic_controller) {
|
|
||||||
if (!pm_power_off) {
|
|
||||||
omap_rtc_power_off_rtc = rtc;
|
|
||||||
pm_power_off = omap_rtc_power_off;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Support ext_wakeup pinconf */
|
/* Support ext_wakeup pinconf */
|
||||||
rtc_pinctrl_desc.name = dev_name(&pdev->dev);
|
rtc_pinctrl_desc.name = dev_name(&pdev->dev);
|
||||||
|
|
||||||
|
@ -880,12 +870,21 @@ static int omap_rtc_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
ret = rtc_register_device(rtc->rtc);
|
ret = rtc_register_device(rtc->rtc);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err_deregister_pinctrl;
|
||||||
|
|
||||||
rtc_nvmem_register(rtc->rtc, &omap_rtc_nvmem_config);
|
rtc_nvmem_register(rtc->rtc, &omap_rtc_nvmem_config);
|
||||||
|
|
||||||
|
if (rtc->is_pmic_controller) {
|
||||||
|
if (!pm_power_off) {
|
||||||
|
omap_rtc_power_off_rtc = rtc;
|
||||||
|
pm_power_off = omap_rtc_power_off;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_deregister_pinctrl:
|
||||||
|
pinctrl_unregister(rtc->pctldev);
|
||||||
err:
|
err:
|
||||||
clk_disable_unprepare(rtc->clk);
|
clk_disable_unprepare(rtc->clk);
|
||||||
device_init_wakeup(&pdev->dev, false);
|
device_init_wakeup(&pdev->dev, false);
|
||||||
|
|
|
@ -36,6 +36,11 @@
|
||||||
#define PCF2127_REG_MO (0x08)
|
#define PCF2127_REG_MO (0x08)
|
||||||
#define PCF2127_REG_YR (0x09)
|
#define PCF2127_REG_YR (0x09)
|
||||||
|
|
||||||
|
/* the pcf2127 has 512 bytes nvmem, pcf2129 doesn't */
|
||||||
|
#define PCF2127_REG_RAM_addr_MSB 0x1a
|
||||||
|
#define PCF2127_REG_RAM_wrt_cmd 0x1c
|
||||||
|
#define PCF2127_REG_RAM_rd_cmd 0x1d
|
||||||
|
|
||||||
#define PCF2127_OSF BIT(7) /* Oscillator Fail flag */
|
#define PCF2127_OSF BIT(7) /* Oscillator Fail flag */
|
||||||
|
|
||||||
struct pcf2127 {
|
struct pcf2127 {
|
||||||
|
@ -183,10 +188,47 @@ static const struct rtc_class_ops pcf2127_rtc_ops = {
|
||||||
.set_time = pcf2127_rtc_set_time,
|
.set_time = pcf2127_rtc_set_time,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int pcf2127_nvmem_read(void *priv, unsigned int offset,
|
||||||
|
void *val, size_t bytes)
|
||||||
|
{
|
||||||
|
struct pcf2127 *pcf2127 = priv;
|
||||||
|
int ret;
|
||||||
|
unsigned char offsetbuf[] = { offset >> 8, offset };
|
||||||
|
|
||||||
|
ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_addr_MSB,
|
||||||
|
offsetbuf, 2);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_RAM_rd_cmd,
|
||||||
|
val, bytes);
|
||||||
|
|
||||||
|
return ret ?: bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pcf2127_nvmem_write(void *priv, unsigned int offset,
|
||||||
|
void *val, size_t bytes)
|
||||||
|
{
|
||||||
|
struct pcf2127 *pcf2127 = priv;
|
||||||
|
int ret;
|
||||||
|
unsigned char offsetbuf[] = { offset >> 8, offset };
|
||||||
|
|
||||||
|
ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_addr_MSB,
|
||||||
|
offsetbuf, 2);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_wrt_cmd,
|
||||||
|
val, bytes);
|
||||||
|
|
||||||
|
return ret ?: bytes;
|
||||||
|
}
|
||||||
|
|
||||||
static int pcf2127_probe(struct device *dev, struct regmap *regmap,
|
static int pcf2127_probe(struct device *dev, struct regmap *regmap,
|
||||||
const char *name)
|
const char *name, bool has_nvmem)
|
||||||
{
|
{
|
||||||
struct pcf2127 *pcf2127;
|
struct pcf2127 *pcf2127;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
dev_dbg(dev, "%s\n", __func__);
|
dev_dbg(dev, "%s\n", __func__);
|
||||||
|
|
||||||
|
@ -200,8 +242,21 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
|
||||||
|
|
||||||
pcf2127->rtc = devm_rtc_device_register(dev, name, &pcf2127_rtc_ops,
|
pcf2127->rtc = devm_rtc_device_register(dev, name, &pcf2127_rtc_ops,
|
||||||
THIS_MODULE);
|
THIS_MODULE);
|
||||||
|
if (IS_ERR(pcf2127->rtc))
|
||||||
|
return PTR_ERR(pcf2127->rtc);
|
||||||
|
|
||||||
return PTR_ERR_OR_ZERO(pcf2127->rtc);
|
if (has_nvmem) {
|
||||||
|
struct nvmem_config nvmem_cfg = {
|
||||||
|
.priv = pcf2127,
|
||||||
|
.reg_read = pcf2127_nvmem_read,
|
||||||
|
.reg_write = pcf2127_nvmem_write,
|
||||||
|
.size = 512,
|
||||||
|
};
|
||||||
|
|
||||||
|
ret = rtc_nvmem_register(pcf2127->rtc, &nvmem_cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_OF
|
#ifdef CONFIG_OF
|
||||||
|
@ -309,11 +364,11 @@ static int pcf2127_i2c_probe(struct i2c_client *client,
|
||||||
}
|
}
|
||||||
|
|
||||||
return pcf2127_probe(&client->dev, regmap,
|
return pcf2127_probe(&client->dev, regmap,
|
||||||
pcf2127_i2c_driver.driver.name);
|
pcf2127_i2c_driver.driver.name, id->driver_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct i2c_device_id pcf2127_i2c_id[] = {
|
static const struct i2c_device_id pcf2127_i2c_id[] = {
|
||||||
{ "pcf2127", 0 },
|
{ "pcf2127", 1 },
|
||||||
{ "pcf2129", 0 },
|
{ "pcf2129", 0 },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
@ -372,11 +427,12 @@ static int pcf2127_spi_probe(struct spi_device *spi)
|
||||||
return PTR_ERR(regmap);
|
return PTR_ERR(regmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pcf2127_probe(&spi->dev, regmap, pcf2127_spi_driver.driver.name);
|
return pcf2127_probe(&spi->dev, regmap, pcf2127_spi_driver.driver.name,
|
||||||
|
spi_get_device_id(spi)->driver_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct spi_device_id pcf2127_spi_id[] = {
|
static const struct spi_device_id pcf2127_spi_id[] = {
|
||||||
{ "pcf2127", 0 },
|
{ "pcf2127", 1 },
|
||||||
{ "pcf2129", 0 },
|
{ "pcf2129", 0 },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,37 +43,38 @@ static struct i2c_driver pcf85063_driver;
|
||||||
|
|
||||||
static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1)
|
static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1)
|
||||||
{
|
{
|
||||||
s32 ret;
|
int rc;
|
||||||
|
u8 reg;
|
||||||
|
|
||||||
ret = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1);
|
rc = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1);
|
||||||
if (ret < 0) {
|
if (rc < 0) {
|
||||||
dev_err(&client->dev, "Failing to stop the clock\n");
|
dev_err(&client->dev, "Failing to stop the clock\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stop the clock */
|
/* stop the clock */
|
||||||
ret |= PCF85063_REG_CTRL1_STOP;
|
reg = rc | PCF85063_REG_CTRL1_STOP;
|
||||||
|
|
||||||
ret = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ret);
|
rc = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, reg);
|
||||||
if (ret < 0) {
|
if (rc < 0) {
|
||||||
dev_err(&client->dev, "Failing to stop the clock\n");
|
dev_err(&client->dev, "Failing to stop the clock\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
*ctrl1 = ret;
|
*ctrl1 = reg;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pcf85063_start_clock(struct i2c_client *client, u8 ctrl1)
|
static int pcf85063_start_clock(struct i2c_client *client, u8 ctrl1)
|
||||||
{
|
{
|
||||||
s32 ret;
|
int rc;
|
||||||
|
|
||||||
/* start the clock */
|
/* start the clock */
|
||||||
ctrl1 &= ~PCF85063_REG_CTRL1_STOP;
|
ctrl1 &= ~PCF85063_REG_CTRL1_STOP;
|
||||||
|
|
||||||
ret = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ctrl1);
|
rc = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ctrl1);
|
||||||
if (ret < 0) {
|
if (rc < 0) {
|
||||||
dev_err(&client->dev, "Failing to start the clock\n");
|
dev_err(&client->dev, "Failing to start the clock\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,9 @@
|
||||||
/*
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
* Copyright (c) 2013-2014 Samsung Electronics Co., Ltd
|
//
|
||||||
* http://www.samsung.com
|
// Copyright (c) 2013-2014 Samsung Electronics Co., Ltd
|
||||||
*
|
// http://www.samsung.com
|
||||||
* Copyright (C) 2013 Google, Inc
|
//
|
||||||
*
|
// Copyright (C) 2013 Google, Inc
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||||
|
|
||||||
|
|
|
@ -224,7 +224,6 @@ int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info)
|
||||||
info->rtc = rtc;
|
info->rtc = rtc;
|
||||||
|
|
||||||
rtc->max_user_freq = RTC_FREQ;
|
rtc->max_user_freq = RTC_FREQ;
|
||||||
rtc_irq_set_freq(rtc, NULL, RTC_FREQ);
|
|
||||||
|
|
||||||
/* Fix for a nasty initialization problem the in SA11xx RTSR register.
|
/* Fix for a nasty initialization problem the in SA11xx RTSR register.
|
||||||
* See also the comments in sa1100_rtc_interrupt().
|
* See also the comments in sa1100_rtc_interrupt().
|
||||||
|
|
|
@ -143,8 +143,6 @@ static int __sh_rtc_alarm(struct sh_rtc *rtc)
|
||||||
|
|
||||||
static int __sh_rtc_periodic(struct sh_rtc *rtc)
|
static int __sh_rtc_periodic(struct sh_rtc *rtc)
|
||||||
{
|
{
|
||||||
struct rtc_device *rtc_dev = rtc->rtc_dev;
|
|
||||||
struct rtc_task *irq_task;
|
|
||||||
unsigned int tmp, pending;
|
unsigned int tmp, pending;
|
||||||
|
|
||||||
tmp = readb(rtc->regbase + RCR2);
|
tmp = readb(rtc->regbase + RCR2);
|
||||||
|
@ -161,14 +159,7 @@ static int __sh_rtc_periodic(struct sh_rtc *rtc)
|
||||||
else {
|
else {
|
||||||
if (rtc->periodic_freq & PF_HP)
|
if (rtc->periodic_freq & PF_HP)
|
||||||
rtc->periodic_freq |= PF_COUNT;
|
rtc->periodic_freq |= PF_COUNT;
|
||||||
if (rtc->periodic_freq & PF_KOU) {
|
rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
|
||||||
spin_lock(&rtc_dev->irq_task_lock);
|
|
||||||
irq_task = rtc_dev->irq_task;
|
|
||||||
if (irq_task)
|
|
||||||
irq_task->func(irq_task->private_data);
|
|
||||||
spin_unlock(&rtc_dev->irq_task_lock);
|
|
||||||
} else
|
|
||||||
rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pending;
|
return pending;
|
||||||
|
@ -224,81 +215,6 @@ static irqreturn_t sh_rtc_shared(int irq, void *dev_id)
|
||||||
return IRQ_RETVAL(ret);
|
return IRQ_RETVAL(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sh_rtc_irq_set_state(struct device *dev, int enable)
|
|
||||||
{
|
|
||||||
struct sh_rtc *rtc = dev_get_drvdata(dev);
|
|
||||||
unsigned int tmp;
|
|
||||||
|
|
||||||
spin_lock_irq(&rtc->lock);
|
|
||||||
|
|
||||||
tmp = readb(rtc->regbase + RCR2);
|
|
||||||
|
|
||||||
if (enable) {
|
|
||||||
rtc->periodic_freq |= PF_KOU;
|
|
||||||
tmp &= ~RCR2_PEF; /* Clear PES bit */
|
|
||||||
tmp |= (rtc->periodic_freq & ~PF_HP); /* Set PES2-0 */
|
|
||||||
} else {
|
|
||||||
rtc->periodic_freq &= ~PF_KOU;
|
|
||||||
tmp &= ~(RCR2_PESMASK | RCR2_PEF);
|
|
||||||
}
|
|
||||||
|
|
||||||
writeb(tmp, rtc->regbase + RCR2);
|
|
||||||
|
|
||||||
spin_unlock_irq(&rtc->lock);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sh_rtc_irq_set_freq(struct device *dev, int freq)
|
|
||||||
{
|
|
||||||
struct sh_rtc *rtc = dev_get_drvdata(dev);
|
|
||||||
int tmp, ret = 0;
|
|
||||||
|
|
||||||
spin_lock_irq(&rtc->lock);
|
|
||||||
tmp = rtc->periodic_freq & PF_MASK;
|
|
||||||
|
|
||||||
switch (freq) {
|
|
||||||
case 0:
|
|
||||||
rtc->periodic_freq = 0x00;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
rtc->periodic_freq = 0x60;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
rtc->periodic_freq = 0x50;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
rtc->periodic_freq = 0x40;
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
rtc->periodic_freq = 0x30 | PF_HP;
|
|
||||||
break;
|
|
||||||
case 16:
|
|
||||||
rtc->periodic_freq = 0x30;
|
|
||||||
break;
|
|
||||||
case 32:
|
|
||||||
rtc->periodic_freq = 0x20 | PF_HP;
|
|
||||||
break;
|
|
||||||
case 64:
|
|
||||||
rtc->periodic_freq = 0x20;
|
|
||||||
break;
|
|
||||||
case 128:
|
|
||||||
rtc->periodic_freq = 0x10 | PF_HP;
|
|
||||||
break;
|
|
||||||
case 256:
|
|
||||||
rtc->periodic_freq = 0x10;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret = -ENOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret == 0)
|
|
||||||
rtc->periodic_freq |= tmp;
|
|
||||||
|
|
||||||
spin_unlock_irq(&rtc->lock);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void sh_rtc_setaie(struct device *dev, unsigned int enable)
|
static inline void sh_rtc_setaie(struct device *dev, unsigned int enable)
|
||||||
{
|
{
|
||||||
struct sh_rtc *rtc = dev_get_drvdata(dev);
|
struct sh_rtc *rtc = dev_get_drvdata(dev);
|
||||||
|
@ -675,8 +591,6 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
|
||||||
platform_set_drvdata(pdev, rtc);
|
platform_set_drvdata(pdev, rtc);
|
||||||
|
|
||||||
/* everything disabled by default */
|
/* everything disabled by default */
|
||||||
sh_rtc_irq_set_freq(&pdev->dev, 0);
|
|
||||||
sh_rtc_irq_set_state(&pdev->dev, 0);
|
|
||||||
sh_rtc_setaie(&pdev->dev, 0);
|
sh_rtc_setaie(&pdev->dev, 0);
|
||||||
sh_rtc_setcie(&pdev->dev, 0);
|
sh_rtc_setcie(&pdev->dev, 0);
|
||||||
|
|
||||||
|
@ -708,8 +622,6 @@ static int __exit sh_rtc_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct sh_rtc *rtc = platform_get_drvdata(pdev);
|
struct sh_rtc *rtc = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
sh_rtc_irq_set_state(&pdev->dev, 0);
|
|
||||||
|
|
||||||
sh_rtc_setaie(&pdev->dev, 0);
|
sh_rtc_setaie(&pdev->dev, 0);
|
||||||
sh_rtc_setcie(&pdev->dev, 0);
|
sh_rtc_setcie(&pdev->dev, 0);
|
||||||
|
|
||||||
|
|
|
@ -40,49 +40,83 @@ struct snvs_rtc_data {
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Read 64 bit timer register, which could be in inconsistent state */
|
||||||
|
static u64 rtc_read_lpsrt(struct snvs_rtc_data *data)
|
||||||
|
{
|
||||||
|
u32 msb, lsb;
|
||||||
|
|
||||||
|
regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &msb);
|
||||||
|
regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &lsb);
|
||||||
|
return (u64)msb << 32 | lsb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the secure real time counter, taking care to deal with the cases of the
|
||||||
|
* counter updating while being read.
|
||||||
|
*/
|
||||||
static u32 rtc_read_lp_counter(struct snvs_rtc_data *data)
|
static u32 rtc_read_lp_counter(struct snvs_rtc_data *data)
|
||||||
{
|
{
|
||||||
u64 read1, read2;
|
u64 read1, read2;
|
||||||
u32 val;
|
unsigned int timeout = 100;
|
||||||
|
|
||||||
|
/* As expected, the registers might update between the read of the LSB
|
||||||
|
* reg and the MSB reg. It's also possible that one register might be
|
||||||
|
* in partially modified state as well.
|
||||||
|
*/
|
||||||
|
read1 = rtc_read_lpsrt(data);
|
||||||
do {
|
do {
|
||||||
regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &val);
|
read2 = read1;
|
||||||
read1 = val;
|
read1 = rtc_read_lpsrt(data);
|
||||||
read1 <<= 32;
|
} while (read1 != read2 && --timeout);
|
||||||
regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &val);
|
if (!timeout)
|
||||||
read1 |= val;
|
dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n");
|
||||||
|
|
||||||
regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &val);
|
|
||||||
read2 = val;
|
|
||||||
read2 <<= 32;
|
|
||||||
regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &val);
|
|
||||||
read2 |= val;
|
|
||||||
} while (read1 != read2);
|
|
||||||
|
|
||||||
/* Convert 47-bit counter to 32-bit raw second count */
|
/* Convert 47-bit counter to 32-bit raw second count */
|
||||||
return (u32) (read1 >> CNTR_TO_SECS_SH);
|
return (u32) (read1 >> CNTR_TO_SECS_SH);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtc_write_sync_lp(struct snvs_rtc_data *data)
|
/* Just read the lsb from the counter, dealing with inconsistent state */
|
||||||
|
static int rtc_read_lp_counter_lsb(struct snvs_rtc_data *data, u32 *lsb)
|
||||||
{
|
{
|
||||||
u32 count1, count2, count3;
|
u32 count1, count2;
|
||||||
int i;
|
unsigned int timeout = 100;
|
||||||
|
|
||||||
/* Wait for 3 CKIL cycles */
|
regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1);
|
||||||
for (i = 0; i < 3; i++) {
|
do {
|
||||||
do {
|
count2 = count1;
|
||||||
regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1);
|
regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1);
|
||||||
regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count2);
|
} while (count1 != count2 && --timeout);
|
||||||
} while (count1 != count2);
|
if (!timeout) {
|
||||||
|
dev_err(&data->rtc->dev, "Timeout trying to get valid LPSRT Counter read\n");
|
||||||
/* Now wait until counter value changes */
|
return -ETIMEDOUT;
|
||||||
do {
|
|
||||||
do {
|
|
||||||
regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count2);
|
|
||||||
regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count3);
|
|
||||||
} while (count2 != count3);
|
|
||||||
} while (count3 == count1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*lsb = count1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rtc_write_sync_lp(struct snvs_rtc_data *data)
|
||||||
|
{
|
||||||
|
u32 count1, count2;
|
||||||
|
u32 elapsed;
|
||||||
|
unsigned int timeout = 1000;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = rtc_read_lp_counter_lsb(data, &count1);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Wait for 3 CKIL cycles, about 61.0-91.5 µs */
|
||||||
|
do {
|
||||||
|
ret = rtc_read_lp_counter_lsb(data, &count2);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
elapsed = count2 - count1; /* wrap around _is_ handled! */
|
||||||
|
} while (elapsed < 3 && --timeout);
|
||||||
|
if (!timeout) {
|
||||||
|
dev_err(&data->rtc->dev, "Timeout waiting for LPSRT Counter to change\n");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snvs_rtc_enable(struct snvs_rtc_data *data, bool enable)
|
static int snvs_rtc_enable(struct snvs_rtc_data *data, bool enable)
|
||||||
|
@ -166,9 +200,7 @@ static int snvs_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
|
||||||
(SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN),
|
(SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN),
|
||||||
enable ? (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN) : 0);
|
enable ? (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN) : 0);
|
||||||
|
|
||||||
rtc_write_sync_lp(data);
|
return rtc_write_sync_lp(data);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||||
|
@ -176,11 +208,14 @@ static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||||
struct snvs_rtc_data *data = dev_get_drvdata(dev);
|
struct snvs_rtc_data *data = dev_get_drvdata(dev);
|
||||||
struct rtc_time *alrm_tm = &alrm->time;
|
struct rtc_time *alrm_tm = &alrm->time;
|
||||||
unsigned long time;
|
unsigned long time;
|
||||||
|
int ret;
|
||||||
|
|
||||||
rtc_tm_to_time(alrm_tm, &time);
|
rtc_tm_to_time(alrm_tm, &time);
|
||||||
|
|
||||||
regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, SNVS_LPCR_LPTA_EN, 0);
|
regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, SNVS_LPCR_LPTA_EN, 0);
|
||||||
rtc_write_sync_lp(data);
|
ret = rtc_write_sync_lp(data);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
regmap_write(data->regmap, data->offset + SNVS_LPTAR, time);
|
regmap_write(data->regmap, data->offset + SNVS_LPTAR, time);
|
||||||
|
|
||||||
/* Clear alarm interrupt status bit */
|
/* Clear alarm interrupt status bit */
|
||||||
|
|
|
@ -288,10 +288,22 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
platform_set_drvdata(pdev, rtc_data);
|
platform_set_drvdata(pdev, rtc_data);
|
||||||
|
|
||||||
err = stmp_reset_block(rtc_data->io);
|
/*
|
||||||
if (err) {
|
* Resetting the rtc stops the watchdog timer that is potentially
|
||||||
dev_err(&pdev->dev, "stmp_reset_block failed: %d\n", err);
|
* running. So (assuming it is running on purpose) don't reset if the
|
||||||
return err;
|
* watchdog is enabled.
|
||||||
|
*/
|
||||||
|
if (readl(rtc_data->io + STMP3XXX_RTC_CTRL) &
|
||||||
|
STMP3XXX_RTC_CTRL_WATCHDOGEN) {
|
||||||
|
dev_info(&pdev->dev,
|
||||||
|
"Watchdog is running, skip resetting rtc\n");
|
||||||
|
} else {
|
||||||
|
err = stmp_reset_block(rtc_data->io);
|
||||||
|
if (err) {
|
||||||
|
dev_err(&pdev->dev, "stmp_reset_block failed: %d\n",
|
||||||
|
err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -317,3 +317,46 @@ const struct attribute_group **rtc_get_dev_attribute_groups(void)
|
||||||
{
|
{
|
||||||
return rtc_attr_groups;
|
return rtc_attr_groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps)
|
||||||
|
{
|
||||||
|
size_t old_cnt = 0, add_cnt = 0, new_cnt;
|
||||||
|
const struct attribute_group **groups, **old;
|
||||||
|
|
||||||
|
if (rtc->registered)
|
||||||
|
return -EINVAL;
|
||||||
|
if (!grps)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
groups = rtc->dev.groups;
|
||||||
|
if (groups)
|
||||||
|
for (; *groups; groups++)
|
||||||
|
old_cnt++;
|
||||||
|
|
||||||
|
for (groups = grps; *groups; groups++)
|
||||||
|
add_cnt++;
|
||||||
|
|
||||||
|
new_cnt = old_cnt + add_cnt + 1;
|
||||||
|
groups = devm_kcalloc(&rtc->dev, new_cnt, sizeof(*groups), GFP_KERNEL);
|
||||||
|
if (IS_ERR_OR_NULL(groups))
|
||||||
|
return PTR_ERR(groups);
|
||||||
|
memcpy(groups, rtc->dev.groups, old_cnt * sizeof(*groups));
|
||||||
|
memcpy(groups + old_cnt, grps, add_cnt * sizeof(*groups));
|
||||||
|
groups[old_cnt + add_cnt] = NULL;
|
||||||
|
|
||||||
|
old = rtc->dev.groups;
|
||||||
|
rtc->dev.groups = groups;
|
||||||
|
if (old && old != rtc_attr_groups)
|
||||||
|
devm_kfree(&rtc->dev, old);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(rtc_add_groups);
|
||||||
|
|
||||||
|
int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp)
|
||||||
|
{
|
||||||
|
const struct attribute_group *groups[] = { grp, NULL };
|
||||||
|
|
||||||
|
return rtc_add_groups(rtc, groups);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(rtc_add_group);
|
||||||
|
|
|
@ -22,7 +22,7 @@ struct rtc_test_data {
|
||||||
bool alarm_en;
|
bool alarm_en;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct platform_device *pdev[MAX_RTC_TEST];
|
static struct platform_device *pdev[MAX_RTC_TEST];
|
||||||
|
|
||||||
static int test_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
static int test_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||||
{
|
{
|
||||||
|
|
|
@ -87,16 +87,11 @@ struct rtc_class_ops {
|
||||||
int (*set_offset)(struct device *, long offset);
|
int (*set_offset)(struct device *, long offset);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct rtc_task {
|
|
||||||
void (*func)(void *private_data);
|
|
||||||
void *private_data;
|
|
||||||
} rtc_task_t;
|
|
||||||
|
|
||||||
|
|
||||||
struct rtc_timer {
|
struct rtc_timer {
|
||||||
struct rtc_task task;
|
|
||||||
struct timerqueue_node node;
|
struct timerqueue_node node;
|
||||||
ktime_t period;
|
ktime_t period;
|
||||||
|
void (*func)(void *private_data);
|
||||||
|
void *private_data;
|
||||||
int enabled;
|
int enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -121,8 +116,6 @@ struct rtc_device {
|
||||||
wait_queue_head_t irq_queue;
|
wait_queue_head_t irq_queue;
|
||||||
struct fasync_struct *async_queue;
|
struct fasync_struct *async_queue;
|
||||||
|
|
||||||
struct rtc_task *irq_task;
|
|
||||||
spinlock_t irq_task_lock;
|
|
||||||
int irq_freq;
|
int irq_freq;
|
||||||
int max_user_freq;
|
int max_user_freq;
|
||||||
|
|
||||||
|
@ -204,14 +197,8 @@ extern void rtc_update_irq(struct rtc_device *rtc,
|
||||||
extern struct rtc_device *rtc_class_open(const char *name);
|
extern struct rtc_device *rtc_class_open(const char *name);
|
||||||
extern void rtc_class_close(struct rtc_device *rtc);
|
extern void rtc_class_close(struct rtc_device *rtc);
|
||||||
|
|
||||||
extern int rtc_irq_register(struct rtc_device *rtc,
|
extern int rtc_irq_set_state(struct rtc_device *rtc, int enabled);
|
||||||
struct rtc_task *task);
|
extern int rtc_irq_set_freq(struct rtc_device *rtc, int freq);
|
||||||
extern void rtc_irq_unregister(struct rtc_device *rtc,
|
|
||||||
struct rtc_task *task);
|
|
||||||
extern int rtc_irq_set_state(struct rtc_device *rtc,
|
|
||||||
struct rtc_task *task, int enabled);
|
|
||||||
extern int rtc_irq_set_freq(struct rtc_device *rtc,
|
|
||||||
struct rtc_task *task, int freq);
|
|
||||||
extern int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled);
|
extern int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled);
|
||||||
extern int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled);
|
extern int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled);
|
||||||
extern int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc,
|
extern int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc,
|
||||||
|
|
Loading…
Reference in a new issue