diff options
Diffstat (limited to 'firmware/target/hosted/ypr0/ascodec-ypr0.c')
-rw-r--r-- | firmware/target/hosted/ypr0/ascodec-ypr0.c | 137 |
1 files changed, 43 insertions, 94 deletions
diff --git a/firmware/target/hosted/ypr0/ascodec-ypr0.c b/firmware/target/hosted/ypr0/ascodec-ypr0.c index a4e92e6f6b..b3bc48290f 100644 --- a/firmware/target/hosted/ypr0/ascodec-ypr0.c +++ b/firmware/target/hosted/ypr0/ascodec-ypr0.c | |||
@@ -32,33 +32,36 @@ | |||
32 | 32 | ||
33 | int afe_dev = -1; | 33 | int afe_dev = -1; |
34 | 34 | ||
35 | /* ioctl parameter struct */ | ||
36 | struct codec_req_struct { | ||
37 | /* This works for every kind of afe.ko module requests */ | ||
38 | unsigned char reg; /* Main register address */ | ||
39 | unsigned char subreg; /* Set this only if you are reading/writing a PMU register*/ | ||
40 | unsigned char value; /* To be read if reading a register; to be set if writing to a register */ | ||
41 | } __attribute__((packed)); | ||
42 | |||
43 | |||
35 | /* Write to a normal register */ | 44 | /* Write to a normal register */ |
36 | #define IOCTL_REG_WRITE 0x40034101 | 45 | #define IOCTL_REG_WRITE 0x40034101 |
37 | /* Write to a PMU register */ | 46 | /* Write to a PMU register */ |
38 | #define IOCTL_SUBREG_WRITE 0x40034103 | 47 | #define IOCTL_SUBREG_WRITE 0x40034103 |
39 | /* Read from a normal register */ | 48 | /* Read from a normal register */ |
40 | #define IOCTL_REG_READ 0x80034102 | 49 | #define IOCTL_REG_READ 0x80034102 |
41 | /* Read from a PMU register */ | 50 | /* Read from a PMU register */ |
42 | #define IOCTL_SUBREG_READ 0x80034103 | 51 | #define IOCTL_SUBREG_READ 0x80034103 |
43 | |||
44 | static struct mutex as_mtx; | ||
45 | 52 | ||
46 | int ascodec_init(void) { | ||
47 | 53 | ||
54 | int ascodec_init(void) | ||
55 | { | ||
48 | afe_dev = open("/dev/afe", O_RDWR); | 56 | afe_dev = open("/dev/afe", O_RDWR); |
49 | |||
50 | mutex_init(&as_mtx); | ||
51 | |||
52 | return afe_dev; | 57 | return afe_dev; |
53 | |||
54 | } | 58 | } |
55 | 59 | ||
56 | void ascodec_close(void) { | 60 | void ascodec_close(void) |
57 | 61 | { | |
58 | if (afe_dev >= 0) { | 62 | if (afe_dev >= 0) { |
59 | close(afe_dev); | 63 | close(afe_dev); |
60 | } | 64 | } |
61 | |||
62 | } | 65 | } |
63 | 66 | ||
64 | /* Read functions returns -1 if fail, otherwise the register's value if success */ | 67 | /* Read functions returns -1 if fail, otherwise the register's value if success */ |
@@ -66,24 +69,16 @@ void ascodec_close(void) { | |||
66 | 69 | ||
67 | int ascodec_write(unsigned int reg, unsigned int value) | 70 | int ascodec_write(unsigned int reg, unsigned int value) |
68 | { | 71 | { |
69 | struct codec_req_struct y; | 72 | struct codec_req_struct r = { .reg = reg, .value = value }; |
70 | struct codec_req_struct *p; | 73 | return ioctl(afe_dev, IOCTL_REG_WRITE, &r); |
71 | p = &y; | ||
72 | p->reg = reg; | ||
73 | p->value = value; | ||
74 | return ioctl(afe_dev, IOCTL_REG_WRITE, p); | ||
75 | } | 74 | } |
76 | 75 | ||
77 | int ascodec_read(unsigned int reg) | 76 | int ascodec_read(unsigned int reg) |
78 | { | 77 | { |
79 | int retval = -1; | 78 | struct codec_req_struct r = { .reg = reg }; |
80 | struct codec_req_struct y; | 79 | int retval = ioctl(afe_dev, IOCTL_REG_READ, &r); |
81 | struct codec_req_struct *p; | ||
82 | p = &y; | ||
83 | p->reg = reg; | ||
84 | retval = ioctl(afe_dev, IOCTL_REG_READ, p); | ||
85 | if (retval >= 0) | 80 | if (retval >= 0) |
86 | return p->value; | 81 | return r.value; |
87 | else | 82 | else |
88 | return retval; | 83 | return retval; |
89 | } | 84 | } |
@@ -91,114 +86,68 @@ int ascodec_read(unsigned int reg) | |||
91 | void ascodec_write_pmu(unsigned int index, unsigned int subreg, | 86 | void ascodec_write_pmu(unsigned int index, unsigned int subreg, |
92 | unsigned int value) | 87 | unsigned int value) |
93 | { | 88 | { |
94 | struct codec_req_struct y; | 89 | struct codec_req_struct r = {.reg = index, .subreg = subreg, .value = value}; |
95 | struct codec_req_struct *p; | 90 | ioctl(afe_dev, IOCTL_SUBREG_WRITE, &r); |
96 | p = &y; | ||
97 | p->reg = index; | ||
98 | p->subreg = subreg; | ||
99 | p->value = value; | ||
100 | ioctl(afe_dev, IOCTL_SUBREG_WRITE, p); | ||
101 | } | 91 | } |
102 | 92 | ||
103 | int ascodec_read_pmu(unsigned int index, unsigned int subreg) | 93 | int ascodec_read_pmu(unsigned int index, unsigned int subreg) |
104 | { | 94 | { |
105 | int retval = -1; | 95 | struct codec_req_struct r = { .reg = index, .subreg = subreg, }; |
106 | struct codec_req_struct y; | 96 | int retval = ioctl(afe_dev, IOCTL_SUBREG_READ, &r); |
107 | struct codec_req_struct *p; | ||
108 | p = &y; | ||
109 | p->reg = index; | ||
110 | p->subreg = subreg; | ||
111 | retval = ioctl(afe_dev, IOCTL_SUBREG_READ, p); | ||
112 | if (retval >= 0) | 97 | if (retval >= 0) |
113 | return p->value; | 98 | return r.value; |
114 | else | 99 | else |
115 | return retval; | 100 | return retval; |
116 | } | 101 | } |
117 | 102 | ||
118 | /* Helpers to set/clear bits */ | ||
119 | void ascodec_set(unsigned int reg, unsigned int bits) | ||
120 | { | ||
121 | ascodec_write(reg, ascodec_read(reg) | bits); | ||
122 | } | ||
123 | |||
124 | void ascodec_clear(unsigned int reg, unsigned int bits) | ||
125 | { | ||
126 | ascodec_write(reg, ascodec_read(reg) & ~bits); | ||
127 | } | ||
128 | |||
129 | void ascodec_write_masked(unsigned int reg, unsigned int bits, | ||
130 | unsigned int mask) | ||
131 | { | ||
132 | ascodec_write(reg, (ascodec_read(reg) & ~mask) | (bits & mask)); | ||
133 | } | ||
134 | |||
135 | /*FIXME: doesn't work */ | ||
136 | int ascodec_readbytes(unsigned int index, unsigned int len, unsigned char *data) | 103 | int ascodec_readbytes(unsigned int index, unsigned int len, unsigned char *data) |
137 | { | 104 | { |
138 | unsigned int i; | 105 | int i, val, ret = 0; |
139 | 106 | ||
140 | for (i=index; i<len; i++) { | 107 | for (i = index; i < (int)len; i++) { |
141 | data[i] = ascodec_read(i); | 108 | val = ascodec_read(i); |
142 | printf("Register %i: value=%i\n",index,data[i]); | 109 | if (val >= 0) data[i] = val; |
110 | else ret = -1; | ||
143 | } | 111 | } |
144 | 112 | ||
145 | printf("TOTAL: %i\n", i); | 113 | return ret ?: i; /* i means success */ |
146 | |||
147 | return i; | ||
148 | } | 114 | } |
149 | 115 | ||
150 | /* | 116 | /* |
151 | * NOTE: | 117 | * NOTE: |
152 | * After the conversion to interrupts, ascodec_(lock|unlock) are only used by | 118 | * After the conversion to interrupts, ascodec_(lock|unlock) are only used by |
153 | * adc-as3514.c to protect against other threads corrupting the result by using | 119 | * adc-as3514.c to protect against other threads corrupting the result by using |
154 | * the ADC at the same time. | 120 | * the ADC at the same time. this adc_read() doesn't yield but blocks, so |
121 | * lock/unlock is not needed | ||
155 | * | 122 | * |
156 | * Concurrent ascodec_(async_)?(read|write) calls are instead protected | 123 | * Additionally, concurrent ascodec_?(read|write) calls are instead protected |
157 | * by the R0's Kernel I2C driver for ascodec (mutexed), so it's automatically safe | 124 | * by the R0's Kernel I2C driver for ascodec (mutexed), so it's automatically |
125 | * safe | ||
158 | */ | 126 | */ |
159 | 127 | ||
160 | void ascodec_lock(void) | 128 | void ascodec_lock(void) |
161 | { | 129 | { |
162 | mutex_lock(&as_mtx); | ||
163 | } | 130 | } |
164 | 131 | ||
165 | void ascodec_unlock(void) | 132 | void ascodec_unlock(void) |
166 | { | 133 | { |
167 | mutex_unlock(&as_mtx); | ||
168 | } | 134 | } |
169 | 135 | ||
170 | /* Read 10-bit channel data */ | 136 | /* Read 10-bit channel data */ |
171 | unsigned short adc_read(int channel) | 137 | unsigned short adc_read(int channel) |
172 | { | 138 | { |
173 | unsigned short data = 0; | ||
174 | |||
175 | if ((unsigned)channel >= NUM_ADC_CHANNELS) | 139 | if ((unsigned)channel >= NUM_ADC_CHANNELS) |
176 | return 0; | 140 | return 0; |
177 | 141 | ||
178 | ascodec_lock(); | ||
179 | |||
180 | /* Select channel */ | 142 | /* Select channel */ |
181 | ascodec_write(AS3514_ADC_0, (channel << 4)); | 143 | ascodec_write(AS3514_ADC_0, (channel << 4)); |
182 | unsigned char buf[2]; | 144 | unsigned char buf[2]; |
183 | 145 | ||
184 | /* | 146 | /* Read data */ |
185 | * The AS3514 ADC will trigger an interrupt when the conversion | 147 | ascodec_readbytes(AS3514_ADC_0, sizeof(buf), buf); |
186 | * is finished, if the corresponding enable bit in IRQ_ENRD2 | 148 | |
187 | * is set. | 149 | /* decode to 10-bit and return */ |
188 | * Previously the code did not wait and this apparently did | 150 | return (((buf[0] & 0x3) << 8) | buf[1]); |
189 | * not pose any problems, but this should be more correct. | ||
190 | * Without the wait the data read back may be completely or | ||
191 | * partially (first one of the two bytes) stale. | ||
192 | */ | ||
193 | /*FIXME: not implemented*/ | ||
194 | ascodec_wait_adc_finished(); | ||
195 | |||
196 | /* Read data */ | ||
197 | ascodec_readbytes(AS3514_ADC_0, 2, buf); | ||
198 | data = (((buf[0] & 0x3) << 8) | buf[1]); | ||
199 | |||
200 | ascodec_unlock(); | ||
201 | return data; | ||
202 | } | 151 | } |
203 | 152 | ||
204 | void adc_init(void) | 153 | void adc_init(void) |