7fa645c2eedb0362f3346dd69b1e55de6c3f8ebb
[apps/native/gear-racing-car.git] / src / pca9685.c
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
3  *
4  * Contact: Jeonghoon Park <jh1979.park@samsung.com>
5  *
6  * Licensed under the Flora License, Version 1.1 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://floralicense.org/license/
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an AS IS BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <math.h>
22 #include <peripheral_io.h>
23 #include "log.h"
24
25 #define RPI3_I2C_BUS 1
26
27 /* Registers/etc: */
28 #define PCA9685_ADDRESS    0x40
29 #define MODE1              0x00
30 #define MODE2              0x01
31 #define SUBADR1            0x02
32 #define SUBADR2            0x03
33 #define SUBADR3            0x04
34 #define PRESCALE           0xFE
35 #define LED0_ON_L          0x06
36 #define LED0_ON_H          0x07
37 #define LED0_OFF_L         0x08
38 #define LED0_OFF_H         0x09
39 #define ALL_LED_ON_L       0xFA
40 #define ALL_LED_ON_H       0xFB
41 #define ALL_LED_OFF_L      0xFC
42 #define ALL_LED_OFF_H      0xFD
43
44 /* Bits: */
45 #define RESTART            0x80
46 #define SLEEP              0x10
47 #define ALLCALL            0x01
48 #define INVRT              0x10
49 #define OUTDRV             0x04
50
51 static peripheral_i2c_h g_i2c_h = NULL;
52
53 int pca9685_set_frequency(unsigned int freq_hz)
54 {
55         int ret = PERIPHERAL_ERROR_NONE;
56         double prescale_value = 0.0;
57         int prescale = 0;
58         uint8_t oldmode = 0;
59         uint8_t newmode = 0;
60
61         prescale_value = 25000000.0;    // 25MHz
62         prescale_value /= 4096.0;       // 12-bit
63         prescale_value /= (double)freq_hz;
64         prescale_value -= 1.0;
65
66         prescale = (int)floor(prescale_value + 0.5);
67
68         ret = peripheral_i2c_read_register_byte(g_i2c_h, MODE1, &oldmode);
69         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to read register");
70
71         newmode = (oldmode & 0x7F) | 0x10; // sleep
72         ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, newmode); // go to sleep
73         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
74
75         ret = peripheral_i2c_write_register_byte(g_i2c_h, PRESCALE, prescale);
76         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
77
78         ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, oldmode);
79         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
80
81         usleep(500);
82
83         ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, (oldmode | 0x80));
84         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
85
86         return 0;
87 }
88
89 int pca9685_set_value_to_channel(unsigned int channel, int on, int off)
90 {
91         int ret = PERIPHERAL_ERROR_NONE;
92         retvm_if(g_i2c_h == NULL, -1, "Not initialized yet");
93
94         ret = peripheral_i2c_write_register_byte(g_i2c_h,
95                         LED0_ON_L + 4*channel, on & 0xFF);
96         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
97
98         ret = peripheral_i2c_write_register_byte(g_i2c_h,
99                         LED0_ON_H + 4*channel, on >> 8);
100         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
101
102         ret = peripheral_i2c_write_register_byte(g_i2c_h,
103                         LED0_OFF_L + 4*channel, off & 0xFF);
104         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
105
106         ret = peripheral_i2c_write_register_byte(g_i2c_h,
107                         LED0_OFF_H + 4*channel, off >> 8);
108         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
109
110         return 0;
111 }
112
113 int pca9685_set_value_to_all(int on, int off)
114 {
115         int ret = PERIPHERAL_ERROR_NONE;
116         retvm_if(g_i2c_h == NULL, -1, "Not initialized yet");
117
118         ret = peripheral_i2c_write_register_byte(g_i2c_h,
119                 ALL_LED_ON_L, on & 0xFF);
120         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
121
122         ret = peripheral_i2c_write_register_byte(g_i2c_h,
123                 ALL_LED_ON_H, on >> 8);
124         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
125
126         ret = peripheral_i2c_write_register_byte(g_i2c_h,
127                 ALL_LED_OFF_L, off & 0xFF);
128         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
129
130         ret = peripheral_i2c_write_register_byte(g_i2c_h,
131                 ALL_LED_OFF_H, off >> 8);
132         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
133
134         return 0;
135 }
136
137 int pca9685_init(void)
138 {
139         uint8_t mode1 = 0;
140
141         int ret = PERIPHERAL_ERROR_NONE;
142         ret = peripheral_i2c_open(RPI3_I2C_BUS, PCA9685_ADDRESS, &g_i2c_h);
143         if (ret != PERIPHERAL_ERROR_NONE) {
144                 _E("failed to open pca9685-[bus:%d, addr:%d]",
145                         RPI3_I2C_BUS, PCA9685_ADDRESS);
146                 return -1;
147         }
148         ret = pca9685_set_value_to_all(0, 0);
149         retvm_if(ret, -1, "failed to set value to register");
150
151         ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE2, OUTDRV);
152         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
153
154         ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, ALLCALL);
155         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
156
157         usleep(500); // wait for oscillator
158
159         ret = peripheral_i2c_read_register_byte(g_i2c_h, MODE1, &mode1);
160         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to read register");
161
162         mode1 = mode1 & (~SLEEP); // # wake up (reset sleep)
163         ret = peripheral_i2c_write_register_byte(g_i2c_h, MODE1, mode1);
164         retvm_if(ret != PERIPHERAL_ERROR_NONE, -1, "failed to write register");
165
166         usleep(500); // wait for oscillator
167
168         return 0;
169 }
170
171 int pca9685_fini(void)
172 {
173         if (g_i2c_h) {
174                 peripheral_i2c_close(g_i2c_h);
175                 g_i2c_h = NULL;
176         }
177
178         return 0;
179 }