|
18 | 18 | #include <linux/platform_device.h> |
19 | 19 | #include <linux/reboot.h> |
20 | 20 | #include <linux/reset-controller.h> |
| 21 | +#include <linux/power/power_on_reason.h> |
21 | 22 |
|
22 | 23 | #include <soc/at91/at91sam9_ddrsdr.h> |
23 | 24 | #include <soc/at91/at91sam9_sdramc.h> |
@@ -149,44 +150,54 @@ static int at91_reset(struct notifier_block *this, unsigned long mode, |
149 | 150 | return NOTIFY_DONE; |
150 | 151 | } |
151 | 152 |
|
152 | | -static const char * __init at91_reset_reason(struct at91_reset *reset) |
| 153 | +static const char *at91_reset_reason(struct at91_reset *reset) |
153 | 154 | { |
154 | 155 | u32 reg = readl(reset->rstc_base + AT91_RSTC_SR); |
155 | 156 | const char *reason; |
156 | 157 |
|
157 | 158 | switch ((reg & AT91_RSTC_RSTTYP) >> 8) { |
158 | 159 | case RESET_TYPE_GENERAL: |
159 | | - reason = "general reset"; |
| 160 | + reason = POWER_ON_REASON_REGULAR; |
160 | 161 | break; |
161 | 162 | case RESET_TYPE_WAKEUP: |
162 | | - reason = "wakeup"; |
| 163 | + reason = POWER_ON_REASON_RTC; |
163 | 164 | break; |
164 | 165 | case RESET_TYPE_WATCHDOG: |
165 | | - reason = "watchdog reset"; |
| 166 | + reason = POWER_ON_REASON_WATCHDOG; |
166 | 167 | break; |
167 | 168 | case RESET_TYPE_SOFTWARE: |
168 | | - reason = "software reset"; |
| 169 | + reason = POWER_ON_REASON_SOFTWARE; |
169 | 170 | break; |
170 | 171 | case RESET_TYPE_USER: |
171 | | - reason = "user reset"; |
| 172 | + reason = POWER_ON_REASON_RST_BTN; |
172 | 173 | break; |
173 | 174 | case RESET_TYPE_CPU_FAIL: |
174 | | - reason = "CPU clock failure detection"; |
| 175 | + reason = POWER_ON_REASON_CPU_CLK_FAIL; |
175 | 176 | break; |
176 | 177 | case RESET_TYPE_XTAL_FAIL: |
177 | | - reason = "32.768 kHz crystal failure detection"; |
| 178 | + reason = POWER_ON_REASON_XTAL_FAIL; |
178 | 179 | break; |
179 | 180 | case RESET_TYPE_ULP2: |
180 | | - reason = "ULP2 reset"; |
| 181 | + reason = POWER_ON_REASON_BROWN_OUT; |
181 | 182 | break; |
182 | 183 | default: |
183 | | - reason = "unknown reset"; |
| 184 | + reason = POWER_ON_REASON_UNKNOWN; |
184 | 185 | break; |
185 | 186 | } |
186 | 187 |
|
187 | 188 | return reason; |
188 | 189 | } |
189 | 190 |
|
| 191 | +static ssize_t power_on_reason_show(struct device *dev, |
| 192 | + struct device_attribute *attr, char *buf) |
| 193 | +{ |
| 194 | + struct platform_device *pdev = to_platform_device(dev); |
| 195 | + struct at91_reset *reset = platform_get_drvdata(pdev); |
| 196 | + |
| 197 | + return sprintf(buf, "%s\n", at91_reset_reason(reset)); |
| 198 | +} |
| 199 | +static DEVICE_ATTR_RO(power_on_reason); |
| 200 | + |
190 | 201 | static const struct of_device_id at91_ramc_of_match[] = { |
191 | 202 | { |
192 | 203 | .compatible = "atmel,at91sam9260-sdramc", |
@@ -391,6 +402,12 @@ static int __init at91_reset_probe(struct platform_device *pdev) |
391 | 402 | if (ret) |
392 | 403 | goto disable_clk; |
393 | 404 |
|
| 405 | + ret = device_create_file(&pdev->dev, &dev_attr_power_on_reason); |
| 406 | + if (ret) { |
| 407 | + dev_err(&pdev->dev, "Could not create sysfs entry\n"); |
| 408 | + return ret; |
| 409 | + } |
| 410 | + |
394 | 411 | dev_info(&pdev->dev, "Starting after %s\n", at91_reset_reason(reset)); |
395 | 412 |
|
396 | 413 | return 0; |
|
0 commit comments