Merge tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / drivers / staging / media / solo6x10 / solo6x10-eeprom.c
1 /*
2  * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
3  *
4  * Original author:
5  * Ben Collins <bcollins@ubuntu.com>
6  *
7  * Additional work by:
8  * John Brooks <john.brooks@bluecherry.net>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23  */
24
25 #include <linux/kernel.h>
26 #include <linux/delay.h>
27
28 #include "solo6x10.h"
29
30 /* Control */
31 #define EE_SHIFT_CLK    0x04
32 #define EE_CS           0x08
33 #define EE_DATA_WRITE   0x02
34 #define EE_DATA_READ    0x01
35 #define EE_ENB          (0x80 | EE_CS)
36
37 #define eeprom_delay()  udelay(100)
38 #if 0
39 #define eeprom_delay()  solo_reg_read(solo_dev, SOLO_EEPROM_CTRL)
40 #define eeprom_delay()  ({                              \
41         int i, ret;                                     \
42         udelay(100);                                    \
43         for (i = ret = 0; i < 1000 && !ret; i++)        \
44                 ret = solo_eeprom_reg_read(solo_dev);   \
45 })
46 #endif
47 #define ADDR_LEN        6
48
49 /* Commands */
50 #define EE_EWEN_CMD     4
51 #define EE_EWDS_CMD     4
52 #define EE_WRITE_CMD    5
53 #define EE_READ_CMD     6
54 #define EE_ERASE_CMD    7
55
56 static unsigned int solo_eeprom_reg_read(struct solo_dev *solo_dev)
57 {
58         return solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) & EE_DATA_READ;
59 }
60
61 static void solo_eeprom_reg_write(struct solo_dev *solo_dev, u32 data)
62 {
63         solo_reg_write(solo_dev, SOLO_EEPROM_CTRL, data);
64         eeprom_delay();
65 }
66
67 static void solo_eeprom_cmd(struct solo_dev *solo_dev, int cmd)
68 {
69         int i;
70
71         solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ACCESS_EN);
72         solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
73
74         for (i = 4 + ADDR_LEN; i >= 0; i--) {
75                 int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0;
76
77                 solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | dataval);
78                 solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
79                                       EE_SHIFT_CLK | dataval);
80         }
81
82         solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
83 }
84
85 unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en)
86 {
87         int ewen_cmd = (w_en ? 0x3f : 0) | (EE_EWEN_CMD << ADDR_LEN);
88         unsigned int retval = 0;
89         int i;
90
91         solo_eeprom_cmd(solo_dev, ewen_cmd);
92
93         for (i = 0; i < 16; i++) {
94                 solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
95                                       EE_SHIFT_CLK);
96                 retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
97                 solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
98                 retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
99         }
100
101         solo_eeprom_reg_write(solo_dev, ~EE_CS);
102         retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
103
104         return retval;
105 }
106
107 unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc)
108 {
109         int read_cmd = loc | (EE_READ_CMD << ADDR_LEN);
110         unsigned short retval = 0;
111         int i;
112
113         solo_eeprom_cmd(solo_dev, read_cmd);
114
115         for (i = 0; i < 16; i++) {
116                 solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
117                                       EE_SHIFT_CLK);
118                 retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
119                 solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
120         }
121
122         solo_eeprom_reg_write(solo_dev, ~EE_CS);
123
124         return retval;
125 }
126
127 int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
128                       unsigned short data)
129 {
130         int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN);
131         unsigned int retval;
132         int i;
133
134         solo_eeprom_cmd(solo_dev, write_cmd);
135
136         for (i = 15; i >= 0; i--) {
137                 unsigned int dataval = (data >> i) & 1;
138
139                 solo_eeprom_reg_write(solo_dev, EE_ENB);
140                 solo_eeprom_reg_write(solo_dev,
141                                       EE_ENB | (dataval << 1) | EE_SHIFT_CLK);
142         }
143
144         solo_eeprom_reg_write(solo_dev, EE_ENB);
145         solo_eeprom_reg_write(solo_dev, ~EE_CS);
146         solo_eeprom_reg_write(solo_dev, EE_ENB);
147
148         for (i = retval = 0; i < 10000 && !retval; i++)
149                 retval = solo_eeprom_reg_read(solo_dev);
150
151         solo_eeprom_reg_write(solo_dev, ~EE_CS);
152
153         return !retval;
154 }