0a0ae4dca5f0bafe85525bfa019729de1502cf0c
[apps/native/co2-meter.git] / src / resource / resource_adc_mcp3008.c
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
3  *
4  * Contact: Jin Yoon <jinny.yoon@samsung.com>
5  *          Geunsun Lee <gs86.lee@samsung.com>
6  *          Eunyoung Lee <ey928.lee@samsung.com>
7  *          Junkyu Han <junkyu.han@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an AS IS BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21
22 #include <stdlib.h>
23 #include <peripheral_io.h>
24 #include <system_info.h>
25 #include "resource/resource_co2_sensor.h"
26 #include "log.h"
27
28 #define MCP3008_SPEED 3600000
29 #define MCP3008_BPW 8
30
31 #define MCP3008_TX_WORD1     0x01       /* 0b00000001 */
32 #define MCP3008_TX_CH0 0x80     /* 0b10000000 */
33 #define MCP3008_TX_CH1 0x90     /* 0b10010000 */
34 #define MCP3008_TX_CH2 0xA0     /* 0b10100000 */
35 #define MCP3008_TX_CH3 0xB0     /* 0b10110000 */
36 #define MCP3008_TX_CH4 0xC0     /* 0b11000000 */
37 #define MCP3008_TX_CH5 0xD0     /* 0b11010000 */
38 #define MCP3008_TX_CH6 0xE0     /* 0b11100000 */
39 #define MCP3008_TX_CH7 0xF0     /* 0b11110000 */
40 #define MCP3008_TX_WORD3     0x00       /* 0b00000000 */
41
42 #define MCP3008_RX_WORD1_MASK 0x00      /* 0b00000000 */
43 #define MCP3008_RX_WORD2_NULL_BIT_MASK 0x04     /* 0b00000100 */
44 #define MCP3008_RX_WORD2_MASK 0x03      /* 0b00000011 */
45 #define MCP3008_RX_WORD3_MASK 0xFF      /* 0b11111111 */
46 #define UINT10_VALIDATION_MASK 0x3FF
47
48 #define MODEL_NAME_KEY "http://tizen.org/system/model_name"
49 #define MODEL_NAME_RPI3 "rpi3"
50 #define MODEL_NAME_ARTIK "artik"
51
52 static peripheral_spi_h MCP3008_H = NULL;
53 static unsigned int ref_count = 0;
54
55 #define retv_if(expr, val) do { \
56         if (expr) { \
57                 ERR("(%s) -> %s() return", #expr, __FUNCTION__); \
58                 return (val); \
59         } \
60 } while (0)
61
62 int resource_adc_mcp3008_init(void)
63 {
64         int ret = 0;
65         int bus = -1;
66         char *model_name = NULL;
67
68         if (MCP3008_H) {
69                 DBG("SPI device already initialized [ref_count : %u]", ref_count);
70                 MUTEX_LOCK;
71                 ref_count++;
72                 MUTEX_UNLOCK;
73                 return 0;
74         }
75
76         system_info_get_platform_string(MODEL_NAME_KEY, &model_name);
77         if (!model_name) {
78                 ERR("fail to get model name");
79                 return -1;
80         }
81
82         if (!strcmp(model_name, MODEL_NAME_RPI3)) {
83                 bus = 0;
84         } else if (!strcmp(model_name, MODEL_NAME_ARTIK)) {
85                 bus = 2;        // ARTIK (2)
86         } else {
87                 ERR("unknown model name : %s", model_name);
88                 free(model_name);
89                 return -1;
90         }
91         DBG("%s model_name: %s, bus: %d", __func__, model_name, bus);
92         free(model_name);
93         model_name = NULL;
94
95         ret = peripheral_spi_open(bus, 0, &MCP3008_H);
96         if (PERIPHERAL_ERROR_NONE != ret) {
97                 ERR("spi open failed :%s ", get_error_message(ret));
98                 return -1;
99         }
100
101         ret = peripheral_spi_set_mode(MCP3008_H, PERIPHERAL_SPI_MODE_0);
102         if (PERIPHERAL_ERROR_NONE != ret) {
103                 ERR("peripheral_spi_set_mode failed :%s ", get_error_message(ret));
104                 goto error_after_open;
105         }
106         ret = peripheral_spi_set_bit_order(MCP3008_H, PERIPHERAL_SPI_BIT_ORDER_MSB);
107         if (PERIPHERAL_ERROR_NONE != ret) {
108                 ERR("peripheral_spi_set_bit_order failed :%s ", get_error_message(ret));
109                 goto error_after_open;
110         }
111
112         ret = peripheral_spi_set_bits_per_word(MCP3008_H, MCP3008_BPW);
113         if (PERIPHERAL_ERROR_NONE != ret) {
114                 ERR("peripheral_spi_set_bits_per_word failed :%s ", get_error_message(ret));
115                 goto error_after_open;
116         }
117
118         ret = peripheral_spi_set_frequency(MCP3008_H, MCP3008_SPEED);
119         if (PERIPHERAL_ERROR_NONE != ret) {
120                 ERR("peripheral_spi_set_frequency failed :%s ", get_error_message(ret));
121                 goto error_after_open;
122         }
123         DBG("%s success: %d", __func__, ref_count);
124
125         MUTEX_LOCK;
126         ref_count++;
127         MUTEX_UNLOCK;
128
129         return 0;
130
131 error_after_open:
132         DBG("%s error: %d", __func__, ref_count);
133         peripheral_spi_close(MCP3008_H);
134         MCP3008_H = NULL;
135         return -1;
136 }
137
138 int resource_read_adc_mcp3008(int ch_num, unsigned int *out_value)
139 {
140         static int spi_read_cnt = 0;
141         static int spi_err_cnt = 0;
142         unsigned char rx[3] = {0, };
143         unsigned char tx[3] = {0, };
144         unsigned char rx_w1 = 0;
145         unsigned char rx_w2 = 0;
146         unsigned char rx_w2_nb = 0;
147         unsigned char rx_w3 = 0;
148         unsigned short int result = 0;
149
150         retv_if(MCP3008_H == NULL, -1);
151         retv_if(out_value == NULL, -1);
152         retv_if((ch_num < 0 || ch_num > 7), -1);
153
154         tx[0] = MCP3008_TX_WORD1;
155         switch (ch_num) {
156         case 0:
157                 tx[1] = MCP3008_TX_CH0;
158                 break;
159         case 1:
160                 tx[1] = MCP3008_TX_CH1;
161                 break;
162         case 2:
163                 tx[1] = MCP3008_TX_CH2;
164                 break;
165         case 3:
166                 tx[1] = MCP3008_TX_CH3;
167                 break;
168         case 4:
169                 tx[1] = MCP3008_TX_CH4;
170                 break;
171         case 5:
172                 tx[1] = MCP3008_TX_CH5;
173                 break;
174         case 6:
175                 tx[1] = MCP3008_TX_CH6;
176                 break;
177         case 7:
178                 tx[1] = MCP3008_TX_CH7;
179                 break;
180         default:
181                 tx[1] = MCP3008_TX_CH0;
182                 break;
183         }
184         tx[2] = MCP3008_TX_WORD3;
185
186         peripheral_spi_transfer(MCP3008_H, tx, rx, 3);
187
188         rx_w1 = rx[0] & MCP3008_RX_WORD1_MASK;
189         rx_w2_nb = rx[1] & MCP3008_RX_WORD2_NULL_BIT_MASK;
190
191         // retv_if(rx_w1 != 0, -1);
192         // retv_if(rx_w2_nb != 0, -1);
193         spi_read_cnt += 1;
194         if (rx_w1 != 0 || rx_w2_nb != 0)
195         {
196                 spi_err_cnt++;
197                 if (spi_err_cnt >= 100)
198                 {
199                         DBG("resource_read_adc_mcp3008 rx_w2_nb is not 0 -> rx: %02x, count: %d", rx[1], spi_read_cnt);
200                         spi_err_cnt = 0;
201                 }
202                 return -1;
203         }
204
205         rx_w2 = rx[1] & MCP3008_RX_WORD2_MASK;
206         rx_w3 = rx[2] & MCP3008_RX_WORD3_MASK;
207
208         result = ((rx_w2 << 8) | (rx_w3)) & UINT10_VALIDATION_MASK;
209
210         *out_value = result;
211
212         return 0;
213 }
214
215 void resource_adc_mcp3008_fini(void)
216 {
217         if (MCP3008_H) {
218                 MUTEX_LOCK;
219                 ref_count--;
220                 MUTEX_UNLOCK;
221         }
222         else
223                 return;
224
225         if (ref_count == 0) {
226                 peripheral_spi_close(MCP3008_H);
227                 MCP3008_H = NULL;
228         }
229 }
230