diff options
| -rw-r--r-- | drivers/rtc/rtc-s5m.c | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 10982cdfce11..977b40cd32a7 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c | |||
| @@ -28,6 +28,16 @@ | |||
| 28 | #include <linux/mfd/samsung/irq.h> | 28 | #include <linux/mfd/samsung/irq.h> |
| 29 | #include <linux/mfd/samsung/rtc.h> | 29 | #include <linux/mfd/samsung/rtc.h> |
| 30 | 30 | ||
| 31 | /* | ||
| 32 | * Maximum number of retries for checking changes in UDR field | ||
| 33 | * of SEC_RTC_UDR_CON register (to limit possible endless loop). | ||
| 34 | * | ||
| 35 | * After writing to RTC registers (setting time or alarm) read the UDR field | ||
| 36 | * in SEC_RTC_UDR_CON register. UDR is auto-cleared when data have | ||
| 37 | * been transferred. | ||
| 38 | */ | ||
| 39 | #define UDR_READ_RETRY_CNT 5 | ||
| 40 | |||
| 31 | struct s5m_rtc_info { | 41 | struct s5m_rtc_info { |
| 32 | struct device *dev; | 42 | struct device *dev; |
| 33 | struct sec_pmic_dev *s5m87xx; | 43 | struct sec_pmic_dev *s5m87xx; |
| @@ -84,6 +94,25 @@ static int s5m8767_tm_to_data(struct rtc_time *tm, u8 *data) | |||
| 84 | } | 94 | } |
| 85 | } | 95 | } |
| 86 | 96 | ||
| 97 | /* | ||
| 98 | * Read RTC_UDR_CON register and wait till UDR field is cleared. | ||
| 99 | * This indicates that time/alarm update ended. | ||
| 100 | */ | ||
| 101 | static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info) | ||
| 102 | { | ||
| 103 | int ret, retry = UDR_READ_RETRY_CNT; | ||
| 104 | unsigned int data; | ||
| 105 | |||
| 106 | do { | ||
| 107 | ret = regmap_read(info->regmap, SEC_RTC_UDR_CON, &data); | ||
| 108 | } while (--retry && (data & RTC_UDR_MASK) && !ret); | ||
| 109 | |||
| 110 | if (!retry) | ||
| 111 | dev_err(info->dev, "waiting for UDR update, reached max number of retries\n"); | ||
| 112 | |||
| 113 | return ret; | ||
| 114 | } | ||
| 115 | |||
| 87 | static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) | 116 | static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) |
| 88 | { | 117 | { |
| 89 | int ret; | 118 | int ret; |
| @@ -104,9 +133,7 @@ static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) | |||
| 104 | return ret; | 133 | return ret; |
| 105 | } | 134 | } |
| 106 | 135 | ||
| 107 | do { | 136 | ret = s5m8767_wait_for_udr_update(info); |
| 108 | ret = regmap_read(info->regmap, SEC_RTC_UDR_CON, &data); | ||
| 109 | } while ((data & RTC_UDR_MASK) && !ret); | ||
| 110 | 137 | ||
| 111 | return ret; | 138 | return ret; |
| 112 | } | 139 | } |
| @@ -133,9 +160,7 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) | |||
| 133 | return ret; | 160 | return ret; |
| 134 | } | 161 | } |
| 135 | 162 | ||
| 136 | do { | 163 | ret = s5m8767_wait_for_udr_update(info); |
| 137 | ret = regmap_read(info->regmap, SEC_RTC_UDR_CON, &data); | ||
| 138 | } while ((data & RTC_UDR_MASK) && !ret); | ||
| 139 | 164 | ||
| 140 | return ret; | 165 | return ret; |
| 141 | } | 166 | } |
