blob: 0c150f3cf408924f2e1502e58005c0217c83dced [file] [log] [blame]
Thomas Gleixnerc942fdd2019-05-27 08:55:06 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Martyn Welch2a7b7532015-12-01 15:32:47 +00002/*
3 * Copyright (C) 2015 Zodiac Inflight Innovations
4 *
5 * Author: Martyn Welch <martyn.welch@collabora.co.uk>
6 *
7 * Based on twl4030_wdt.c by Timo Kokkonen <timo.t.kokkonen at nokia.com>:
8 *
9 * Copyright (C) Nokia Corporation
Martyn Welch2a7b7532015-12-01 15:32:47 +000010 */
11
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +020012#include <linux/delay.h>
Martyn Welch2a7b7532015-12-01 15:32:47 +000013#include <linux/i2c.h>
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +020014#include <linux/ihex.h>
15#include <linux/firmware.h>
Martyn Welch2a7b7532015-12-01 15:32:47 +000016#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/slab.h>
19#include <linux/sysfs.h>
20#include <linux/types.h>
21#include <linux/version.h>
22#include <linux/watchdog.h>
23
Andrey Smirnov08f980a2019-08-12 13:08:55 -070024#include <asm/unaligned.h>
25
Martyn Welch2a7b7532015-12-01 15:32:47 +000026#define ZIIRAVE_TIMEOUT_MIN 3
27#define ZIIRAVE_TIMEOUT_MAX 255
Andrey Smirnov39d03872019-08-12 13:08:48 -070028#define ZIIRAVE_TIMEOUT_DEFAULT 30
Martyn Welch2a7b7532015-12-01 15:32:47 +000029
30#define ZIIRAVE_PING_VALUE 0x0
31
32#define ZIIRAVE_STATE_INITIAL 0x0
33#define ZIIRAVE_STATE_OFF 0x1
34#define ZIIRAVE_STATE_ON 0x2
35
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +020036#define ZIIRAVE_FW_NAME "ziirave_wdt.fw"
37
Martyn Welch0ce72f32016-02-26 16:05:12 +000038static char *ziirave_reasons[] = {"power cycle", "hw watchdog", NULL, NULL,
Martyn Welch2a7b7532015-12-01 15:32:47 +000039 "host request", NULL, "illegal configuration",
40 "illegal instruction", "illegal trap",
41 "unknown"};
42
43#define ZIIRAVE_WDT_FIRM_VER_MAJOR 0x1
44#define ZIIRAVE_WDT_BOOT_VER_MAJOR 0x3
45#define ZIIRAVE_WDT_RESET_REASON 0x5
46#define ZIIRAVE_WDT_STATE 0x6
47#define ZIIRAVE_WDT_TIMEOUT 0x7
48#define ZIIRAVE_WDT_TIME_LEFT 0x8
49#define ZIIRAVE_WDT_PING 0x9
50#define ZIIRAVE_WDT_RESET_DURATION 0xa
51
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +020052#define ZIIRAVE_FIRM_PKT_TOTAL_SIZE 20
53#define ZIIRAVE_FIRM_PKT_DATA_SIZE 16
Andrey Smirnovd2ddc4502019-08-12 13:08:58 -070054#define ZIIRAVE_FIRM_FLASH_MEMORY_START (2 * 0x1600)
55#define ZIIRAVE_FIRM_FLASH_MEMORY_END (2 * 0x2bbf)
Andrey Smirnov5870f492019-08-12 13:08:50 -070056#define ZIIRAVE_FIRM_PAGE_SIZE 128
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +020057
58/* Received and ready for next Download packet. */
59#define ZIIRAVE_FIRM_DOWNLOAD_ACK 1
60/* Currently writing to flash. Retry Download status in a moment! */
61#define ZIIRAVE_FIRM_DOWNLOAD_BUSY 2
62
63/* Wait for ACK timeout in ms */
64#define ZIIRAVE_FIRM_WAIT_FOR_ACK_TIMEOUT 50
65
66/* Firmware commands */
67#define ZIIRAVE_CMD_DOWNLOAD_START 0x10
68#define ZIIRAVE_CMD_DOWNLOAD_END 0x11
69#define ZIIRAVE_CMD_DOWNLOAD_SET_READ_ADDR 0x12
70#define ZIIRAVE_CMD_DOWNLOAD_READ_BYTE 0x13
71#define ZIIRAVE_CMD_RESET_PROCESSOR 0x0b
72#define ZIIRAVE_CMD_JUMP_TO_BOOTLOADER 0x0c
73#define ZIIRAVE_CMD_DOWNLOAD_PACKET 0x0e
74
Andrey Smirnov42abc122019-08-12 13:08:49 -070075#define ZIIRAVE_FW_VERSION_FMT "02.%02u.%02u"
76#define ZIIRAVE_BL_VERSION_FMT "01.%02u.%02u"
77
Martyn Welch2a7b7532015-12-01 15:32:47 +000078struct ziirave_wdt_rev {
79 unsigned char major;
80 unsigned char minor;
81};
82
83struct ziirave_wdt_data {
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +020084 struct mutex sysfs_mutex;
Martyn Welch2a7b7532015-12-01 15:32:47 +000085 struct watchdog_device wdd;
86 struct ziirave_wdt_rev bootloader_rev;
87 struct ziirave_wdt_rev firmware_rev;
88 int reset_reason;
89};
90
91static int wdt_timeout;
92module_param(wdt_timeout, int, 0);
93MODULE_PARM_DESC(wdt_timeout, "Watchdog timeout in seconds");
94
95static int reset_duration;
96module_param(reset_duration, int, 0);
97MODULE_PARM_DESC(reset_duration,
98 "Watchdog reset pulse duration in milliseconds");
99
100static bool nowayout = WATCHDOG_NOWAYOUT;
101module_param(nowayout, bool, 0);
102MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started default="
103 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
104
105static int ziirave_wdt_revision(struct i2c_client *client,
106 struct ziirave_wdt_rev *rev, u8 command)
107{
108 int ret;
109
110 ret = i2c_smbus_read_byte_data(client, command);
111 if (ret < 0)
112 return ret;
113
114 rev->major = ret;
115
116 ret = i2c_smbus_read_byte_data(client, command + 1);
117 if (ret < 0)
118 return ret;
119
120 rev->minor = ret;
121
122 return 0;
123}
124
125static int ziirave_wdt_set_state(struct watchdog_device *wdd, int state)
126{
127 struct i2c_client *client = to_i2c_client(wdd->parent);
128
129 return i2c_smbus_write_byte_data(client, ZIIRAVE_WDT_STATE, state);
130}
131
132static int ziirave_wdt_start(struct watchdog_device *wdd)
133{
134 return ziirave_wdt_set_state(wdd, ZIIRAVE_STATE_ON);
135}
136
137static int ziirave_wdt_stop(struct watchdog_device *wdd)
138{
139 return ziirave_wdt_set_state(wdd, ZIIRAVE_STATE_OFF);
140}
141
142static int ziirave_wdt_ping(struct watchdog_device *wdd)
143{
144 struct i2c_client *client = to_i2c_client(wdd->parent);
145
146 return i2c_smbus_write_byte_data(client, ZIIRAVE_WDT_PING,
147 ZIIRAVE_PING_VALUE);
148}
149
150static int ziirave_wdt_set_timeout(struct watchdog_device *wdd,
151 unsigned int timeout)
152{
153 struct i2c_client *client = to_i2c_client(wdd->parent);
154 int ret;
155
156 ret = i2c_smbus_write_byte_data(client, ZIIRAVE_WDT_TIMEOUT, timeout);
157 if (!ret)
158 wdd->timeout = timeout;
159
160 return ret;
161}
162
163static unsigned int ziirave_wdt_get_timeleft(struct watchdog_device *wdd)
164{
165 struct i2c_client *client = to_i2c_client(wdd->parent);
166 int ret;
167
168 ret = i2c_smbus_read_byte_data(client, ZIIRAVE_WDT_TIME_LEFT);
169 if (ret < 0)
170 ret = 0;
171
172 return ret;
173}
174
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200175static int ziirave_firm_wait_for_ack(struct watchdog_device *wdd)
176{
177 struct i2c_client *client = to_i2c_client(wdd->parent);
178 int ret;
179 unsigned long timeout;
180
181 timeout = jiffies + msecs_to_jiffies(ZIIRAVE_FIRM_WAIT_FOR_ACK_TIMEOUT);
182 do {
183 if (time_after(jiffies, timeout))
184 return -ETIMEDOUT;
185
186 usleep_range(5000, 10000);
187
188 ret = i2c_smbus_read_byte(client);
189 if (ret < 0) {
190 dev_err(&client->dev, "Failed to read byte\n");
191 return ret;
192 }
193 } while (ret == ZIIRAVE_FIRM_DOWNLOAD_BUSY);
194
195 return ret == ZIIRAVE_FIRM_DOWNLOAD_ACK ? 0 : -EIO;
196}
197
Andrey Smirnovd2ddc4502019-08-12 13:08:58 -0700198static int ziirave_firm_set_read_addr(struct watchdog_device *wdd, u32 addr)
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200199{
200 struct i2c_client *client = to_i2c_client(wdd->parent);
Andrey Smirnovd2ddc4502019-08-12 13:08:58 -0700201 const u16 addr16 = (u16)addr / 2;
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200202 u8 address[2];
203
Andrey Smirnovd2ddc4502019-08-12 13:08:58 -0700204 put_unaligned_le16(addr16, address);
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200205
206 return i2c_smbus_write_block_data(client,
207 ZIIRAVE_CMD_DOWNLOAD_SET_READ_ADDR,
Andrey Smirnove6bd4482019-08-12 13:08:53 -0700208 sizeof(address), address);
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200209}
210
211static int ziirave_firm_write_block_data(struct watchdog_device *wdd,
212 u8 command, u8 length, const u8 *data,
213 bool wait_for_ack)
214{
215 struct i2c_client *client = to_i2c_client(wdd->parent);
216 int ret;
217
218 ret = i2c_smbus_write_block_data(client, command, length, data);
219 if (ret) {
220 dev_err(&client->dev,
221 "Failed to send command 0x%02x: %d\n", command, ret);
222 return ret;
223 }
224
225 if (wait_for_ack)
226 ret = ziirave_firm_wait_for_ack(wdd);
227
228 return ret;
229}
230
231static int ziirave_firm_write_byte(struct watchdog_device *wdd, u8 command,
232 u8 byte, bool wait_for_ack)
233{
234 return ziirave_firm_write_block_data(wdd, command, 1, &byte,
235 wait_for_ack);
236}
237
Andrey Smirnovd2ddc4502019-08-12 13:08:58 -0700238static bool ziirave_firm_addr_readonly(u32 addr)
239{
240 return addr < ZIIRAVE_FIRM_FLASH_MEMORY_START ||
241 addr > ZIIRAVE_FIRM_FLASH_MEMORY_END;
242}
243
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200244/*
245 * ziirave_firm_write_pkt() - Build and write a firmware packet
246 *
247 * A packet to send to the firmware is composed by following bytes:
248 * Length | Addr0 | Addr1 | Data0 .. Data15 | Checksum |
249 * Where,
250 * Length: A data byte containing the length of the data.
251 * Addr0: Low byte of the address.
252 * Addr1: High byte of the address.
253 * Data0 .. Data15: Array of 16 bytes of data.
254 * Checksum: Checksum byte to verify data integrity.
255 */
Andrey Smirnov5870f492019-08-12 13:08:50 -0700256static int __ziirave_firm_write_pkt(struct watchdog_device *wdd,
257 u32 addr, const u8 *data, u8 len)
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200258{
Andrey Smirnov5870f492019-08-12 13:08:50 -0700259 const u16 addr16 = (u16)addr / 2;
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200260 struct i2c_client *client = to_i2c_client(wdd->parent);
261 u8 i, checksum = 0, packet[ZIIRAVE_FIRM_PKT_TOTAL_SIZE];
262 int ret;
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200263
Andrey Smirnov08188e82019-08-12 13:08:51 -0700264 /* Check max data size */
265 if (len > ZIIRAVE_FIRM_PKT_DATA_SIZE) {
266 dev_err(&client->dev, "Firmware packet too long (%d)\n",
267 len);
268 return -EMSGSIZE;
269 }
270
Andrey Smirnovd2ddc4502019-08-12 13:08:58 -0700271 /*
272 * Ignore packets that are targeting program memory outisde of
273 * app partition, since they will be ignored by the
274 * bootloader. At the same time, we need to make sure we'll
275 * allow zero length packet that will be sent as the last step
276 * of firmware update
277 */
278 if (len && ziirave_firm_addr_readonly(addr))
279 return 0;
280
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200281 /* Packet length */
Andrey Smirnov5870f492019-08-12 13:08:50 -0700282 packet[0] = len;
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200283 /* Packet address */
Andrey Smirnov08f980a2019-08-12 13:08:55 -0700284 put_unaligned_le16(addr16, packet + 1);
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200285
Andrey Smirnov5870f492019-08-12 13:08:50 -0700286 memcpy(packet + 3, data, len);
Andrey Smirnov10f98fe2019-08-12 13:08:54 -0700287 memset(packet + 3 + len, 0, ZIIRAVE_FIRM_PKT_DATA_SIZE - len);
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200288
289 /* Packet checksum */
Andrey Smirnovdc0dd282019-08-12 13:08:52 -0700290 for (i = 0; i < len + 3; i++)
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200291 checksum += packet[i];
292 packet[ZIIRAVE_FIRM_PKT_TOTAL_SIZE - 1] = checksum;
293
294 ret = ziirave_firm_write_block_data(wdd, ZIIRAVE_CMD_DOWNLOAD_PACKET,
Andrey Smirnove6bd4482019-08-12 13:08:53 -0700295 sizeof(packet), packet, true);
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200296 if (ret)
297 dev_err(&client->dev,
298 "Failed to write firmware packet at address 0x%04x: %d\n",
Andrey Smirnovd2ddc4502019-08-12 13:08:58 -0700299 addr, ret);
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200300
301 return ret;
302}
303
Andrey Smirnov5870f492019-08-12 13:08:50 -0700304static int ziirave_firm_write_pkt(struct watchdog_device *wdd,
305 u32 addr, const u8 *data, u8 len)
306{
307 const u8 max_write_len = ZIIRAVE_FIRM_PAGE_SIZE -
308 (addr - ALIGN_DOWN(addr, ZIIRAVE_FIRM_PAGE_SIZE));
309 int ret;
310
311 if (len > max_write_len) {
312 /*
313 * If data crossed page boundary we need to split this
314 * write in two
315 */
316 ret = __ziirave_firm_write_pkt(wdd, addr, data, max_write_len);
317 if (ret)
318 return ret;
319
320 addr += max_write_len;
321 data += max_write_len;
322 len -= max_write_len;
323 }
324
325 return __ziirave_firm_write_pkt(wdd, addr, data, len);
326}
327
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200328static int ziirave_firm_verify(struct watchdog_device *wdd,
329 const struct firmware *fw)
330{
331 struct i2c_client *client = to_i2c_client(wdd->parent);
332 const struct ihex_binrec *rec;
333 int i, ret;
334 u8 data[ZIIRAVE_FIRM_PKT_DATA_SIZE];
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200335
336 for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) {
Andrey Smirnovde880532019-08-12 13:08:57 -0700337 const u16 len = be16_to_cpu(rec->len);
Andrey Smirnovd2ddc4502019-08-12 13:08:58 -0700338 const u32 addr = be32_to_cpu(rec->addr);
Andrey Smirnovde880532019-08-12 13:08:57 -0700339
Andrey Smirnovd2ddc4502019-08-12 13:08:58 -0700340 if (ziirave_firm_addr_readonly(addr))
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200341 continue;
342
343 ret = ziirave_firm_set_read_addr(wdd, addr);
344 if (ret) {
345 dev_err(&client->dev,
346 "Failed to send SET_READ_ADDR command: %d\n",
347 ret);
348 return ret;
349 }
350
Andrey Smirnovde880532019-08-12 13:08:57 -0700351 for (i = 0; i < len; i++) {
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200352 ret = i2c_smbus_read_byte_data(client,
353 ZIIRAVE_CMD_DOWNLOAD_READ_BYTE);
354 if (ret < 0) {
355 dev_err(&client->dev,
356 "Failed to READ DATA: %d\n", ret);
357 return ret;
358 }
359 data[i] = ret;
360 }
361
Andrey Smirnovde880532019-08-12 13:08:57 -0700362 if (memcmp(data, rec->data, len)) {
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200363 dev_err(&client->dev,
364 "Firmware mismatch at address 0x%04x\n", addr);
365 return -EINVAL;
366 }
367 }
368
369 return 0;
370}
371
372static int ziirave_firm_upload(struct watchdog_device *wdd,
373 const struct firmware *fw)
374{
375 struct i2c_client *client = to_i2c_client(wdd->parent);
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200376 const struct ihex_binrec *rec;
Andrey Smirnov5870f492019-08-12 13:08:50 -0700377 int ret;
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200378
379 ret = ziirave_firm_write_byte(wdd, ZIIRAVE_CMD_JUMP_TO_BOOTLOADER, 1,
380 false);
Andrey Smirnovb774fce2019-08-12 13:08:47 -0700381 if (ret) {
382 dev_err(&client->dev, "Failed to jump to bootloader\n");
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200383 return ret;
Andrey Smirnovb774fce2019-08-12 13:08:47 -0700384 }
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200385
386 msleep(500);
387
388 ret = ziirave_firm_write_byte(wdd, ZIIRAVE_CMD_DOWNLOAD_START, 1, true);
Andrey Smirnovb774fce2019-08-12 13:08:47 -0700389 if (ret) {
390 dev_err(&client->dev, "Failed to start download\n");
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200391 return ret;
Andrey Smirnovb774fce2019-08-12 13:08:47 -0700392 }
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200393
394 msleep(500);
395
396 for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) {
Andrey Smirnov5870f492019-08-12 13:08:50 -0700397 ret = ziirave_firm_write_pkt(wdd, be32_to_cpu(rec->addr),
398 rec->data, be16_to_cpu(rec->len));
399 if (ret)
400 return ret;
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200401 }
402
Andrey Smirnov5870f492019-08-12 13:08:50 -0700403 /*
404 * Finish firmware download process by sending a zero length
405 * payload
406 */
407 ret = ziirave_firm_write_pkt(wdd, 0, NULL, 0);
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200408 if (ret) {
409 dev_err(&client->dev, "Failed to send EMPTY packet: %d\n", ret);
410 return ret;
411 }
412
413 /* This sleep seems to be required */
414 msleep(20);
415
416 /* Start firmware verification */
417 ret = ziirave_firm_verify(wdd, fw);
418 if (ret) {
419 dev_err(&client->dev,
420 "Failed to verify firmware: %d\n", ret);
421 return ret;
422 }
423
424 /* End download operation */
425 ret = ziirave_firm_write_byte(wdd, ZIIRAVE_CMD_DOWNLOAD_END, 1, false);
Andrey Smirnovb774fce2019-08-12 13:08:47 -0700426 if (ret) {
427 dev_err(&client->dev,
428 "Failed to end firmware download: %d\n", ret);
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200429 return ret;
Andrey Smirnovb774fce2019-08-12 13:08:47 -0700430 }
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200431
432 /* Reset the processor */
433 ret = ziirave_firm_write_byte(wdd, ZIIRAVE_CMD_RESET_PROCESSOR, 1,
434 false);
Andrey Smirnovb774fce2019-08-12 13:08:47 -0700435 if (ret) {
436 dev_err(&client->dev,
437 "Failed to reset the watchdog: %d\n", ret);
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200438 return ret;
Andrey Smirnovb774fce2019-08-12 13:08:47 -0700439 }
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200440
441 msleep(500);
442
443 return 0;
444}
445
Martyn Welch2a7b7532015-12-01 15:32:47 +0000446static const struct watchdog_info ziirave_wdt_info = {
447 .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
448 .identity = "Zodiac RAVE Watchdog",
449};
450
451static const struct watchdog_ops ziirave_wdt_ops = {
452 .owner = THIS_MODULE,
453 .start = ziirave_wdt_start,
454 .stop = ziirave_wdt_stop,
455 .ping = ziirave_wdt_ping,
456 .set_timeout = ziirave_wdt_set_timeout,
457 .get_timeleft = ziirave_wdt_get_timeleft,
458};
459
460static ssize_t ziirave_wdt_sysfs_show_firm(struct device *dev,
461 struct device_attribute *attr,
462 char *buf)
463{
464 struct i2c_client *client = to_i2c_client(dev->parent);
465 struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client);
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200466 int ret;
Martyn Welch2a7b7532015-12-01 15:32:47 +0000467
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200468 ret = mutex_lock_interruptible(&w_priv->sysfs_mutex);
469 if (ret)
470 return ret;
471
Andrey Smirnov42abc122019-08-12 13:08:49 -0700472 ret = sprintf(buf, ZIIRAVE_FW_VERSION_FMT, w_priv->firmware_rev.major,
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200473 w_priv->firmware_rev.minor);
474
475 mutex_unlock(&w_priv->sysfs_mutex);
476
477 return ret;
Martyn Welch2a7b7532015-12-01 15:32:47 +0000478}
479
480static DEVICE_ATTR(firmware_version, S_IRUGO, ziirave_wdt_sysfs_show_firm,
481 NULL);
482
483static ssize_t ziirave_wdt_sysfs_show_boot(struct device *dev,
484 struct device_attribute *attr,
485 char *buf)
486{
487 struct i2c_client *client = to_i2c_client(dev->parent);
488 struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client);
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200489 int ret;
Martyn Welch2a7b7532015-12-01 15:32:47 +0000490
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200491 ret = mutex_lock_interruptible(&w_priv->sysfs_mutex);
492 if (ret)
493 return ret;
494
Andrey Smirnov42abc122019-08-12 13:08:49 -0700495 ret = sprintf(buf, ZIIRAVE_BL_VERSION_FMT, w_priv->bootloader_rev.major,
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200496 w_priv->bootloader_rev.minor);
497
498 mutex_unlock(&w_priv->sysfs_mutex);
499
500 return ret;
Martyn Welch2a7b7532015-12-01 15:32:47 +0000501}
502
503static DEVICE_ATTR(bootloader_version, S_IRUGO, ziirave_wdt_sysfs_show_boot,
504 NULL);
505
506static ssize_t ziirave_wdt_sysfs_show_reason(struct device *dev,
507 struct device_attribute *attr,
508 char *buf)
509{
510 struct i2c_client *client = to_i2c_client(dev->parent);
511 struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client);
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200512 int ret;
Martyn Welch2a7b7532015-12-01 15:32:47 +0000513
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200514 ret = mutex_lock_interruptible(&w_priv->sysfs_mutex);
515 if (ret)
516 return ret;
517
518 ret = sprintf(buf, "%s", ziirave_reasons[w_priv->reset_reason]);
519
520 mutex_unlock(&w_priv->sysfs_mutex);
521
522 return ret;
Martyn Welch2a7b7532015-12-01 15:32:47 +0000523}
524
525static DEVICE_ATTR(reset_reason, S_IRUGO, ziirave_wdt_sysfs_show_reason,
526 NULL);
527
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200528static ssize_t ziirave_wdt_sysfs_store_firm(struct device *dev,
529 struct device_attribute *attr,
530 const char *buf, size_t count)
531{
532 struct i2c_client *client = to_i2c_client(dev->parent);
533 struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client);
534 const struct firmware *fw;
535 int err;
536
537 err = request_ihex_firmware(&fw, ZIIRAVE_FW_NAME, dev);
538 if (err) {
539 dev_err(&client->dev, "Failed to request ihex firmware\n");
540 return err;
541 }
542
543 err = mutex_lock_interruptible(&w_priv->sysfs_mutex);
544 if (err)
545 goto release_firmware;
546
547 err = ziirave_firm_upload(&w_priv->wdd, fw);
548 if (err) {
549 dev_err(&client->dev, "The firmware update failed: %d\n", err);
550 goto unlock_mutex;
551 }
552
553 /* Update firmware version */
554 err = ziirave_wdt_revision(client, &w_priv->firmware_rev,
555 ZIIRAVE_WDT_FIRM_VER_MAJOR);
556 if (err) {
557 dev_err(&client->dev, "Failed to read firmware version: %d\n",
558 err);
559 goto unlock_mutex;
560 }
561
Andrey Smirnov42abc122019-08-12 13:08:49 -0700562 dev_info(&client->dev,
563 "Firmware updated to version " ZIIRAVE_FW_VERSION_FMT "\n",
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200564 w_priv->firmware_rev.major, w_priv->firmware_rev.minor);
565
566 /* Restore the watchdog timeout */
567 err = ziirave_wdt_set_timeout(&w_priv->wdd, w_priv->wdd.timeout);
568 if (err)
569 dev_err(&client->dev, "Failed to set timeout: %d\n", err);
570
571unlock_mutex:
572 mutex_unlock(&w_priv->sysfs_mutex);
573
574release_firmware:
575 release_firmware(fw);
576
577 return err ? err : count;
578}
579
580static DEVICE_ATTR(update_firmware, S_IWUSR, NULL,
581 ziirave_wdt_sysfs_store_firm);
582
Martyn Welch2a7b7532015-12-01 15:32:47 +0000583static struct attribute *ziirave_wdt_attrs[] = {
584 &dev_attr_firmware_version.attr,
585 &dev_attr_bootloader_version.attr,
586 &dev_attr_reset_reason.attr,
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200587 &dev_attr_update_firmware.attr,
Martyn Welch2a7b7532015-12-01 15:32:47 +0000588 NULL
589};
Guenter Roeck2c2f3082016-01-03 15:11:57 -0800590ATTRIBUTE_GROUPS(ziirave_wdt);
Martyn Welch2a7b7532015-12-01 15:32:47 +0000591
592static int ziirave_wdt_init_duration(struct i2c_client *client)
593{
594 int ret;
595
596 if (!reset_duration) {
597 /* See if the reset pulse duration is provided in an of_node */
598 if (!client->dev.of_node)
599 ret = -ENODEV;
600 else
601 ret = of_property_read_u32(client->dev.of_node,
602 "reset-duration-ms",
603 &reset_duration);
604 if (ret) {
605 dev_info(&client->dev,
Andrey Smirnovd2c1d422019-08-12 13:08:59 -0700606 "No reset pulse duration specified, using default\n");
Martyn Welch2a7b7532015-12-01 15:32:47 +0000607 return 0;
608 }
609 }
610
611 if (reset_duration < 1 || reset_duration > 255)
612 return -EINVAL;
613
614 dev_info(&client->dev, "Setting reset duration to %dms",
615 reset_duration);
616
617 return i2c_smbus_write_byte_data(client, ZIIRAVE_WDT_RESET_DURATION,
618 reset_duration);
619}
620
621static int ziirave_wdt_probe(struct i2c_client *client,
622 const struct i2c_device_id *id)
623{
624 int ret;
625 struct ziirave_wdt_data *w_priv;
626 int val;
627
628 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
629 return -ENODEV;
630
631 w_priv = devm_kzalloc(&client->dev, sizeof(*w_priv), GFP_KERNEL);
632 if (!w_priv)
633 return -ENOMEM;
634
Enric Balletbo i Serra217209d2016-08-10 18:18:03 +0200635 mutex_init(&w_priv->sysfs_mutex);
636
Martyn Welch2a7b7532015-12-01 15:32:47 +0000637 w_priv->wdd.info = &ziirave_wdt_info;
638 w_priv->wdd.ops = &ziirave_wdt_ops;
639 w_priv->wdd.min_timeout = ZIIRAVE_TIMEOUT_MIN;
640 w_priv->wdd.max_timeout = ZIIRAVE_TIMEOUT_MAX;
641 w_priv->wdd.parent = &client->dev;
Guenter Roeck2c2f3082016-01-03 15:11:57 -0800642 w_priv->wdd.groups = ziirave_wdt_groups;
Martyn Welch2a7b7532015-12-01 15:32:47 +0000643
Wolfram Sang15451162019-04-19 20:16:01 +0200644 watchdog_init_timeout(&w_priv->wdd, wdt_timeout, &client->dev);
Martyn Welch2a7b7532015-12-01 15:32:47 +0000645
646 /*
647 * The default value set in the watchdog should be perfectly valid, so
648 * pass that in if we haven't provided one via the module parameter or
649 * of property.
650 */
651 if (w_priv->wdd.timeout == 0) {
652 val = i2c_smbus_read_byte_data(client, ZIIRAVE_WDT_TIMEOUT);
Andrey Smirnov4a9600c2019-08-12 13:08:46 -0700653 if (val < 0) {
654 dev_err(&client->dev, "Failed to read timeout\n");
Martyn Welch2a7b7532015-12-01 15:32:47 +0000655 return val;
Andrey Smirnov4a9600c2019-08-12 13:08:46 -0700656 }
Martyn Welch2a7b7532015-12-01 15:32:47 +0000657
Andrey Smirnov39d03872019-08-12 13:08:48 -0700658 if (val > ZIIRAVE_TIMEOUT_MAX ||
659 val < ZIIRAVE_TIMEOUT_MIN)
660 val = ZIIRAVE_TIMEOUT_DEFAULT;
Martyn Welch2a7b7532015-12-01 15:32:47 +0000661
662 w_priv->wdd.timeout = val;
Martyn Welch2a7b7532015-12-01 15:32:47 +0000663 }
664
Andrey Smirnov39d03872019-08-12 13:08:48 -0700665 ret = ziirave_wdt_set_timeout(&w_priv->wdd, w_priv->wdd.timeout);
666 if (ret) {
667 dev_err(&client->dev, "Failed to set timeout\n");
668 return ret;
669 }
670
671 dev_info(&client->dev, "Timeout set to %ds\n", w_priv->wdd.timeout);
672
Martyn Welch2a7b7532015-12-01 15:32:47 +0000673 watchdog_set_nowayout(&w_priv->wdd, nowayout);
674
675 i2c_set_clientdata(client, w_priv);
676
677 /* If in unconfigured state, set to stopped */
678 val = i2c_smbus_read_byte_data(client, ZIIRAVE_WDT_STATE);
Andrey Smirnov4a9600c2019-08-12 13:08:46 -0700679 if (val < 0) {
680 dev_err(&client->dev, "Failed to read state\n");
Martyn Welch2a7b7532015-12-01 15:32:47 +0000681 return val;
Andrey Smirnov4a9600c2019-08-12 13:08:46 -0700682 }
Martyn Welch2a7b7532015-12-01 15:32:47 +0000683
684 if (val == ZIIRAVE_STATE_INITIAL)
685 ziirave_wdt_stop(&w_priv->wdd);
686
687 ret = ziirave_wdt_init_duration(client);
Andrey Smirnov4a9600c2019-08-12 13:08:46 -0700688 if (ret) {
689 dev_err(&client->dev, "Failed to init duration\n");
Martyn Welch2a7b7532015-12-01 15:32:47 +0000690 return ret;
Andrey Smirnov4a9600c2019-08-12 13:08:46 -0700691 }
Martyn Welch2a7b7532015-12-01 15:32:47 +0000692
693 ret = ziirave_wdt_revision(client, &w_priv->firmware_rev,
694 ZIIRAVE_WDT_FIRM_VER_MAJOR);
Andrey Smirnov4a9600c2019-08-12 13:08:46 -0700695 if (ret) {
696 dev_err(&client->dev, "Failed to read firmware version\n");
Martyn Welch2a7b7532015-12-01 15:32:47 +0000697 return ret;
Andrey Smirnov4a9600c2019-08-12 13:08:46 -0700698 }
Martyn Welch2a7b7532015-12-01 15:32:47 +0000699
Andrey Smirnov42abc122019-08-12 13:08:49 -0700700 dev_info(&client->dev,
701 "Firmware version: " ZIIRAVE_FW_VERSION_FMT "\n",
702 w_priv->firmware_rev.major, w_priv->firmware_rev.minor);
703
Martyn Welch2a7b7532015-12-01 15:32:47 +0000704 ret = ziirave_wdt_revision(client, &w_priv->bootloader_rev,
705 ZIIRAVE_WDT_BOOT_VER_MAJOR);
Andrey Smirnov4a9600c2019-08-12 13:08:46 -0700706 if (ret) {
707 dev_err(&client->dev, "Failed to read bootloader version\n");
Martyn Welch2a7b7532015-12-01 15:32:47 +0000708 return ret;
Andrey Smirnov4a9600c2019-08-12 13:08:46 -0700709 }
Martyn Welch2a7b7532015-12-01 15:32:47 +0000710
Andrey Smirnov42abc122019-08-12 13:08:49 -0700711 dev_info(&client->dev,
712 "Bootloader version: " ZIIRAVE_BL_VERSION_FMT "\n",
713 w_priv->bootloader_rev.major, w_priv->bootloader_rev.minor);
714
Martyn Welch2a7b7532015-12-01 15:32:47 +0000715 w_priv->reset_reason = i2c_smbus_read_byte_data(client,
716 ZIIRAVE_WDT_RESET_REASON);
Andrey Smirnov4a9600c2019-08-12 13:08:46 -0700717 if (w_priv->reset_reason < 0) {
718 dev_err(&client->dev, "Failed to read reset reason\n");
Martyn Welch2a7b7532015-12-01 15:32:47 +0000719 return w_priv->reset_reason;
Andrey Smirnov4a9600c2019-08-12 13:08:46 -0700720 }
Martyn Welch2a7b7532015-12-01 15:32:47 +0000721
722 if (w_priv->reset_reason >= ARRAY_SIZE(ziirave_reasons) ||
Andrey Smirnov4a9600c2019-08-12 13:08:46 -0700723 !ziirave_reasons[w_priv->reset_reason]) {
724 dev_err(&client->dev, "Invalid reset reason\n");
Martyn Welch2a7b7532015-12-01 15:32:47 +0000725 return -ENODEV;
Andrey Smirnov4a9600c2019-08-12 13:08:46 -0700726 }
Martyn Welch2a7b7532015-12-01 15:32:47 +0000727
728 ret = watchdog_register_device(&w_priv->wdd);
Martyn Welch2a7b7532015-12-01 15:32:47 +0000729
Guenter Roeck2c2f3082016-01-03 15:11:57 -0800730 return ret;
Martyn Welch2a7b7532015-12-01 15:32:47 +0000731}
732
733static int ziirave_wdt_remove(struct i2c_client *client)
734{
735 struct ziirave_wdt_data *w_priv = i2c_get_clientdata(client);
736
Martyn Welch2a7b7532015-12-01 15:32:47 +0000737 watchdog_unregister_device(&w_priv->wdd);
738
739 return 0;
740}
741
Arvind Yadav68c82be2017-08-21 22:18:38 +0530742static const struct i2c_device_id ziirave_wdt_id[] = {
Enric Balletbo i Serra22daf7a2016-07-09 11:43:19 +0200743 { "rave-wdt", 0 },
Martyn Welch2a7b7532015-12-01 15:32:47 +0000744 { }
745};
746MODULE_DEVICE_TABLE(i2c, ziirave_wdt_id);
747
748static const struct of_device_id zrv_wdt_of_match[] = {
749 { .compatible = "zii,rave-wdt", },
750 { },
751};
752MODULE_DEVICE_TABLE(of, zrv_wdt_of_match);
753
754static struct i2c_driver ziirave_wdt_driver = {
755 .driver = {
756 .name = "ziirave_wdt",
757 .of_match_table = zrv_wdt_of_match,
758 },
759 .probe = ziirave_wdt_probe,
760 .remove = ziirave_wdt_remove,
761 .id_table = ziirave_wdt_id,
762};
763
764module_i2c_driver(ziirave_wdt_driver);
765
766MODULE_AUTHOR("Martyn Welch <martyn.welch@collabora.co.uk");
767MODULE_DESCRIPTION("Zodiac Aerospace RAVE Switch Watchdog Processor Driver");
768MODULE_LICENSE("GPL");