1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> |
4 | * |
5 | * Original author: |
6 | * Ben Collins <bcollins@ubuntu.com> |
7 | * |
8 | * Additional work by: |
9 | * John Brooks <john.brooks@bluecherry.net> |
10 | */ |
11 | |
12 | #include <linux/kernel.h> |
13 | #include <linux/delay.h> |
14 | |
15 | #include "solo6x10.h" |
16 | |
17 | /* Control */ |
18 | #define EE_SHIFT_CLK 0x04 |
19 | #define EE_CS 0x08 |
20 | #define EE_DATA_WRITE 0x02 |
21 | #define EE_DATA_READ 0x01 |
22 | #define EE_ENB (0x80 | EE_CS) |
23 | |
24 | #define eeprom_delay() udelay(100) |
25 | #if 0 |
26 | #define eeprom_delay() solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) |
27 | #define eeprom_delay() ({ \ |
28 | int i, ret; \ |
29 | udelay(100); \ |
30 | for (i = ret = 0; i < 1000 && !ret; i++) \ |
31 | ret = solo_eeprom_reg_read(solo_dev); \ |
32 | }) |
33 | #endif |
34 | #define ADDR_LEN 6 |
35 | |
36 | /* Commands */ |
37 | #define EE_EWEN_CMD 4 |
38 | #define EE_EWDS_CMD 4 |
39 | #define EE_WRITE_CMD 5 |
40 | #define EE_READ_CMD 6 |
41 | #define EE_ERASE_CMD 7 |
42 | |
43 | static unsigned int solo_eeprom_reg_read(struct solo_dev *solo_dev) |
44 | { |
45 | return solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) & EE_DATA_READ; |
46 | } |
47 | |
48 | static void solo_eeprom_reg_write(struct solo_dev *solo_dev, u32 data) |
49 | { |
50 | solo_reg_write(solo_dev, SOLO_EEPROM_CTRL, data); |
51 | eeprom_delay(); |
52 | } |
53 | |
54 | static void solo_eeprom_cmd(struct solo_dev *solo_dev, int cmd) |
55 | { |
56 | int i; |
57 | |
58 | solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ACCESS_EN); |
59 | solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); |
60 | |
61 | for (i = 4 + ADDR_LEN; i >= 0; i--) { |
62 | int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0; |
63 | |
64 | solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | dataval); |
65 | solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | |
66 | EE_SHIFT_CLK | dataval); |
67 | } |
68 | |
69 | solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); |
70 | } |
71 | |
72 | unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en) |
73 | { |
74 | int ewen_cmd = (w_en ? 0x3f : 0) | (EE_EWEN_CMD << ADDR_LEN); |
75 | unsigned int retval = 0; |
76 | int i; |
77 | |
78 | solo_eeprom_cmd(solo_dev, cmd: ewen_cmd); |
79 | |
80 | for (i = 0; i < 16; i++) { |
81 | solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | |
82 | EE_SHIFT_CLK); |
83 | retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); |
84 | solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); |
85 | retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); |
86 | } |
87 | |
88 | solo_eeprom_reg_write(solo_dev, data: ~EE_CS); |
89 | retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); |
90 | |
91 | return retval; |
92 | } |
93 | |
94 | __be16 solo_eeprom_read(struct solo_dev *solo_dev, int loc) |
95 | { |
96 | int read_cmd = loc | (EE_READ_CMD << ADDR_LEN); |
97 | u16 retval = 0; |
98 | int i; |
99 | |
100 | solo_eeprom_cmd(solo_dev, cmd: read_cmd); |
101 | |
102 | for (i = 0; i < 16; i++) { |
103 | solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | |
104 | EE_SHIFT_CLK); |
105 | retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); |
106 | solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); |
107 | } |
108 | |
109 | solo_eeprom_reg_write(solo_dev, data: ~EE_CS); |
110 | |
111 | return (__force __be16)retval; |
112 | } |
113 | |
114 | int solo_eeprom_write(struct solo_dev *solo_dev, int loc, |
115 | __be16 data) |
116 | { |
117 | int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN); |
118 | unsigned int retval; |
119 | int i; |
120 | |
121 | solo_eeprom_cmd(solo_dev, cmd: write_cmd); |
122 | |
123 | for (i = 15; i >= 0; i--) { |
124 | unsigned int dataval = ((__force unsigned)data >> i) & 1; |
125 | |
126 | solo_eeprom_reg_write(solo_dev, EE_ENB); |
127 | solo_eeprom_reg_write(solo_dev, |
128 | EE_ENB | (dataval << 1) | EE_SHIFT_CLK); |
129 | } |
130 | |
131 | solo_eeprom_reg_write(solo_dev, EE_ENB); |
132 | solo_eeprom_reg_write(solo_dev, data: ~EE_CS); |
133 | solo_eeprom_reg_write(solo_dev, EE_ENB); |
134 | |
135 | for (i = retval = 0; i < 10000 && !retval; i++) |
136 | retval = solo_eeprom_reg_read(solo_dev); |
137 | |
138 | solo_eeprom_reg_write(solo_dev, data: ~EE_CS); |
139 | |
140 | return !retval; |
141 | } |
142 | |