Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[sfrench/cifs-2.6.git] / drivers / media / pci / 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
21 #include <linux/kernel.h>
22 #include <linux/delay.h>
23
24 #include "solo6x10.h"
25
26 /* Control */
27 #define EE_SHIFT_CLK    0x04
28 #define EE_CS           0x08
29 #define EE_DATA_WRITE   0x02
30 #define EE_DATA_READ    0x01
31 #define EE_ENB          (0x80 | EE_CS)
32
33 #define eeprom_delay()  udelay(100)
34 #if 0
35 #define eeprom_delay()  solo_reg_read(solo_dev, SOLO_EEPROM_CTRL)
36 #define eeprom_delay()  ({                              \
37         int i, ret;                                     \
38         udelay(100);                                    \
39         for (i = ret = 0; i < 1000 && !ret; i++)        \
40                 ret = solo_eeprom_reg_read(solo_dev);   \
41 })
42 #endif
43 #define ADDR_LEN        6
44
45 /* Commands */
46 #define EE_EWEN_CMD     4
47 #define EE_EWDS_CMD     4
48 #define EE_WRITE_CMD    5
49 #define EE_READ_CMD     6
50 #define EE_ERASE_CMD    7
51
52 static unsigned int solo_eeprom_reg_read(struct solo_dev *solo_dev)
53 {
54         return solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) & EE_DATA_READ;
55 }
56
57 static void solo_eeprom_reg_write(struct solo_dev *solo_dev, u32 data)
58 {
59         solo_reg_write(solo_dev, SOLO_EEPROM_CTRL, data);
60         eeprom_delay();
61 }
62
63 static void solo_eeprom_cmd(struct solo_dev *solo_dev, int cmd)
64 {
65         int i;
66
67         solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ACCESS_EN);
68         solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
69
70         for (i = 4 + ADDR_LEN; i >= 0; i--) {
71                 int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0;
72
73                 solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | dataval);
74                 solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
75                                       EE_SHIFT_CLK | dataval);
76         }
77
78         solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
79 }
80
81 unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en)
82 {
83         int ewen_cmd = (w_en ? 0x3f : 0) | (EE_EWEN_CMD << ADDR_LEN);
84         unsigned int retval = 0;
85         int i;
86
87         solo_eeprom_cmd(solo_dev, ewen_cmd);
88
89         for (i = 0; i < 16; i++) {
90                 solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
91                                       EE_SHIFT_CLK);
92                 retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
93                 solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
94                 retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
95         }
96
97         solo_eeprom_reg_write(solo_dev, ~EE_CS);
98         retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
99
100         return retval;
101 }
102
103 __be16 solo_eeprom_read(struct solo_dev *solo_dev, int loc)
104 {
105         int read_cmd = loc | (EE_READ_CMD << ADDR_LEN);
106         u16 retval = 0;
107         int i;
108
109         solo_eeprom_cmd(solo_dev, read_cmd);
110
111         for (i = 0; i < 16; i++) {
112                 solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
113                                       EE_SHIFT_CLK);
114                 retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
115                 solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
116         }
117
118         solo_eeprom_reg_write(solo_dev, ~EE_CS);
119
120         return (__force __be16)retval;
121 }
122
123 int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
124                       __be16 data)
125 {
126         int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN);
127         unsigned int retval;
128         int i;
129
130         solo_eeprom_cmd(solo_dev, write_cmd);
131
132         for (i = 15; i >= 0; i--) {
133                 unsigned int dataval = ((__force unsigned)data >> i) & 1;
134
135                 solo_eeprom_reg_write(solo_dev, EE_ENB);
136                 solo_eeprom_reg_write(solo_dev,
137                                       EE_ENB | (dataval << 1) | EE_SHIFT_CLK);
138         }
139
140         solo_eeprom_reg_write(solo_dev, EE_ENB);
141         solo_eeprom_reg_write(solo_dev, ~EE_CS);
142         solo_eeprom_reg_write(solo_dev, EE_ENB);
143
144         for (i = retval = 0; i < 10000 && !retval; i++)
145                 retval = solo_eeprom_reg_read(solo_dev);
146
147         solo_eeprom_reg_write(solo_dev, ~EE_CS);
148
149         return !retval;
150 }