After setting alarm or time the driver is waiting for UDR register to be cleared indicating that registers data have been transferred. Limit the endless loop to only 5 retries.
Unified · Split
| @@ -28,6 +28,16 @@ · 27 unmodified lines | ||
| 28 | 28 | #include <linux/mfd/samsung/irq.h> |
| 29 | 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 | 41 | struct s5m_rtc_info { |
| 32 | 42 | struct device *dev; |
| 33 | 43 | struct sec_pmic_dev *s5m87xx; |
| @@ -84,6 +94,25 @@ static int s5m8767_tm_to_data(struct rtc_time *tm, u8 *data) · 50 unmodified lines | ||
| 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 | 116 | static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) |
| 88 | 117 | { |
| 89 | 118 | int ret; |
| @@ -104,9 +133,7 @@ static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) · 14 unmodified lines | ||
| 104 | 133 | return ret; |
| 105 | 134 | } |
| 106 | 135 | |
| 107 | − do { | |
| 108 | − ret = regmap_read(info->regmap, SEC_RTC_UDR_CON, &data); | |
| 109 | − } while ((data & RTC_UDR_MASK) && !ret); | |
| 136 | + ret = s5m8767_wait_for_udr_update(info); | |
| 110 | 137 | |
| 111 | 138 | return ret; |
| 112 | 139 | } |
| @@ -133,9 +160,7 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) · 20 unmodified lines | ||
| 133 | 160 | return ret; |
| 134 | 161 | } |
| 135 | 162 | |
| 136 | − do { | |
| 137 | − ret = regmap_read(info->regmap, SEC_RTC_UDR_CON, &data); | |
| 138 | − } while ((data & RTC_UDR_MASK) && !ret); | |
| 163 | + ret = s5m8767_wait_for_udr_update(info); | |
| 139 | 164 | |
| 140 | 165 | return ret; |
| 141 | 166 | } |