summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx233/creative-zenxfi3/mpr121-zenxfi3.c
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2016-05-30 16:24:38 +0100
committerAmaury Pouly <amaury.pouly@gmail.com>2016-06-01 23:09:27 +0200
commitd42a4a4eb4bc20fda41543b8b831c1970723346f (patch)
treef6ba16e95c61e441c1f110131b17a710c785285c /firmware/target/arm/imx233/creative-zenxfi3/mpr121-zenxfi3.c
parentb2afd931e2d83ce346811a68a34ee56c48be6d35 (diff)
downloadrockbox-d42a4a4eb4bc20fda41543b8b831c1970723346f.tar.gz
rockbox-d42a4a4eb4bc20fda41543b8b831c1970723346f.zip
zenxfi3: rewrite mpr121 driver
The new driver uses an asynchronous architecture for touch status reading. Change-Id: Ic75a8b91bc47ee16c3af873afde178cd70186376
Diffstat (limited to 'firmware/target/arm/imx233/creative-zenxfi3/mpr121-zenxfi3.c')
-rw-r--r--firmware/target/arm/imx233/creative-zenxfi3/mpr121-zenxfi3.c236
1 files changed, 236 insertions, 0 deletions
diff --git a/firmware/target/arm/imx233/creative-zenxfi3/mpr121-zenxfi3.c b/firmware/target/arm/imx233/creative-zenxfi3/mpr121-zenxfi3.c
new file mode 100644
index 0000000000..23fcc7f0e4
--- /dev/null
+++ b/firmware/target/arm/imx233/creative-zenxfi3/mpr121-zenxfi3.c
@@ -0,0 +1,236 @@
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 "kernel.h"
25#include "usb.h"
26#include "mpr121.h"
27#include "mpr121-zenxfi3.h"
28#include "i2c-imx233.h"
29#include "pinctrl-imx233.h"
30
31#define MPR121_I2C_ADDR 0xb4
32
33/* NOTE on the architecture of the driver
34 *
35 * All non-time-critical operations (setup, gpio/pwm changes) are done with
36 * blocking i2c transfers to make the code simpler. Since reading the touch
37 * status is time critical, it is done asynchronously: when the IRQ pin is
38 * asserted, it will disable IRQ pin sensing and trigger an asynchronous i2c
39 * transfer to read touch status. When the transfer finishes, the driver will
40 * renable IRQ pin sensing. */
41
42static unsigned touch_status = 0; /* touch bitmask as reported by mpr121 */
43static struct imx233_i2c_xfer_t read_status_xfer; /* async transfer to read touch status */
44static uint8_t read_status_sel_reg; /* buffer for async transfer operation */
45static uint8_t read_status_buf[2]; /* buffer for async transfer operation */
46
47static void mpr121_irq_cb(int bank, int pin, intptr_t user);
48
49static void touch_status_i2c_cb(struct imx233_i2c_xfer_t *xfer, enum imx233_i2c_error_t status)
50{
51 (void) xfer;
52 (void) status;
53 /* put status in the global variable */
54 touch_status = read_status_buf[0] | read_status_buf[1] << 8;
55 /* start sensing IRQ pin again */
56 imx233_pinctrl_setup_irq(0, 18, true, true, false, &mpr121_irq_cb, 0);
57}
58
59void mpr121_irq_cb(int bank, int pin, intptr_t user)
60{
61 (void) bank;
62 (void) pin;
63 (void) user;
64 /* NOTE the callback will not be fired until interrupt is enabled back.
65 *
66 * now setup an asynchronous i2c transfer to read touch status register,
67 * this is a readmem operation with a first stage to select register
68 * and a second stage to read status (2 bytes) */
69 read_status_sel_reg = REG_TOUCH_STATUS;
70
71 read_status_xfer.next = NULL;
72 read_status_xfer.fast_mode = true;
73 read_status_xfer.dev_addr = MPR121_I2C_ADDR;
74 read_status_xfer.mode = I2C_READ;
75 read_status_xfer.count[0] = 1; /* set touch status register address */
76 read_status_xfer.data[0] = &read_status_sel_reg;
77 read_status_xfer.count[1] = 2;
78 read_status_xfer.data[1] = &read_status_buf;
79 read_status_xfer.tmo_ms = 1000;
80 read_status_xfer.callback = &touch_status_i2c_cb;
81
82 imx233_i2c_transfer(&read_status_xfer);
83}
84
85static inline int mpr121_write_reg(uint8_t reg, uint8_t data)
86{
87 return i2c_writemem(MPR121_I2C_ADDR, reg, &data, 1);
88}
89
90static inline int mpr121_read_reg(uint8_t reg, uint8_t *data)
91{
92 return i2c_readmem(MPR121_I2C_ADDR, reg, data, 1);
93}
94
95void mpr121_init(void)
96{
97 /* soft reset */
98 mpr121_write_reg(REG_SOFTRESET, REG_SOFTRESET__MAGIC);
99 /* enable interrupt */
100 imx233_pinctrl_acquire(0, 18, "mpr121_int");
101 imx233_pinctrl_set_function(0, 18, PINCTRL_FUNCTION_GPIO);
102 imx233_pinctrl_enable_gpio(0, 18, false);
103 imx233_pinctrl_setup_irq(0, 18, true, true, false, &mpr121_irq_cb, 0);
104}
105
106void mpr121_set_config(struct mpr121_config_t *conf)
107{
108 /* stop mode */
109 mpr121_write_reg(REG_ELECTRODE, 0);
110 /* write baseline values */
111 for(int i = 0; i < ELECTRODE_COUNT; i++)
112 mpr121_write_reg(REG_ExBV(i), conf->ele[i].bv);
113 /* write eleprox bv */
114 mpr121_write_reg(REG_EPROXBV, conf->eleprox.bv);
115 /* write global fields */
116 mpr121_write_reg(REG_MHDR, conf->filters.ele.rising.mhd);
117 mpr121_write_reg(REG_NHDR, conf->filters.ele.rising.nhd);
118 mpr121_write_reg(REG_NCLR, conf->filters.ele.rising.ncl);
119 mpr121_write_reg(REG_FDLR, conf->filters.ele.rising.fdl);
120 mpr121_write_reg(REG_MHDF, conf->filters.ele.falling.mhd);
121 mpr121_write_reg(REG_NHDF, conf->filters.ele.falling.nhd);
122 mpr121_write_reg(REG_NCLF, conf->filters.ele.falling.ncl);
123 mpr121_write_reg(REG_FDLF, conf->filters.ele.falling.fdl);
124 mpr121_write_reg(REG_NHDT, conf->filters.ele.touched.nhd);
125 mpr121_write_reg(REG_NCLT, conf->filters.ele.touched.ncl);
126 mpr121_write_reg(REG_FDLT, conf->filters.ele.touched.fdl);
127 mpr121_write_reg(REG_MHDPROXR, conf->filters.eleprox.rising.mhd);
128 mpr121_write_reg(REG_NHDPROXR, conf->filters.eleprox.rising.nhd);
129 mpr121_write_reg(REG_NCLPROXR, conf->filters.eleprox.rising.ncl);
130 mpr121_write_reg(REG_FDLPROXR, conf->filters.eleprox.rising.fdl);
131 mpr121_write_reg(REG_MHDPROXF, conf->filters.eleprox.falling.mhd);
132 mpr121_write_reg(REG_NHDPROXF, conf->filters.eleprox.falling.nhd);
133 mpr121_write_reg(REG_NCLPROXF, conf->filters.eleprox.falling.ncl);
134 mpr121_write_reg(REG_FDLPROXF, conf->filters.eleprox.falling.fdl);
135 mpr121_write_reg(REG_NHDPROXT, conf->filters.eleprox.touched.nhd);
136 mpr121_write_reg(REG_NCLPROXT, conf->filters.eleprox.touched.ncl);
137 mpr121_write_reg(REG_FDLPROXT, conf->filters.eleprox.touched.fdl);
138 /* touch & release thresholds */
139 for(int i = 0; i < ELECTRODE_COUNT; i++)
140 {
141 mpr121_write_reg(REG_ExTTH(i), conf->ele[i].tth);
142 mpr121_write_reg(REG_ExRTH(i), conf->ele[i].rth);
143 }
144 mpr121_write_reg(REG_EPROXTTH, conf->eleprox.tth);
145 mpr121_write_reg(REG_EPROXRTH, conf->eleprox.rth);
146 /* debounce */
147 mpr121_write_reg(REG_DEBOUNCE, REG_DEBOUNCE__DR(conf->debounce.dr) |
148 REG_DEBOUNCE__DT(conf->debounce.dt));
149 /* analog-front end and filters */
150 mpr121_write_reg(REG_AFE, REG_AFE__CDC(conf->global.cdc) |
151 REG_AFE__FFI(conf->global.ffi));
152 mpr121_write_reg(REG_FILTER, REG_FILTER__CDT(conf->global.cdt) |
153 REG_FILTER__ESI(conf->global.esi) | REG_FILTER__SFI(conf->global.sfi));
154 /* electrode charge */
155 for(int i = 0; i < ELECTRODE_COUNT; i++)
156 mpr121_write_reg(REG_CDCx(i), conf->ele[i].cdc);
157 mpr121_write_reg(REG_CDCPROX, conf->eleprox.cdc);
158 for(int i = 0; i < ELECTRODE_COUNT; i += 2)
159 {
160 mpr121_write_reg(REG_CDTx(i), REG_CDTx__CDT0(conf->ele[i].cdt) |
161 REG_CDTx__CDT1(conf->ele[i+1].cdt));
162 }
163 mpr121_write_reg(REG_CDTPROX, conf->eleprox.cdt);
164 /* Auto-Configuration */
165 mpr121_write_reg(REG_AUTO_CONF, REG_AUTO_CONF__ACE(conf->autoconf.en) |
166 REG_AUTO_CONF__ARE(conf->autoconf.ren) |
167 REG_AUTO_CONF__BVA(conf->cal_lock) |
168 REG_AUTO_CONF__RETRY(conf->autoconf.retry) |
169 REG_AUTO_CONF__FFI(conf->global.ffi));
170 mpr121_write_reg(REG_AUTO_CONF2, REG_AUTO_CONF2__ACFIE(conf->autoconf.acfie) |
171 REG_AUTO_CONF2__ARFIE(conf->autoconf.arfie) |
172 REG_AUTO_CONF2__OORIE(conf->autoconf.oorie) |
173 REG_AUTO_CONF2__SCTS(conf->autoconf.scts));
174 mpr121_write_reg(REG_USL, conf->autoconf.usl);
175 mpr121_write_reg(REG_LSL, conf->autoconf.lsl);
176 mpr121_write_reg(REG_TL, conf->autoconf.tl);
177 /* electrode configuration */
178 mpr121_write_reg(REG_ELECTRODE, REG_ELECTRODE__ELE_EN(conf->ele_en) |
179 REG_ELECTRODE__ELEPROX_EN(conf->eleprox_en) |
180 REG_ELECTRODE__CL(conf->cal_lock));
181 /* gpio config */
182 uint8_t ctl = 0;
183 for(int i = ELE_GPIO_FIRST; i <= ELE_GPIO_LAST; i++)
184 if(ELE_GPIO_CTL0(conf->ele[i].gpio))
185 ctl |= REG_GPIO_CTL0__CTL0x(i);
186 mpr121_write_reg(REG_GPIO_CTL0, ctl);
187 ctl = 0;
188 for(int i = ELE_GPIO_FIRST; i <= ELE_GPIO_LAST; i++)
189 if(ELE_GPIO_CTL1(conf->ele[i].gpio))
190 ctl |= REG_GPIO_CTL1__CTL1x(i);
191 mpr121_write_reg(REG_GPIO_CTL1, ctl);
192 ctl = 0;
193 for(int i = ELE_GPIO_FIRST; i <= ELE_GPIO_LAST; i++)
194 if(ELE_GPIO_DIR(conf->ele[i].gpio))
195 ctl |= REG_GPIO_DIR__DIRx(i);
196 mpr121_write_reg(REG_GPIO_DIR, ctl);
197 ctl = 0;
198 for(int i = ELE_GPIO_FIRST; i <= ELE_GPIO_LAST; i++)
199 if(ELE_GPIO_EN(conf->ele[i].gpio))
200 ctl |= REG_GPIO_EN__ENx(i);
201 mpr121_write_reg(REG_GPIO_EN, ctl);
202}
203
204void mpr121_set_gpio_output(int ele, int gpio_val)
205{
206 switch(gpio_val)
207 {
208 case ELE_GPIO_SET:
209 mpr121_write_reg(REG_GPIO_SET, REG_GPIO_SET__SETx(ele));
210 break;
211 case ELE_GPIO_CLR:
212 mpr121_write_reg(REG_GPIO_CLR, REG_GPIO_CLR__CLRx(ele));
213 break;
214 case ELE_GPIO_TOG:
215 mpr121_write_reg(REG_GPIO_TOG, REG_GPIO_TOG__TOGx(ele));
216 break;
217 default:
218 break;
219 }
220}
221
222void mpr121_set_gpio_pwm(int ele, int pwm)
223{
224 uint8_t reg_val;
225 mpr121_read_reg(REG_PWMx(ele), &reg_val);
226 if(REG_PWMx_IS_PWM0(ele))
227 reg_val = (reg_val & ~REG_PWMx__PWM0_BM) | REG_PWMx__PWM0(pwm);
228 else
229 reg_val = (reg_val & ~REG_PWMx__PWM1_BM) | REG_PWMx__PWM1(pwm);
230 mpr121_write_reg(REG_PWMx(ele), reg_val);
231}
232
233unsigned mpr121_get_touch_status(void)
234{
235 return touch_status;
236}