blob: fc60b26870acf5e9bef615d8ef39df31a4955a18 [file] [log] [blame]
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -08001/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
Nicholas Troast42621782017-07-06 07:43:13 -070013#include <linux/sort.h>
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -070014#include "fg-core.h"
15
Nicholas Troast1769fd32016-09-07 09:20:58 -070016void fg_circ_buf_add(struct fg_circ_buf *buf, int val)
17{
18 buf->arr[buf->head] = val;
19 buf->head = (buf->head + 1) % ARRAY_SIZE(buf->arr);
20 buf->size = min(++buf->size, (int)ARRAY_SIZE(buf->arr));
21}
22
23void fg_circ_buf_clr(struct fg_circ_buf *buf)
24{
Nicholas Troast805c2422017-07-06 14:53:46 -070025 buf->size = 0;
26 buf->head = 0;
27 memset(buf->arr, 0, sizeof(buf->arr));
Nicholas Troast1769fd32016-09-07 09:20:58 -070028}
29
30int fg_circ_buf_avg(struct fg_circ_buf *buf, int *avg)
31{
32 s64 result = 0;
33 int i;
34
35 if (buf->size == 0)
36 return -ENODATA;
37
38 for (i = 0; i < buf->size; i++)
39 result += buf->arr[i];
40
41 *avg = div_s64(result, buf->size);
42 return 0;
43}
44
Nicholas Troast42621782017-07-06 07:43:13 -070045static int cmp_int(const void *a, const void *b)
46{
47 return *(int *)a - *(int *)b;
48}
49
50int fg_circ_buf_median(struct fg_circ_buf *buf, int *median)
51{
52 int *temp;
53
54 if (buf->size == 0)
55 return -ENODATA;
56
57 if (buf->size == 1) {
58 *median = buf->arr[0];
59 return 0;
60 }
61
62 temp = kmalloc_array(buf->size, sizeof(*temp), GFP_KERNEL);
63 if (!temp)
64 return -ENOMEM;
65
66 memcpy(temp, buf->arr, buf->size * sizeof(*temp));
67 sort(temp, buf->size, sizeof(*temp), cmp_int, NULL);
68
69 if (buf->size % 2)
70 *median = temp[buf->size / 2];
71 else
72 *median = (temp[buf->size / 2 - 1] + temp[buf->size / 2]) / 2;
73
74 kfree(temp);
75 return 0;
76}
77
Nicholas Troast1769fd32016-09-07 09:20:58 -070078int fg_lerp(const struct fg_pt *pts, size_t tablesize, s32 input, s32 *output)
79{
80 int i;
81 s64 temp;
82
83 if (pts == NULL) {
84 pr_err("Table is NULL\n");
85 return -EINVAL;
86 }
87
88 if (tablesize < 1) {
89 pr_err("Table has no entries\n");
90 return -ENOENT;
91 }
92
93 if (tablesize == 1) {
94 *output = pts[0].y;
95 return 0;
96 }
97
98 if (pts[0].x > pts[1].x) {
99 pr_err("Table is not in acending order\n");
100 return -EINVAL;
101 }
102
103 if (input <= pts[0].x) {
104 *output = pts[0].y;
105 return 0;
106 }
107
108 if (input >= pts[tablesize - 1].x) {
109 *output = pts[tablesize - 1].y;
110 return 0;
111 }
112
113 for (i = 1; i < tablesize; i++) {
114 if (input >= pts[i].x)
115 continue;
116
117 temp = (s64)(pts[i].y - pts[i - 1].y) *
118 (s64)(input - pts[i - 1].x);
119 temp = div_s64(temp, pts[i].x - pts[i - 1].x);
120 *output = temp + pts[i - 1].y;
121 return 0;
122 }
123
124 return -EINVAL;
125}
126
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700127static struct fg_dbgfs dbgfs_data = {
128 .help_msg = {
129 .data =
130 "FG Debug-FS support\n"
131 "\n"
132 "Hierarchy schema:\n"
133 "/sys/kernel/debug/fg_sram\n"
134 " /help -- Static help text\n"
135 " /address -- Starting register address for reads or writes\n"
136 " /count -- Number of registers to read (only used for reads)\n"
137 " /data -- Initiates the SRAM read (formatted output)\n"
138 "\n",
139 },
140};
141
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700142static bool is_usb_present(struct fg_chip *chip)
143{
144 union power_supply_propval pval = {0, };
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -0700145 int rc;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700146
147 if (!chip->usb_psy)
148 chip->usb_psy = power_supply_get_by_name("usb");
149
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -0700150 if (!chip->usb_psy)
151 return false;
152
153 rc = power_supply_get_property(chip->usb_psy,
154 POWER_SUPPLY_PROP_PRESENT, &pval);
155 if (rc < 0)
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700156 return false;
157
158 return pval.intval != 0;
159}
160
161static bool is_dc_present(struct fg_chip *chip)
162{
163 union power_supply_propval pval = {0, };
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -0700164 int rc;
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700165
166 if (!chip->dc_psy)
167 chip->dc_psy = power_supply_get_by_name("dc");
168
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -0700169 if (!chip->dc_psy)
170 return false;
171
172 rc = power_supply_get_property(chip->dc_psy,
173 POWER_SUPPLY_PROP_PRESENT, &pval);
174 if (rc < 0)
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700175 return false;
176
177 return pval.intval != 0;
178}
179
180bool is_input_present(struct fg_chip *chip)
181{
182 return is_usb_present(chip) || is_dc_present(chip);
183}
184
Abhijeet Dharmapurikar86a5e172017-07-05 13:58:04 -0700185bool is_qnovo_en(struct fg_chip *chip)
186{
187 union power_supply_propval pval = {0, };
188 int rc;
189
190 if (!chip->batt_psy)
191 chip->batt_psy = power_supply_get_by_name("battery");
192
193 if (!chip->batt_psy)
194 return false;
195
196 rc = power_supply_get_property(chip->batt_psy,
197 POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE, &pval);
198 if (rc < 0)
199 return false;
200
201 return pval.intval != 0;
202}
203
Nicholas Troast9bf1fd42016-08-25 10:59:21 -0700204#define EXPONENT_SHIFT 11
205#define EXPONENT_OFFSET -9
206#define MANTISSA_SIGN_BIT 10
207#define MICRO_UNIT 1000000
208s64 fg_float_decode(u16 val)
209{
210 s8 exponent;
211 s32 mantissa;
212
213 /* mantissa bits are shifted out during sign extension */
214 exponent = ((s16)val >> EXPONENT_SHIFT) + EXPONENT_OFFSET;
215 /* exponent bits are shifted out during sign extension */
216 mantissa = sign_extend32(val, MANTISSA_SIGN_BIT) * MICRO_UNIT;
217
218 if (exponent < 0)
219 return (s64)mantissa >> -exponent;
220
221 return (s64)mantissa << exponent;
222}
223
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700224void fill_string(char *str, size_t str_len, u8 *buf, int buf_len)
225{
226 int pos = 0;
227 int i;
228
229 for (i = 0; i < buf_len; i++) {
230 pos += scnprintf(str + pos, str_len - pos, "%02x", buf[i]);
231 if (i < buf_len - 1)
232 pos += scnprintf(str + pos, str_len - pos, " ");
233 }
234}
235
Subbaraman Narayanamurthyeca9bb32016-12-09 16:43:52 -0800236void dump_sram(u8 *buf, int addr, int len)
237{
238 int i;
239 char str[16];
240
241 /*
242 * Length passed should be in multiple of 4 as each FG SRAM word
243 * holds 4 bytes. To keep this simple, even if a length which is
244 * not a multiple of 4 bytes or less than 4 bytes is passed, SRAM
245 * registers dumped will be always in multiple of 4 bytes.
246 */
247 for (i = 0; i < len; i += 4) {
248 str[0] = '\0';
249 fill_string(str, sizeof(str), buf + i, 4);
250 pr_info("%03d %s\n", addr + (i / 4), str);
251 }
252}
253
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700254static inline bool fg_sram_address_valid(u16 address, int len)
255{
256 if (address > FG_SRAM_ADDRESS_MAX)
257 return false;
258
259 if ((address + DIV_ROUND_UP(len, 4)) > FG_SRAM_ADDRESS_MAX + 1)
260 return false;
261
262 return true;
263}
264
265#define SOC_UPDATE_WAIT_MS 1500
266int fg_sram_write(struct fg_chip *chip, u16 address, u8 offset,
267 u8 *val, int len, int flags)
268{
269 int rc = 0;
270 bool tried_again = false;
271 bool atomic_access = false;
272
273 if (!chip)
274 return -ENXIO;
275
Subbaraman Narayanamurthy0a749db2016-10-03 18:33:19 -0700276 if (chip->battery_missing)
277 return -ENODATA;
278
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700279 if (!fg_sram_address_valid(address, len))
280 return -EFAULT;
281
Nicholas Troastf086aad2016-08-05 11:04:45 -0700282 if (!(flags & FG_IMA_NO_WLOCK))
283 vote(chip->awake_votable, SRAM_WRITE, true, 0);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700284 mutex_lock(&chip->sram_rw_lock);
285
286 if ((flags & FG_IMA_ATOMIC) && chip->irqs[SOC_UPDATE_IRQ].irq) {
287 /*
288 * This interrupt need to be enabled only when it is
289 * required. It will be kept disabled other times.
290 */
Subbaraman Narayanamurthyf9611e32016-09-26 11:12:47 -0700291 reinit_completion(&chip->soc_update);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700292 enable_irq(chip->irqs[SOC_UPDATE_IRQ].irq);
293 atomic_access = true;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700294 }
295wait:
296 /*
297 * Atomic access mean waiting upon SOC_UPDATE interrupt from
298 * FG_ALG and do the transaction after that. This is to make
299 * sure that there will be no SOC update happening when an
300 * IMA write is happening. SOC_UPDATE interrupt fires every
301 * FG cycle (~1.47 seconds).
302 */
303 if (atomic_access) {
304 /* Wait for SOC_UPDATE completion */
305 rc = wait_for_completion_interruptible_timeout(
306 &chip->soc_update,
307 msecs_to_jiffies(SOC_UPDATE_WAIT_MS));
308
309 /* If we were interrupted wait again one more time. */
310 if (rc == -ERESTARTSYS && !tried_again) {
311 tried_again = true;
312 goto wait;
313 } else if (rc <= 0) {
314 pr_err("wait for soc_update timed out rc=%d\n", rc);
315 goto out;
316 }
317 }
318
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -0700319 if (chip->use_dma)
320 rc = fg_direct_mem_write(chip, address, offset, val, len,
321 false);
322 else
323 rc = fg_interleaved_mem_write(chip, address, offset, val, len,
324 atomic_access);
325
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700326 if (rc < 0)
327 pr_err("Error in writing SRAM address 0x%x[%d], rc=%d\n",
328 address, offset, rc);
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -0700329
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700330out:
331 if (atomic_access)
332 disable_irq_nosync(chip->irqs[SOC_UPDATE_IRQ].irq);
333
334 mutex_unlock(&chip->sram_rw_lock);
Nicholas Troastf086aad2016-08-05 11:04:45 -0700335 if (!(flags & FG_IMA_NO_WLOCK))
336 vote(chip->awake_votable, SRAM_WRITE, false, 0);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700337 return rc;
338}
339
340int fg_sram_read(struct fg_chip *chip, u16 address, u8 offset,
341 u8 *val, int len, int flags)
342{
343 int rc = 0;
344
345 if (!chip)
346 return -ENXIO;
347
Subbaraman Narayanamurthy0a749db2016-10-03 18:33:19 -0700348 if (chip->battery_missing)
349 return -ENODATA;
350
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700351 if (!fg_sram_address_valid(address, len))
352 return -EFAULT;
353
Nicholas Troastf086aad2016-08-05 11:04:45 -0700354 if (!(flags & FG_IMA_NO_WLOCK))
355 vote(chip->awake_votable, SRAM_READ, true, 0);
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -0700356
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700357 mutex_lock(&chip->sram_rw_lock);
358
Subbaraman Narayanamurthy2d62e9e2017-06-02 17:40:28 -0700359 if (chip->use_dma)
360 rc = fg_direct_mem_read(chip, address, offset, val, len);
361 else
362 rc = fg_interleaved_mem_read(chip, address, offset, val, len);
363
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700364 if (rc < 0)
365 pr_err("Error in reading SRAM address 0x%x[%d], rc=%d\n",
366 address, offset, rc);
367
368 mutex_unlock(&chip->sram_rw_lock);
Nicholas Troastf086aad2016-08-05 11:04:45 -0700369 if (!(flags & FG_IMA_NO_WLOCK))
370 vote(chip->awake_votable, SRAM_READ, false, 0);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700371 return rc;
372}
373
374int fg_sram_masked_write(struct fg_chip *chip, u16 address, u8 offset,
375 u8 mask, u8 val, int flags)
376{
377 int rc = 0;
378 u8 buf[4];
379
380 rc = fg_sram_read(chip, address, 0, buf, 4, flags);
381 if (rc < 0) {
382 pr_err("sram read failed: address=%03X, rc=%d\n", address, rc);
383 return rc;
384 }
385
386 buf[offset] &= ~mask;
387 buf[offset] |= val & mask;
388
389 rc = fg_sram_write(chip, address, 0, buf, 4, flags);
390 if (rc < 0) {
391 pr_err("sram write failed: address=%03X, rc=%d\n", address, rc);
392 return rc;
393 }
394
395 return rc;
396}
397
398int fg_read(struct fg_chip *chip, int addr, u8 *val, int len)
399{
400 int rc, i;
401
402 if (!chip || !chip->regmap)
403 return -ENXIO;
404
405 rc = regmap_bulk_read(chip->regmap, addr, val, len);
406
407 if (rc < 0) {
408 dev_err(chip->dev, "regmap_read failed for address %04x rc=%d\n",
409 addr, rc);
410 return rc;
411 }
412
413 if (*chip->debug_mask & FG_BUS_READ) {
414 pr_info("length %d addr=%04x\n", len, addr);
415 for (i = 0; i < len; i++)
416 pr_info("val[%d]: %02x\n", i, val[i]);
417 }
418
419 return 0;
420}
421
422int fg_write(struct fg_chip *chip, int addr, u8 *val, int len)
423{
424 int rc, i;
425 bool sec_access = false;
426
427 if (!chip || !chip->regmap)
428 return -ENXIO;
429
430 mutex_lock(&chip->bus_lock);
Anirudh Ghayalb00eac62017-03-02 12:53:04 +0530431 sec_access = (addr & 0x00FF) > 0xD0;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700432 if (sec_access) {
433 rc = regmap_write(chip->regmap, (addr & 0xFF00) | 0xD0, 0xA5);
434 if (rc < 0) {
435 dev_err(chip->dev, "regmap_write failed for address %x rc=%d\n",
436 addr, rc);
437 goto out;
438 }
439 }
440
441 if (len > 1)
442 rc = regmap_bulk_write(chip->regmap, addr, val, len);
443 else
444 rc = regmap_write(chip->regmap, addr, *val);
445
446 if (rc < 0) {
447 dev_err(chip->dev, "regmap_write failed for address %04x rc=%d\n",
448 addr, rc);
449 goto out;
450 }
451
452 if (*chip->debug_mask & FG_BUS_WRITE) {
453 pr_info("length %d addr=%04x\n", len, addr);
454 for (i = 0; i < len; i++)
455 pr_info("val[%d]: %02x\n", i, val[i]);
456 }
457out:
458 mutex_unlock(&chip->bus_lock);
459 return rc;
460}
461
462int fg_masked_write(struct fg_chip *chip, int addr, u8 mask, u8 val)
463{
464 int rc;
465 bool sec_access = false;
466
467 if (!chip || !chip->regmap)
468 return -ENXIO;
469
470 mutex_lock(&chip->bus_lock);
Anirudh Ghayalb00eac62017-03-02 12:53:04 +0530471 sec_access = (addr & 0x00FF) > 0xD0;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700472 if (sec_access) {
473 rc = regmap_write(chip->regmap, (addr & 0xFF00) | 0xD0, 0xA5);
474 if (rc < 0) {
475 dev_err(chip->dev, "regmap_write failed for address %x rc=%d\n",
476 addr, rc);
477 goto out;
478 }
479 }
480
481 rc = regmap_update_bits(chip->regmap, addr, mask, val);
482 if (rc < 0) {
483 dev_err(chip->dev, "regmap_update_bits failed for address %04x rc=%d\n",
484 addr, rc);
485 goto out;
486 }
487
488 fg_dbg(chip, FG_BUS_WRITE, "addr=%04x mask: %02x val: %02x\n", addr,
489 mask, val);
490out:
491 mutex_unlock(&chip->bus_lock);
492 return rc;
493}
494
Subbaraman Narayanamurthy2d385062017-09-14 20:23:13 -0700495int fg_dump_regs(struct fg_chip *chip)
496{
497 int i, rc;
498 u8 buf[256];
499
500 if (!chip)
501 return -EINVAL;
502
503 rc = fg_read(chip, chip->batt_soc_base, buf, sizeof(buf));
504 if (rc < 0)
505 return rc;
506
507 pr_info("batt_soc_base registers:\n");
508 for (i = 0; i < sizeof(buf); i++)
509 pr_info("%04x:%02x\n", chip->batt_soc_base + i, buf[i]);
510
511 rc = fg_read(chip, chip->mem_if_base, buf, sizeof(buf));
512 if (rc < 0)
513 return rc;
514
515 pr_info("mem_if_base registers:\n");
516 for (i = 0; i < sizeof(buf); i++)
517 pr_info("%04x:%02x\n", chip->mem_if_base + i, buf[i]);
518
519 return 0;
520}
521
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700522int64_t twos_compliment_extend(int64_t val, int sign_bit_pos)
523{
524 int i, nbytes = DIV_ROUND_UP(sign_bit_pos, 8);
525 int64_t mask, val_out;
526
527 val_out = val;
528 mask = 1 << sign_bit_pos;
529 if (val & mask) {
530 for (i = 8; i > nbytes; i--) {
531 mask = 0xFFLL << ((i - 1) * 8);
532 val_out |= mask;
533 }
534
535 if ((nbytes * 8) - 1 > sign_bit_pos) {
536 mask = 1 << sign_bit_pos;
537 for (i = 1; i <= (nbytes * 8) - sign_bit_pos; i++)
538 val_out |= mask << i;
539 }
540 }
541
542 pr_debug("nbytes: %d val: %llx val_out: %llx\n", nbytes, val, val_out);
543 return val_out;
544}
545
546/* All the debugfs related functions are defined below */
547static int fg_sram_dfs_open(struct inode *inode, struct file *file)
548{
549 struct fg_log_buffer *log;
550 struct fg_trans *trans;
551 u8 *data_buf;
552
553 size_t logbufsize = SZ_4K;
554 size_t databufsize = SZ_4K;
555
556 if (!dbgfs_data.chip) {
557 pr_err("Not initialized data\n");
558 return -EINVAL;
559 }
560
561 /* Per file "transaction" data */
562 trans = devm_kzalloc(dbgfs_data.chip->dev, sizeof(*trans), GFP_KERNEL);
563 if (!trans)
564 return -ENOMEM;
565
566 /* Allocate log buffer */
567 log = devm_kzalloc(dbgfs_data.chip->dev, logbufsize, GFP_KERNEL);
568 if (!log)
569 return -ENOMEM;
570
571 log->rpos = 0;
572 log->wpos = 0;
573 log->len = logbufsize - sizeof(*log);
574
575 /* Allocate data buffer */
576 data_buf = devm_kzalloc(dbgfs_data.chip->dev, databufsize, GFP_KERNEL);
577 if (!data_buf)
578 return -ENOMEM;
579
580 trans->log = log;
581 trans->data = data_buf;
582 trans->cnt = dbgfs_data.cnt;
583 trans->addr = dbgfs_data.addr;
584 trans->chip = dbgfs_data.chip;
585 trans->offset = trans->addr;
ansharma63bffdb2017-01-20 18:16:18 +0530586 mutex_init(&trans->fg_dfs_lock);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700587
588 file->private_data = trans;
589 return 0;
590}
591
592static int fg_sram_dfs_close(struct inode *inode, struct file *file)
593{
594 struct fg_trans *trans = file->private_data;
595
596 if (trans && trans->log && trans->data) {
597 file->private_data = NULL;
ansharma63bffdb2017-01-20 18:16:18 +0530598 mutex_destroy(&trans->fg_dfs_lock);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700599 devm_kfree(trans->chip->dev, trans->log);
600 devm_kfree(trans->chip->dev, trans->data);
601 devm_kfree(trans->chip->dev, trans);
602 }
603
604 return 0;
605}
606
607/**
608 * print_to_log: format a string and place into the log buffer
609 * @log: The log buffer to place the result into.
610 * @fmt: The format string to use.
611 * @...: The arguments for the format string.
612 *
613 * The return value is the number of characters written to @log buffer
614 * not including the trailing '\0'.
615 */
616static int print_to_log(struct fg_log_buffer *log, const char *fmt, ...)
617{
618 va_list args;
619 int cnt;
620 char *buf = &log->data[log->wpos];
621 size_t size = log->len - log->wpos;
622
623 va_start(args, fmt);
624 cnt = vscnprintf(buf, size, fmt, args);
625 va_end(args);
626
627 log->wpos += cnt;
628 return cnt;
629}
630
631/**
632 * write_next_line_to_log: Writes a single "line" of data into the log buffer
633 * @trans: Pointer to SRAM transaction data.
634 * @offset: SRAM address offset to start reading from.
635 * @pcnt: Pointer to 'cnt' variable. Indicates the number of bytes to read.
636 *
637 * The 'offset' is a 12-bit SRAM address.
638 *
639 * On a successful read, the pcnt is decremented by the number of data
640 * bytes read from the SRAM. When the cnt reaches 0, all requested bytes have
641 * been read.
642 */
643static int write_next_line_to_log(struct fg_trans *trans, int offset,
644 size_t *pcnt)
645{
Subbaraman Narayanamurthy4a65dc72016-07-27 10:41:47 -0700646 int i;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700647 u8 data[ITEMS_PER_LINE];
648 u16 address;
649 struct fg_log_buffer *log = trans->log;
650 int cnt = 0;
651 int items_to_read = min(ARRAY_SIZE(data), *pcnt);
652 int items_to_log = min(ITEMS_PER_LINE, items_to_read);
653
654 /* Buffer needs enough space for an entire line */
655 if ((log->len - log->wpos) < MAX_LINE_LENGTH)
656 goto done;
657
658 memcpy(data, trans->data + (offset - trans->addr), items_to_read);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700659 *pcnt -= items_to_read;
660
661 /* address is in word now and it increments by 1. */
662 address = trans->addr + ((offset - trans->addr) / ITEMS_PER_LINE);
663 cnt = print_to_log(log, "%3.3d ", address & 0xfff);
664 if (cnt == 0)
665 goto done;
666
667 /* Log the data items */
Subbaraman Narayanamurthy4a65dc72016-07-27 10:41:47 -0700668 for (i = 0; i < items_to_log; ++i) {
669 cnt = print_to_log(log, "%2.2X ", data[i]);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700670 if (cnt == 0)
671 goto done;
672 }
673
674 /* If the last character was a space, then replace it with a newline */
675 if (log->wpos > 0 && log->data[log->wpos - 1] == ' ')
676 log->data[log->wpos - 1] = '\n';
677
678done:
679 return cnt;
680}
681
682/**
683 * get_log_data - reads data from SRAM and saves to the log buffer
684 * @trans: Pointer to SRAM transaction data.
685 *
686 * Returns the number of "items" read or SPMI error code for read failures.
687 */
688static int get_log_data(struct fg_trans *trans)
689{
690 int cnt, rc;
691 int last_cnt;
692 int items_read;
693 int total_items_read = 0;
694 u32 offset = trans->offset;
695 size_t item_cnt = trans->cnt;
696 struct fg_log_buffer *log = trans->log;
697
698 if (item_cnt == 0)
699 return 0;
700
701 if (item_cnt > SZ_4K) {
702 pr_err("Reading too many bytes\n");
703 return -EINVAL;
704 }
705
706 pr_debug("addr: %d offset: %d count: %d\n", trans->addr, trans->offset,
707 trans->cnt);
708 rc = fg_sram_read(trans->chip, trans->addr, 0,
709 trans->data, trans->cnt, 0);
710 if (rc < 0) {
711 pr_err("SRAM read failed: rc = %d\n", rc);
712 return rc;
713 }
714 /* Reset the log buffer 'pointers' */
715 log->wpos = log->rpos = 0;
716
717 /* Keep reading data until the log is full */
718 do {
719 last_cnt = item_cnt;
720 cnt = write_next_line_to_log(trans, offset, &item_cnt);
721 items_read = last_cnt - item_cnt;
722 offset += items_read;
723 total_items_read += items_read;
724 } while (cnt && item_cnt > 0);
725
726 /* Adjust the transaction offset and count */
727 trans->cnt = item_cnt;
728 trans->offset += total_items_read;
729
730 return total_items_read;
731}
732
733/**
734 * fg_sram_dfs_reg_read: reads value(s) from SRAM and fills user's buffer a
735 * byte array (coded as string)
736 * @file: file pointer
737 * @buf: where to put the result
738 * @count: maximum space available in @buf
739 * @ppos: starting position
740 * @return number of user bytes read, or negative error value
741 */
742static ssize_t fg_sram_dfs_reg_read(struct file *file, char __user *buf,
743 size_t count, loff_t *ppos)
744{
745 struct fg_trans *trans = file->private_data;
746 struct fg_log_buffer *log = trans->log;
747 size_t ret;
748 size_t len;
749
ansharma63bffdb2017-01-20 18:16:18 +0530750 mutex_lock(&trans->fg_dfs_lock);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700751 /* Is the the log buffer empty */
752 if (log->rpos >= log->wpos) {
ansharma63bffdb2017-01-20 18:16:18 +0530753 if (get_log_data(trans) <= 0) {
754 len = 0;
755 goto unlock_mutex;
756 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700757 }
758
759 len = min(count, log->wpos - log->rpos);
760
761 ret = copy_to_user(buf, &log->data[log->rpos], len);
762 if (ret == len) {
763 pr_err("error copy sram register values to user\n");
ansharma63bffdb2017-01-20 18:16:18 +0530764 len = -EFAULT;
765 goto unlock_mutex;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700766 }
767
768 /* 'ret' is the number of bytes not copied */
769 len -= ret;
770
771 *ppos += len;
772 log->rpos += len;
ansharma63bffdb2017-01-20 18:16:18 +0530773
774unlock_mutex:
775 mutex_unlock(&trans->fg_dfs_lock);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700776 return len;
777}
778
779/**
780 * fg_sram_dfs_reg_write: write user's byte array (coded as string) to SRAM.
781 * @file: file pointer
782 * @buf: user data to be written.
783 * @count: maximum space available in @buf
784 * @ppos: starting position
785 * @return number of user byte written, or negative error value
786 */
787static ssize_t fg_sram_dfs_reg_write(struct file *file, const char __user *buf,
788 size_t count, loff_t *ppos)
789{
790 int bytes_read;
791 int data;
792 int pos = 0;
793 int cnt = 0;
794 u8 *values;
795 char *kbuf;
796 size_t ret = 0;
797 struct fg_trans *trans = file->private_data;
798 u32 address = trans->addr;
799
ansharma63bffdb2017-01-20 18:16:18 +0530800 mutex_lock(&trans->fg_dfs_lock);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700801 /* Make a copy of the user data */
802 kbuf = kmalloc(count + 1, GFP_KERNEL);
ansharma63bffdb2017-01-20 18:16:18 +0530803 if (!kbuf) {
804 ret = -ENOMEM;
805 goto unlock_mutex;
806 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700807
808 ret = copy_from_user(kbuf, buf, count);
809 if (ret == count) {
810 pr_err("failed to copy data from user\n");
811 ret = -EFAULT;
812 goto free_buf;
813 }
814
815 count -= ret;
816 *ppos += count;
817 kbuf[count] = '\0';
818
819 /* Override the text buffer with the raw data */
820 values = kbuf;
821
822 /* Parse the data in the buffer. It should be a string of numbers */
Subbaraman Narayanamurthy4a65dc72016-07-27 10:41:47 -0700823 while ((pos < count) &&
824 sscanf(kbuf + pos, "%i%n", &data, &bytes_read) == 1) {
Subbaraman Narayanamurthy3c081082016-10-13 19:16:27 -0700825 /*
826 * We shouldn't be receiving a string of characters that
827 * exceeds a size of 5 to keep this functionally correct.
828 * Also, we should make sure that pos never gets overflowed
829 * beyond the limit.
830 */
831 if (bytes_read > 5 || bytes_read > INT_MAX - pos) {
832 cnt = 0;
833 ret = -EINVAL;
834 break;
835 }
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700836 pos += bytes_read;
837 values[cnt++] = data & 0xff;
838 }
839
840 if (!cnt)
841 goto free_buf;
842
843 pr_debug("address %d, count %d\n", address, cnt);
844 /* Perform the write(s) */
845
846 ret = fg_sram_write(trans->chip, address, 0, values, cnt, 0);
847 if (ret) {
848 pr_err("SRAM write failed, err = %zu\n", ret);
849 } else {
850 ret = count;
851 trans->offset += cnt > 4 ? 4 : cnt;
852 }
853
854free_buf:
855 kfree(kbuf);
ansharma63bffdb2017-01-20 18:16:18 +0530856unlock_mutex:
857 mutex_unlock(&trans->fg_dfs_lock);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700858 return ret;
859}
860
861static const struct file_operations fg_sram_dfs_reg_fops = {
862 .open = fg_sram_dfs_open,
863 .release = fg_sram_dfs_close,
864 .read = fg_sram_dfs_reg_read,
865 .write = fg_sram_dfs_reg_write,
866};
867
868/*
869 * fg_debugfs_create: adds new fg_sram debugfs entry
870 * @return zero on success
871 */
Nicholas Troast69da2252016-09-07 16:17:47 -0700872static int fg_sram_debugfs_create(struct fg_chip *chip)
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700873{
Nicholas Troast69da2252016-09-07 16:17:47 -0700874 struct dentry *dfs_sram;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700875 struct dentry *file;
876 mode_t dfs_mode = 0600;
877
878 pr_debug("Creating FG_SRAM debugfs file-system\n");
Nicholas Troast69da2252016-09-07 16:17:47 -0700879 dfs_sram = debugfs_create_dir("sram", chip->dfs_root);
880 if (!dfs_sram) {
881 pr_err("error creating fg sram dfs rc=%ld\n",
882 (long)dfs_sram);
883 return -ENOMEM;
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700884 }
885
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700886 dbgfs_data.help_msg.size = strlen(dbgfs_data.help_msg.data);
Nicholas Troast69da2252016-09-07 16:17:47 -0700887 file = debugfs_create_blob("help", 0444, dfs_sram,
888 &dbgfs_data.help_msg);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700889 if (!file) {
890 pr_err("error creating help entry\n");
891 goto err_remove_fs;
892 }
893
894 dbgfs_data.chip = chip;
895
Nicholas Troast69da2252016-09-07 16:17:47 -0700896 file = debugfs_create_u32("count", dfs_mode, dfs_sram,
897 &(dbgfs_data.cnt));
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700898 if (!file) {
899 pr_err("error creating 'count' entry\n");
900 goto err_remove_fs;
901 }
902
Nicholas Troast69da2252016-09-07 16:17:47 -0700903 file = debugfs_create_x32("address", dfs_mode, dfs_sram,
904 &(dbgfs_data.addr));
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700905 if (!file) {
906 pr_err("error creating 'address' entry\n");
907 goto err_remove_fs;
908 }
909
Nicholas Troast69da2252016-09-07 16:17:47 -0700910 file = debugfs_create_file("data", dfs_mode, dfs_sram, &dbgfs_data,
911 &fg_sram_dfs_reg_fops);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700912 if (!file) {
913 pr_err("error creating 'data' entry\n");
914 goto err_remove_fs;
915 }
916
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700917 return 0;
918
919err_remove_fs:
Nicholas Troast69da2252016-09-07 16:17:47 -0700920 debugfs_remove_recursive(dfs_sram);
921 return -ENOMEM;
922}
923
924static int fg_alg_flags_open(struct inode *inode, struct file *file)
925{
926 file->private_data = inode->i_private;
927 return 0;
928}
929
930static ssize_t fg_alg_flags_read(struct file *file, char __user *userbuf,
931 size_t count, loff_t *ppos)
932{
933 struct fg_chip *chip = file->private_data;
934 char buf[512];
935 u8 alg_flags = 0;
936 int rc, i, len;
937
938 rc = fg_sram_read(chip, chip->sp[FG_SRAM_ALG_FLAGS].addr_word,
939 chip->sp[FG_SRAM_ALG_FLAGS].addr_byte, &alg_flags, 1,
940 FG_IMA_DEFAULT);
941 if (rc < 0) {
942 pr_err("failed to read algorithm flags rc=%d\n", rc);
943 return -EFAULT;
944 }
945
946 len = 0;
947 for (i = 0; i < ALG_FLAG_MAX; ++i) {
948 if (len > ARRAY_SIZE(buf) - 1)
949 return -EFAULT;
950 if (chip->alg_flags[i].invalid)
951 continue;
952
953 len += snprintf(buf + len, sizeof(buf) - sizeof(*buf) * len,
954 "%s = %d\n", chip->alg_flags[i].name,
955 (bool)(alg_flags & chip->alg_flags[i].bit));
956 }
957
958 return simple_read_from_buffer(userbuf, count, ppos, buf, len);
959}
960
961static const struct file_operations fg_alg_flags_fops = {
962 .open = fg_alg_flags_open,
963 .read = fg_alg_flags_read,
964};
965
966int fg_debugfs_create(struct fg_chip *chip)
967{
968 int rc;
969
970 pr_debug("Creating debugfs file-system\n");
971 chip->dfs_root = debugfs_create_dir("fg", NULL);
972 if (IS_ERR_OR_NULL(chip->dfs_root)) {
973 if (PTR_ERR(chip->dfs_root) == -ENODEV)
974 pr_err("debugfs is not enabled in the kernel\n");
975 else
976 pr_err("error creating fg dfs root rc=%ld\n",
977 (long)chip->dfs_root);
978 return -ENODEV;
979 }
980
981 rc = fg_sram_debugfs_create(chip);
982 if (rc < 0) {
983 pr_err("failed to create sram dfs rc=%d\n", rc);
984 goto err_remove_fs;
985 }
986
987 if (!debugfs_create_file("alg_flags", 0400, chip->dfs_root, chip,
988 &fg_alg_flags_fops)) {
989 pr_err("failed to create alg_flags file\n");
990 goto err_remove_fs;
991 }
992
993 return 0;
994
995err_remove_fs:
996 debugfs_remove_recursive(chip->dfs_root);
Subbaraman Narayanamurthy6accb262016-03-14 16:41:16 -0700997 return -ENOMEM;
998}