summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKrzysztof Kozlowski <k.kozlowski@samsung.com>2015-12-29 23:47:27 -0500
committerAlexandre Belloni <alexandre.belloni@free-electrons.com>2016-01-11 14:21:55 -0500
commit8ae83b6f76fc74eb6535b9d331a3310a59c32f84 (patch)
tree6cd50d77a623198ebd2f37f87aa489cb279bb808
parent67a6025a77be7c6bcb4baeb9424509fcb4ca1e32 (diff)
rtc: s5m: Make register configuration per S2MPS device to remove exceptions
Before updating time and alarm the driver must set appropriate mask in UDR register. For that purpose the driver uses common register configuration and a lot of exceptions per device in the code. The exceptions are not obvious, for example except the change in the logic sometimes the fields are swapped (WUDR and AUDR between S2MPS14 and S2MPS15). This leads to quite complicated code. Try to make it more obvious by: 1. Documenting the UDR masks for devices and operations. 2. Adding fields in register configuration structure for each operation (read time, write time and alarm). 3. Splitting the configuration per S2MPS13, S2MPS14 and S2MPS15 thus removing exceptions for them. Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> Reviewed-by: Alim Akhtar <alim.akhtar@samsung.com> Tested-by: Alim Akhtar <alim.akhtar@samsung.com> Acked-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
-rw-r--r--drivers/rtc/rtc-s5m.c110
-rw-r--r--include/linux/mfd/samsung/rtc.h2
2 files changed, 77 insertions, 35 deletions
diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c
index 559db8f72117..7407d7394bb4 100644
--- a/drivers/rtc/rtc-s5m.c
+++ b/drivers/rtc/rtc-s5m.c
@@ -38,7 +38,22 @@
38 */ 38 */
39#define UDR_READ_RETRY_CNT 5 39#define UDR_READ_RETRY_CNT 5
40 40
41/* Registers used by the driver which are different between chipsets. */ 41/*
42 * Registers used by the driver which are different between chipsets.
43 *
44 * Operations like read time and write alarm/time require updating
45 * specific fields in UDR register. These fields usually are auto-cleared
46 * (with some exceptions).
47 *
48 * Table of operations per device:
49 *
50 * Device | Write time | Read time | Write alarm
51 * =================================================
52 * S5M8767 | UDR + TIME | | UDR
53 * S2MPS11/14 | WUDR | RUDR | WUDR + RUDR
54 * S2MPS13 | WUDR | RUDR | WUDR + AUDR
55 * S2MPS15 | WUDR | RUDR | AUDR
56 */
42struct s5m_rtc_reg_config { 57struct s5m_rtc_reg_config {
43 /* Number of registers used for setting time/alarm0/alarm1 */ 58 /* Number of registers used for setting time/alarm0/alarm1 */
44 unsigned int regs_count; 59 unsigned int regs_count;
@@ -58,8 +73,13 @@ struct s5m_rtc_reg_config {
58 unsigned int udr_update; 73 unsigned int udr_update;
59 /* Auto-cleared mask in UDR field for writing time and alarm */ 74 /* Auto-cleared mask in UDR field for writing time and alarm */
60 unsigned int autoclear_udr_mask; 75 unsigned int autoclear_udr_mask;
61 /* Mask for UDR field in 'udr_update' register */ 76 /*
62 unsigned int udr_mask; 77 * Masks in UDR field for time and alarm operations.
78 * The read time mask can be 0. Rest should not.
79 */
80 unsigned int read_time_udr_mask;
81 unsigned int write_time_udr_mask;
82 unsigned int write_alarm_udr_mask;
63}; 83};
64 84
65/* Register map for S5M8763 and S5M8767 */ 85/* Register map for S5M8763 and S5M8767 */
@@ -71,14 +91,44 @@ static const struct s5m_rtc_reg_config s5m_rtc_regs = {
71 .alarm1 = S5M_ALARM1_SEC, 91 .alarm1 = S5M_ALARM1_SEC,
72 .udr_update = S5M_RTC_UDR_CON, 92 .udr_update = S5M_RTC_UDR_CON,
73 .autoclear_udr_mask = S5M_RTC_UDR_MASK, 93 .autoclear_udr_mask = S5M_RTC_UDR_MASK,
74 .udr_mask = S5M_RTC_UDR_MASK, 94 .read_time_udr_mask = 0, /* Not needed */
95 .write_time_udr_mask = S5M_RTC_UDR_MASK | S5M_RTC_TIME_EN_MASK,
96 .write_alarm_udr_mask = S5M_RTC_UDR_MASK,
97};
98
99/* Register map for S2MPS13 */
100static const struct s5m_rtc_reg_config s2mps13_rtc_regs = {
101 .regs_count = 7,
102 .time = S2MPS_RTC_SEC,
103 .ctrl = S2MPS_RTC_CTRL,
104 .alarm0 = S2MPS_ALARM0_SEC,
105 .alarm1 = S2MPS_ALARM1_SEC,
106 .udr_update = S2MPS_RTC_UDR_CON,
107 .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK,
108 .read_time_udr_mask = S2MPS_RTC_RUDR_MASK,
109 .write_time_udr_mask = S2MPS_RTC_WUDR_MASK,
110 .write_alarm_udr_mask = S2MPS_RTC_WUDR_MASK | S2MPS13_RTC_AUDR_MASK,
111};
112
113/* Register map for S2MPS11/14 */
114static const struct s5m_rtc_reg_config s2mps14_rtc_regs = {
115 .regs_count = 7,
116 .time = S2MPS_RTC_SEC,
117 .ctrl = S2MPS_RTC_CTRL,
118 .alarm0 = S2MPS_ALARM0_SEC,
119 .alarm1 = S2MPS_ALARM1_SEC,
120 .udr_update = S2MPS_RTC_UDR_CON,
121 .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK,
122 .read_time_udr_mask = S2MPS_RTC_RUDR_MASK,
123 .write_time_udr_mask = S2MPS_RTC_WUDR_MASK,
124 .write_alarm_udr_mask = S2MPS_RTC_WUDR_MASK | S2MPS_RTC_RUDR_MASK,
75}; 125};
76 126
77/* 127/*
78 * Register map for S2MPS14. 128 * Register map for S2MPS15 - in comparison to S2MPS14 the WUDR and AUDR bits
79 * It may be also suitable for S2MPS11 but this was not tested. 129 * are swapped.
80 */ 130 */
81static const struct s5m_rtc_reg_config s2mps_rtc_regs = { 131static const struct s5m_rtc_reg_config s2mps15_rtc_regs = {
82 .regs_count = 7, 132 .regs_count = 7,
83 .time = S2MPS_RTC_SEC, 133 .time = S2MPS_RTC_SEC,
84 .ctrl = S2MPS_RTC_CTRL, 134 .ctrl = S2MPS_RTC_CTRL,
@@ -86,7 +136,9 @@ static const struct s5m_rtc_reg_config s2mps_rtc_regs = {
86 .alarm1 = S2MPS_ALARM1_SEC, 136 .alarm1 = S2MPS_ALARM1_SEC,
87 .udr_update = S2MPS_RTC_UDR_CON, 137 .udr_update = S2MPS_RTC_UDR_CON,
88 .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK, 138 .autoclear_udr_mask = S2MPS_RTC_WUDR_MASK,
89 .udr_mask = S2MPS_RTC_WUDR_MASK, 139 .read_time_udr_mask = S2MPS_RTC_RUDR_MASK,
140 .write_time_udr_mask = S2MPS15_RTC_WUDR_MASK,
141 .write_alarm_udr_mask = S2MPS15_RTC_AUDR_MASK,
90}; 142};
91 143
92struct s5m_rtc_info { 144struct s5m_rtc_info {
@@ -223,21 +275,7 @@ static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info)
223 return ret; 275 return ret;
224 } 276 }
225 277
226 switch (info->device_type) { 278 data |= info->regs->write_time_udr_mask;
227 case S5M8763X:
228 case S5M8767X:
229 data |= info->regs->udr_mask | S5M_RTC_TIME_EN_MASK;
230 case S2MPS15X:
231 /* As per UM, for write time register, set WUDR bit to high */
232 data |= S2MPS15_RTC_WUDR_MASK;
233 break;
234 case S2MPS14X:
235 case S2MPS13X:
236 data |= info->regs->udr_mask;
237 break;
238 default:
239 return -EINVAL;
240 }
241 279
242 ret = regmap_write(info->regmap, info->regs->udr_update, data); 280 ret = regmap_write(info->regmap, info->regs->udr_update, data);
243 if (ret < 0) { 281 if (ret < 0) {
@@ -262,22 +300,16 @@ static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info)
262 return ret; 300 return ret;
263 } 301 }
264 302
265 data |= info->regs->udr_mask; 303 data |= info->regs->write_alarm_udr_mask;
266 switch (info->device_type) { 304 switch (info->device_type) {
267 case S5M8763X: 305 case S5M8763X:
268 case S5M8767X: 306 case S5M8767X:
269 data &= ~S5M_RTC_TIME_EN_MASK; 307 data &= ~S5M_RTC_TIME_EN_MASK;
270 break; 308 break;
271 case S2MPS15X: 309 case S2MPS15X:
272 /* As per UM, for write alarm, set A_UDR(bit[4]) to high
273 * udr_mask above sets bit[4]
274 */
275 break;
276 case S2MPS14X: 310 case S2MPS14X:
277 data |= S2MPS_RTC_RUDR_MASK;
278 break;
279 case S2MPS13X: 311 case S2MPS13X:
280 data |= S2MPS13_RTC_AUDR_MASK; 312 /* No exceptions needed */
281 break; 313 break;
282 default: 314 default:
283 return -EINVAL; 315 return -EINVAL;
@@ -338,11 +370,11 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm)
338 u8 data[info->regs->regs_count]; 370 u8 data[info->regs->regs_count];
339 int ret; 371 int ret;
340 372
341 if (info->device_type == S2MPS15X || info->device_type == S2MPS14X || 373 if (info->regs->read_time_udr_mask) {
342 info->device_type == S2MPS13X) {
343 ret = regmap_update_bits(info->regmap, 374 ret = regmap_update_bits(info->regmap,
344 info->regs->udr_update, 375 info->regs->udr_update,
345 S2MPS_RTC_RUDR_MASK, S2MPS_RTC_RUDR_MASK); 376 info->regs->read_time_udr_mask,
377 info->regs->read_time_udr_mask);
346 if (ret) { 378 if (ret) {
347 dev_err(dev, 379 dev_err(dev,
348 "Failed to prepare registers for time reading: %d\n", 380 "Failed to prepare registers for time reading: %d\n",
@@ -709,10 +741,18 @@ static int s5m_rtc_probe(struct platform_device *pdev)
709 741
710 switch (platform_get_device_id(pdev)->driver_data) { 742 switch (platform_get_device_id(pdev)->driver_data) {
711 case S2MPS15X: 743 case S2MPS15X:
744 regmap_cfg = &s2mps14_rtc_regmap_config;
745 info->regs = &s2mps15_rtc_regs;
746 alarm_irq = S2MPS14_IRQ_RTCA0;
747 break;
712 case S2MPS14X: 748 case S2MPS14X:
749 regmap_cfg = &s2mps14_rtc_regmap_config;
750 info->regs = &s2mps14_rtc_regs;
751 alarm_irq = S2MPS14_IRQ_RTCA0;
752 break;
713 case S2MPS13X: 753 case S2MPS13X:
714 regmap_cfg = &s2mps14_rtc_regmap_config; 754 regmap_cfg = &s2mps14_rtc_regmap_config;
715 info->regs = &s2mps_rtc_regs; 755 info->regs = &s2mps13_rtc_regs;
716 alarm_irq = S2MPS14_IRQ_RTCA0; 756 alarm_irq = S2MPS14_IRQ_RTCA0;
717 break; 757 break;
718 case S5M8763X: 758 case S5M8763X:
diff --git a/include/linux/mfd/samsung/rtc.h b/include/linux/mfd/samsung/rtc.h
index a65e4655d470..48c3c5be7eb1 100644
--- a/include/linux/mfd/samsung/rtc.h
+++ b/include/linux/mfd/samsung/rtc.h
@@ -105,6 +105,8 @@ enum s2mps_rtc_reg {
105#define S5M_RTC_UDR_MASK (1 << S5M_RTC_UDR_SHIFT) 105#define S5M_RTC_UDR_MASK (1 << S5M_RTC_UDR_SHIFT)
106#define S2MPS_RTC_WUDR_SHIFT 4 106#define S2MPS_RTC_WUDR_SHIFT 4
107#define S2MPS_RTC_WUDR_MASK (1 << S2MPS_RTC_WUDR_SHIFT) 107#define S2MPS_RTC_WUDR_MASK (1 << S2MPS_RTC_WUDR_SHIFT)
108#define S2MPS15_RTC_AUDR_SHIFT 4
109#define S2MPS15_RTC_AUDR_MASK (1 << S2MPS15_RTC_AUDR_SHIFT)
108#define S2MPS13_RTC_AUDR_SHIFT 1 110#define S2MPS13_RTC_AUDR_SHIFT 1
109#define S2MPS13_RTC_AUDR_MASK (1 << S2MPS13_RTC_AUDR_SHIFT) 111#define S2MPS13_RTC_AUDR_MASK (1 << S2MPS13_RTC_AUDR_SHIFT)
110#define S2MPS15_RTC_WUDR_SHIFT 1 112#define S2MPS15_RTC_WUDR_SHIFT 1