diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2012-05-19 13:47:12 +0200 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2012-05-19 16:10:52 +0200 |
commit | deb61e0622f58b58b6f61d1822054df04cf09456 (patch) | |
tree | 68466e43baa6c94d3be895c7c4ae8612079b70c3 /firmware/drivers/mpr121.c | |
parent | 8b53c0f9a9cd421c90913032081b1c292ddb0806 (diff) | |
download | rockbox-deb61e0622f58b58b6f61d1822054df04cf09456.tar.gz rockbox-deb61e0622f58b58b6f61d1822054df04cf09456.zip |
Add the MPR121 (touchbutton chip) driver
Change-Id: I9db97a698ef1c7f0b4f47e406faa1f6c0ec524db
Diffstat (limited to 'firmware/drivers/mpr121.c')
-rw-r--r-- | firmware/drivers/mpr121.c | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/firmware/drivers/mpr121.c b/firmware/drivers/mpr121.c new file mode 100644 index 0000000000..7b41208a3a --- /dev/null +++ b/firmware/drivers/mpr121.c | |||
@@ -0,0 +1,350 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2012 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | /** Driver for the Freescale MPR121 Capacitive Proximity Sensor */ | ||
23 | #include "system.h" | ||
24 | #include "mpr121.h" | ||
25 | #include "i2c.h" | ||
26 | |||
27 | /* Touch status: EL{0,7} */ | ||
28 | #define REG_TOUCH_STATUS 0x00 | ||
29 | #define REG_TOUCH_STATUS__ELE(x) (1 << (x)) | ||
30 | /* Touch status: EL{8-11,prox}, overcurrent */ | ||
31 | #define REG_TOUCH_STATUS2 0x01 | ||
32 | #define REG_TOUCH_STATUS2__ELE(x) (1 << ((x) - 8)) | ||
33 | #define REG_TOUCH_STATUS2__ELEPROX (1 << 4) | ||
34 | #define REG_TOUCH_STATUS2__OVCF (1 << 7) | ||
35 | /* Out of range: EL{0,7} */ | ||
36 | #define REG_OOR_STATUS 0x02 | ||
37 | #define REG_OOR_STATUS__ELE(x) (1 << (x)) | ||
38 | /* Out of range: EL{8-11,prox}, autoconf err */ | ||
39 | #define REG_OOR_STATUS2 0x03 | ||
40 | #define REG_OOR_STATUS2__ELE(x) (1 << (x)) | ||
41 | #define REG_OOR_STATUS2__ELEPROX (1 << 4) | ||
42 | #define REG_OOR_STATUS2__ACFF (1 << 6) | ||
43 | #define REG_OOR_STATUS2__ARFF (1 << 7) | ||
44 | /* Electrode X filtered data LSB */ | ||
45 | #define REG_EFDxLB(x) (0x04 + 0x02 * (x)) | ||
46 | /* Electrode X filtered data MSB */ | ||
47 | #define REG_EFDxHB(x) (0x05 + 0x02 * (x)) | ||
48 | /* Proximity electrode X filtered data LSB */ | ||
49 | #define REG_EFDPROXLB 0x1c | ||
50 | /* Proximity electrode X filtered data MSB */ | ||
51 | #define REG_EFDPROXHB 0x1d | ||
52 | /* Electrode baseline value */ | ||
53 | #define REG_ExBV(x) (0x1e + (x)) | ||
54 | /* Proximity electrode baseline value */ | ||
55 | #define REG_EPROXBV 0x2a | ||
56 | /* Max Half Delta Rising */ | ||
57 | #define REG_MHDR 0x2b | ||
58 | /* Noise Half Delta Rising */ | ||
59 | #define REG_NHDR 0x2c | ||
60 | /* Noise Count Limit Rising */ | ||
61 | #define REG_NCLR 0x2d | ||
62 | /* Filter Delay Limit Rising */ | ||
63 | #define REG_FDLR 0x2e | ||
64 | /* Max Half Delta Falling */ | ||
65 | #define REG_MHDF 0x2f | ||
66 | /* Noise Half Delta Falling */ | ||
67 | #define REG_NHDF 0x30 | ||
68 | /* Noise Count Limit Falling */ | ||
69 | #define REG_NCLF 0x31 | ||
70 | /* Filter Delay Limit Falling */ | ||
71 | #define REG_FDLF 0x32 | ||
72 | /* Noise Half Delta Touched */ | ||
73 | #define REG_NHDT 0x33 | ||
74 | /* Noise Count Limit Touched */ | ||
75 | #define REG_NCLT 0x34 | ||
76 | /* Filter Delay Limit Touched */ | ||
77 | #define REG_FDLT 0x35 | ||
78 | /* Proximity Max Half Delta Rising */ | ||
79 | #define REG_MHDPROXR 0x36 | ||
80 | /* Proximity Noise Half Delta Rising */ | ||
81 | #define REG_NHDPROXR 0x37 | ||
82 | /* Proximity Noise Count Limit Rising */ | ||
83 | #define REG_NCLPROXR 0x38 | ||
84 | /* Proximity Filter Delay Limit Rising */ | ||
85 | #define REG_FDLPROXR 0x39 | ||
86 | /* Proximity Max Half Delta Falling */ | ||
87 | #define REG_MHDPROXF 0x3a | ||
88 | /* Proximity Noise Half Delta Falling */ | ||
89 | #define REG_NHDPROXF 0x3b | ||
90 | /* Proximity Noise Count Limit Falling */ | ||
91 | #define REG_NCLPROXF 0x3c | ||
92 | /* Proximity Filter Delay Limit Falling */ | ||
93 | #define REG_FDLPROXF 0x3d | ||
94 | /* Proximity Noise Half Delta Touched */ | ||
95 | #define REG_NHDPROXT 0x3e | ||
96 | /* Proximity Noise Count Limit Touched */ | ||
97 | #define REG_NCLPROXT 0x3f | ||
98 | /* Proximity Filter Delay Limit Touched */ | ||
99 | #define REG_FDLPROXT 0x40 | ||
100 | /* Eletrode Touch Threshold */ | ||
101 | #define REG_ExTTH(x) (0x41 + 2 * (x)) | ||
102 | /* Eletrode Release Threshold */ | ||
103 | #define REG_ExRTH(x) (0x42 + 2 * (x)) | ||
104 | /* Proximity Eletrode Touch Threshold */ | ||
105 | #define REG_EPROXTTH 0x59 | ||
106 | /* Proximity Eletrode Release Threshold */ | ||
107 | #define REG_EPROXRTH 0x5a | ||
108 | /* Debounce Control */ | ||
109 | #define REG_DEBOUNCE 0x5b | ||
110 | #define REG_DEBOUNCE__DR(dr) ((dr) << 4) | ||
111 | #define REG_DEBOUNCE__DT(dt) (dt) | ||
112 | /* Analog Front End Configuration */ | ||
113 | #define REG_AFE 0x5c | ||
114 | #define REG_AFE__CDC(cdc) (cdc) | ||
115 | #define REG_AFE__FFI(ffi) ((ffi) << 6) | ||
116 | /* Filter Configuration */ | ||
117 | #define REG_FILTER 0x5d | ||
118 | #define REG_FILTER__ESI(esi) (esi) | ||
119 | #define REG_FILTER__SFI(sfi) ((sfi) << 3) | ||
120 | #define REG_FILTER__CDT(cdt) ((cdt) << 5) | ||
121 | /* Electrode Configuration */ | ||
122 | #define REG_ELECTRODE 0x5e | ||
123 | #define REG_ELECTRODE__ELE_EN(en) (en) | ||
124 | #define REG_ELECTRODE__ELEPROX_EN(en) ((en) << 4) | ||
125 | #define REG_ELECTRODE__CL(cl) ((cl) << 6) | ||
126 | /* Electrode X Current */ | ||
127 | #define REG_CDCx(x) (0x5f + (x)) | ||
128 | /* Proximity Eletrode X Current */ | ||
129 | #define REG_CDCPROX 0x6b | ||
130 | /* Electrode X Charge Time */ | ||
131 | #define REG_CDTx(x) (0x6c + (x) / 2) | ||
132 | #define REG_CDTx__CDT0(x) (x) | ||
133 | #define REG_CDTx__CDT1(x) ((x) << 4) | ||
134 | /* Proximity Eletrode X Charge Time */ | ||
135 | #define REG_CDTPROX 0x72 | ||
136 | /* GPIO Control Register: CTL0{4-11} */ | ||
137 | #define REG_GPIO_CTL0 0x73 | ||
138 | #define REG_GPIO_CTL0__CTL0x(x) (1 << ((x) - 4)) | ||
139 | /* GPIO Control Register: CTL1{4-11} */ | ||
140 | #define REG_GPIO_CTL1 0x74 | ||
141 | #define REG_GPIO_CTL1__CTL1x(x) (1 << ((x) - 4)) | ||
142 | /* GPIO Data Register */ | ||
143 | #define REG_GPIO_DATA 0x75 | ||
144 | #define REG_GPIO_DATA__DATx(x) (1 << ((x) - 4)) | ||
145 | /* GPIO Direction Register */ | ||
146 | #define REG_GPIO_DIR 0x76 | ||
147 | #define REG_GPIO_DIR__DIRx(x) (1 << ((x) - 4)) | ||
148 | /* GPIO Enable Register */ | ||
149 | #define REG_GPIO_EN 0x77 | ||
150 | #define REG_GPIO_EN__ENx(x) (1 << ((x) - 4)) | ||
151 | /* GPIO Data Set Register */ | ||
152 | #define REG_GPIO_SET 0x78 | ||
153 | #define REG_GPIO_SET__SETx(x) (1 << ((x) - 4)) | ||
154 | /* GPIO Data Clear Register */ | ||
155 | #define REG_GPIO_CLR 0x79 | ||
156 | #define REG_GPIO_CLR__CLRx(x) (1 << ((x) - 4)) | ||
157 | /* GPIO Data Toggle Register */ | ||
158 | #define REG_GPIO_TOG 0x7a | ||
159 | #define REG_GPIO_TOG__TOGx(x) (1 << ((x) - 4)) | ||
160 | /* Auto-Configuration Control 0 */ | ||
161 | #define REG_AUTO_CONF 0x7b | ||
162 | #define REG_AUTO_CONF__ACE(ace) (ace) | ||
163 | #define REG_AUTO_CONF__ARE(are) ((are) << 1) | ||
164 | #define REG_AUTO_CONF__BVA(bva) ((bva) << 2) | ||
165 | #define REG_AUTO_CONF__RETRY(retry) ((retry) << 4) | ||
166 | #define REG_AUTO_CONF__FFI(ffi) ((ffi) << 6) | ||
167 | /* Auto-Configuration Control 1 */ | ||
168 | #define REG_AUTO_CONF2 0x7c | ||
169 | #define REG_AUTO_CONF2__ACFIE(acfie) (acfie) | ||
170 | #define REG_AUTO_CONF2__ARFIE(arfie) ((arfie) << 1) | ||
171 | #define REG_AUTO_CONF2__OORIE(oorie) ((oorie) << 2) | ||
172 | #define REG_AUTO_CONF2__SCTS(scts) ((scts) << 7) | ||
173 | /* Auto-Configuration Upper-Limit */ | ||
174 | #define REG_USL 0x7d | ||
175 | /* Auto-Configuration Lower-Limit */ | ||
176 | #define REG_LSL 0x7e | ||
177 | /* Auto-Configuration Target Level */ | ||
178 | #define REG_TL 0x7f | ||
179 | /* Soft-Reset */ | ||
180 | #define REG_SOFTRESET 0x80 | ||
181 | #define REG_SOFTRESET__MAGIC 0x63 | ||
182 | /* PWM Control */ | ||
183 | #define REG_PWMx(x) (0x81 + ((x) - 4) / 2) | ||
184 | #define REG_PWMx_IS_PWM0(x) (((x) % 2) == 0) | ||
185 | #define REG_PWMx__PWM0(x) (x) | ||
186 | #define REG_PWMx__PWM0_BM 0xf | ||
187 | #define REG_PWMx__PWM1(x) ((x) << 4) | ||
188 | #define REG_PWMx__PWM1_BM 0xf0 | ||
189 | |||
190 | static int i2c_addr; | ||
191 | |||
192 | static inline int mpr121_write_reg(uint8_t reg, uint8_t data) | ||
193 | { | ||
194 | return i2c_writemem(i2c_addr, reg, &data, 1); | ||
195 | } | ||
196 | |||
197 | static inline int mpr121_read_reg(uint8_t reg, uint8_t *data) | ||
198 | { | ||
199 | return i2c_readmem(i2c_addr, reg, data, 1); | ||
200 | } | ||
201 | |||
202 | int mpr121_init(int dev_i2c_addr) | ||
203 | { | ||
204 | i2c_addr = dev_i2c_addr; | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | int mpr121_soft_reset(void) | ||
209 | { | ||
210 | return mpr121_write_reg(REG_SOFTRESET, REG_SOFTRESET__MAGIC); | ||
211 | } | ||
212 | int mpr121_set_config(struct mpr121_config_t *conf) | ||
213 | { | ||
214 | int ret; | ||
215 | #define safe_write(reg, val) \ | ||
216 | do { ret = mpr121_write_reg(reg, val); \ | ||
217 | if(ret) return ret; } while(0) | ||
218 | /* stop mode */ | ||
219 | safe_write(REG_ELECTRODE, 0); | ||
220 | /* write baseline values */ | ||
221 | for(int i = 0; i < ELECTRODE_COUNT; i++) | ||
222 | safe_write(REG_ExBV(i), conf->ele[i].bv); | ||
223 | /* write eleprox bv */ | ||
224 | safe_write(REG_EPROXBV, conf->eleprox.bv); | ||
225 | /* write global fields */ | ||
226 | safe_write(REG_MHDR, conf->filters.ele.rising.mhd); | ||
227 | safe_write(REG_NHDR, conf->filters.ele.rising.nhd); | ||
228 | safe_write(REG_NCLR, conf->filters.ele.rising.ncl); | ||
229 | safe_write(REG_FDLR, conf->filters.ele.rising.fdl); | ||
230 | safe_write(REG_MHDF, conf->filters.ele.falling.mhd); | ||
231 | safe_write(REG_NHDF, conf->filters.ele.falling.nhd); | ||
232 | safe_write(REG_NCLF, conf->filters.ele.falling.ncl); | ||
233 | safe_write(REG_FDLF, conf->filters.ele.falling.fdl); | ||
234 | safe_write(REG_NHDT, conf->filters.ele.touched.nhd); | ||
235 | safe_write(REG_NCLT, conf->filters.ele.touched.ncl); | ||
236 | safe_write(REG_FDLT, conf->filters.ele.touched.fdl); | ||
237 | safe_write(REG_MHDPROXR, conf->filters.eleprox.rising.mhd); | ||
238 | safe_write(REG_NHDPROXR, conf->filters.eleprox.rising.nhd); | ||
239 | safe_write(REG_NCLPROXR, conf->filters.eleprox.rising.ncl); | ||
240 | safe_write(REG_FDLPROXR, conf->filters.eleprox.rising.fdl); | ||
241 | safe_write(REG_MHDPROXF, conf->filters.eleprox.falling.mhd); | ||
242 | safe_write(REG_NHDPROXF, conf->filters.eleprox.falling.nhd); | ||
243 | safe_write(REG_NCLPROXF, conf->filters.eleprox.falling.ncl); | ||
244 | safe_write(REG_FDLPROXF, conf->filters.eleprox.falling.fdl); | ||
245 | safe_write(REG_NHDPROXT, conf->filters.eleprox.touched.nhd); | ||
246 | safe_write(REG_NCLPROXT, conf->filters.eleprox.touched.ncl); | ||
247 | safe_write(REG_FDLPROXT, conf->filters.eleprox.touched.fdl); | ||
248 | /* touch & release thresholds */ | ||
249 | for(int i = 0; i < ELECTRODE_COUNT; i++) | ||
250 | { | ||
251 | safe_write(REG_ExTTH(i), conf->ele[i].tth); | ||
252 | safe_write(REG_ExRTH(i), conf->ele[i].rth); | ||
253 | } | ||
254 | safe_write(REG_EPROXTTH, conf->eleprox.tth); | ||
255 | safe_write(REG_EPROXRTH, conf->eleprox.rth); | ||
256 | /* debounce */ | ||
257 | safe_write(REG_DEBOUNCE, REG_DEBOUNCE__DR(conf->debounce.dr) | | ||
258 | REG_DEBOUNCE__DT(conf->debounce.dt)); | ||
259 | /* analog-front end and filters */ | ||
260 | safe_write(REG_AFE, REG_AFE__CDC(conf->global.cdc) | | ||
261 | REG_AFE__FFI(conf->global.ffi)); | ||
262 | safe_write(REG_FILTER, REG_FILTER__CDT(conf->global.cdt) | | ||
263 | REG_FILTER__ESI(conf->global.esi) | REG_FILTER__SFI(conf->global.sfi)); | ||
264 | /* electrode charge */ | ||
265 | for(int i = 0; i < ELECTRODE_COUNT; i++) | ||
266 | safe_write(REG_CDCx(i), conf->ele[i].cdc); | ||
267 | safe_write(REG_CDCPROX, conf->eleprox.cdc); | ||
268 | for(int i = 0; i < ELECTRODE_COUNT; i += 2) | ||
269 | { | ||
270 | safe_write(REG_CDTx(i), REG_CDTx__CDT0(conf->ele[i].cdt) | | ||
271 | REG_CDTx__CDT1(conf->ele[i+1].cdt)); | ||
272 | } | ||
273 | safe_write(REG_CDTPROX, conf->eleprox.cdt); | ||
274 | /* Auto-Configuration */ | ||
275 | safe_write(REG_AUTO_CONF, REG_AUTO_CONF__ACE(conf->autoconf.en) | | ||
276 | REG_AUTO_CONF__ARE(conf->autoconf.ren) | | ||
277 | REG_AUTO_CONF__BVA(conf->cal_lock) | | ||
278 | REG_AUTO_CONF__RETRY(conf->autoconf.retry) | | ||
279 | REG_AUTO_CONF__FFI(conf->global.ffi)); | ||
280 | safe_write(REG_AUTO_CONF2, REG_AUTO_CONF2__ACFIE(conf->autoconf.acfie) | | ||
281 | REG_AUTO_CONF2__ARFIE(conf->autoconf.arfie) | | ||
282 | REG_AUTO_CONF2__OORIE(conf->autoconf.oorie) | | ||
283 | REG_AUTO_CONF2__SCTS(conf->autoconf.scts)); | ||
284 | safe_write(REG_USL, conf->autoconf.usl); | ||
285 | safe_write(REG_LSL, conf->autoconf.lsl); | ||
286 | safe_write(REG_TL, conf->autoconf.tl); | ||
287 | /* electrode configuration */ | ||
288 | safe_write(REG_ELECTRODE, REG_ELECTRODE__ELE_EN(conf->ele_en) | | ||
289 | REG_ELECTRODE__ELEPROX_EN(conf->eleprox_en) | | ||
290 | REG_ELECTRODE__CL(conf->cal_lock)); | ||
291 | /* gpio config */ | ||
292 | uint8_t ctl = 0; | ||
293 | for(int i = ELE_GPIO_FIRST; i <= ELE_GPIO_LAST; i++) | ||
294 | if(ELE_GPIO_CTL0(conf->ele[i].gpio)) | ||
295 | ctl |= REG_GPIO_CTL0__CTL0x(i); | ||
296 | safe_write(REG_GPIO_CTL0, ctl); | ||
297 | ctl = 0; | ||
298 | for(int i = ELE_GPIO_FIRST; i <= ELE_GPIO_LAST; i++) | ||
299 | if(ELE_GPIO_CTL1(conf->ele[i].gpio)) | ||
300 | ctl |= REG_GPIO_CTL1__CTL1x(i); | ||
301 | safe_write(REG_GPIO_CTL1, ctl); | ||
302 | ctl = 0; | ||
303 | for(int i = ELE_GPIO_FIRST; i <= ELE_GPIO_LAST; i++) | ||
304 | if(ELE_GPIO_DIR(conf->ele[i].gpio)) | ||
305 | ctl |= REG_GPIO_DIR__DIRx(i); | ||
306 | safe_write(REG_GPIO_DIR, ctl); | ||
307 | ctl = 0; | ||
308 | for(int i = ELE_GPIO_FIRST; i <= ELE_GPIO_LAST; i++) | ||
309 | if(ELE_GPIO_EN(conf->ele[i].gpio)) | ||
310 | ctl |= REG_GPIO_EN__ENx(i); | ||
311 | safe_write(REG_GPIO_EN, ctl); | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | int mpr121_set_gpio_output(int ele, int gpio_val) | ||
317 | { | ||
318 | switch(gpio_val) | ||
319 | { | ||
320 | case ELE_GPIO_SET: | ||
321 | return mpr121_write_reg(REG_GPIO_SET, REG_GPIO_SET__SETx(ele)); | ||
322 | case ELE_GPIO_CLR: | ||
323 | return mpr121_write_reg(REG_GPIO_CLR, REG_GPIO_CLR__CLRx(ele)); | ||
324 | case ELE_GPIO_TOG: | ||
325 | return mpr121_write_reg(REG_GPIO_TOG, REG_GPIO_TOG__TOGx(ele)); | ||
326 | default: | ||
327 | return -1; | ||
328 | } | ||
329 | } | ||
330 | |||
331 | int mpr121_set_gpio_pwm(int ele, int pwm) | ||
332 | { | ||
333 | uint8_t reg_val; | ||
334 | int ret = mpr121_read_reg(REG_PWMx(ele), ®_val); | ||
335 | if(ret) return ret; | ||
336 | if(REG_PWMx_IS_PWM0(ele)) | ||
337 | reg_val = (reg_val & ~REG_PWMx__PWM0_BM) | REG_PWMx__PWM0(pwm); | ||
338 | else | ||
339 | reg_val = (reg_val & ~REG_PWMx__PWM1_BM) | REG_PWMx__PWM1(pwm); | ||
340 | return mpr121_write_reg(REG_PWMx(ele), reg_val); | ||
341 | } | ||
342 | |||
343 | int mpr121_get_touch_status(unsigned *status) | ||
344 | { | ||
345 | uint8_t buf[2]; | ||
346 | int ret = i2c_readmem(i2c_addr, REG_TOUCH_STATUS, buf, 2); | ||
347 | if(!ret && status) | ||
348 | *status = buf[0] | buf[1]; | ||
349 | return ret; | ||
350 | } | ||