1 /*
2  * Author: Jon Trulson <jtrulson@ics.com>
3  * Copyright (c) 2015 Intel Corporation.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include <unistd.h>
26 #include <math.h>
27 #include <iostream>
28 #include <string>
29 #include <stdexcept>
30 
31 #include "at42qt1070.h"
32 
33 using namespace upm;
34 using namespace std;
35 
36 
AT42QT1070(int bus,uint8_t address)37 AT42QT1070::AT42QT1070(int bus, uint8_t address)
38 {
39     m_addr = address;
40 
41     // setup our i2c link
42     if (!(m_i2c = mraa_i2c_init(bus))) {
43         throw std::invalid_argument(std::string(__FUNCTION__) +
44                                     ": mraa_i2c_init() failed");
45         return;
46     }
47 
48     mraa_result_t rv;
49 
50     if ((rv = mraa_i2c_address(m_i2c, m_addr)) != MRAA_SUCCESS) {
51         throw std::invalid_argument(std::string(__FUNCTION__) +
52                                     ": mraa_i2c_address() failed");
53         return;
54     }
55 
56     if (readChipID() != 0x2E) {
57         throw std::runtime_error("Chip ID does not match the expected value (2Eh)");
58     }
59 
60     m_buttonStates = 0;
61     m_calibrating = false;
62     m_overflow = false;
63 }
64 
~AT42QT1070()65 AT42QT1070::~AT42QT1070()
66 {
67     mraa_i2c_stop(m_i2c);
68 }
69 
70 bool
writeByte(uint8_t reg,uint8_t byte)71 AT42QT1070::writeByte(uint8_t reg, uint8_t byte)
72 {
73     mraa_result_t rv = mraa_i2c_write_byte_data(m_i2c, byte, reg);
74 
75     if (rv != MRAA_SUCCESS) {
76         throw std::runtime_error(std::string(__FUNCTION__) +
77                                  ": mraa_i2c_write_byte() failed");
78         return false;
79     }
80 
81     return true;
82 }
83 
84 bool
writeWord(uint8_t reg,uint16_t word)85 AT42QT1070::writeWord(uint8_t reg, uint16_t word)
86 {
87     mraa_result_t rv = mraa_i2c_write_word_data(m_i2c, word, reg);
88 
89     if (rv != MRAA_SUCCESS) {
90         throw std::runtime_error(std::string(__FUNCTION__) +
91                                  ": mraa_i2c_write_word() failed");
92         return false;
93     }
94 
95     return true;
96 }
97 
98 uint8_t
readByte(uint8_t reg)99 AT42QT1070::readByte(uint8_t reg)
100 {
101     return mraa_i2c_read_byte_data(m_i2c, reg);
102 }
103 
104 uint16_t
readWord(uint8_t reg)105 AT42QT1070::readWord(uint8_t reg)
106 {
107     return mraa_i2c_read_word_data(m_i2c, reg);
108 }
109 
110 uint8_t
readChipID(void)111 AT42QT1070::readChipID(void)
112 {
113     return readByte(REG_CHIPID);
114 }
115 
116 void
updateState()117 AT42QT1070::updateState()
118 {
119     uint8_t stat = readByte(REG_DETSTATUS);
120 
121     // if we are calibrating, don't change anything
122     if (stat & DET_CALIBRATE) {
123         m_calibrating = true;
124         return;
125     } else {
126         m_calibrating = false;
127     }
128 
129     if (stat & DET_OVERFLOW)
130         m_overflow = true;
131     else
132         m_overflow = false;
133 
134     // if a touch is occurring, read the button states
135     if (stat & DET_TOUCH) {
136         uint8_t keys = readByte(REG_KEYSTATUS);
137         // high bit is reserved, filter it out
138         m_buttonStates = keys & ~0x80;
139     } else {
140         m_buttonStates = 0;
141     }
142 }
143 
144 uint8_t
getLPMode(void)145 AT42QT1070::getLPMode(void)
146 {
147     return readByte(REG_LP);
148 }
149 
150 uint8_t
setLPMode(uint8_t mode)151 AT42QT1070::setLPMode(uint8_t mode)
152 {
153     writeByte(REG_LP, mode);
154 
155     return getLPMode();
156 }
157 
158 uint8_t
getAVE(uint8_t key)159 AT42QT1070::getAVE(uint8_t key)
160 {
161     uint8_t value, ave;
162 
163     if (key > 6) {
164         throw std::invalid_argument("Only keys 0-6 are allowed");
165     }
166 
167     value = readByte(REG_AVE0 + key);
168     ave = (value & 0xFC) >> 2;
169 
170     return ave;
171 }
172 
173 uint8_t
setAVE(uint8_t key,uint8_t ave)174 AT42QT1070::setAVE(uint8_t key, uint8_t ave)
175 {
176     uint8_t value;
177 
178     if (key > 6) {
179         throw std::invalid_argument("Only keys 0-6 are allowed");
180     }
181 
182     switch (ave) {
183         case 1:
184         case 2:
185         case 4:
186         case 8:
187         case 16:
188         case 32:
189             break;
190 
191         default:
192             throw std::invalid_argument("Invalid averaging factor");
193     }
194 
195     value = readByte(REG_AVE0 + key);
196     value = value & 0x03;
197     value = value | (ave << 2);
198     writeByte(REG_AVE0 + key, value);
199 
200     return getAVE(key);
201 }
202 
203 uint8_t
getAKSGroup(uint8_t key)204 AT42QT1070::getAKSGroup(uint8_t key)
205 {
206     uint8_t value, aks;
207 
208     if (key > 6) {
209         throw std::invalid_argument("Only keys 0-6 are allowed");
210     }
211 
212     value = readByte(REG_AVE0 + key);
213     aks = value & 0x03;
214 
215     return aks;
216 }
217 
218 uint8_t
setAKSGroup(uint8_t key,uint8_t group)219 AT42QT1070::setAKSGroup(uint8_t key, uint8_t group)
220 {
221     uint8_t value;
222 
223     if (key > 6) {
224         throw std::invalid_argument("Only keys 0-6 are allowed");
225     }
226 
227     if (group > 3) {
228         throw std::invalid_argument("Only groups 0-3 are allowed");
229     }
230 
231     value = readByte(REG_AVE0 + key);
232     value = value & 0xFC;
233     value = value | group;
234 
235     writeByte(REG_AVE0 + key, value);
236 
237     return getAKSGroup(key);
238 }
239 
240 bool
reset()241 AT42QT1070::reset()
242 {
243     // write a non-zero value to the reset register
244     return writeByte(REG_RESET, 0xff);
245 }
246 
247 bool
calibrate()248 AT42QT1070::calibrate()
249 {
250     // write a non-zero value to the calibrate register
251     return writeByte(REG_CALIBRATE, 0xff);
252 }
253