Added i2cp tools for TLV320AIC2x chips (in BT200 phones, at least)
[firmerware] / bin / i2cp / aic2x-setup.c
1 /* aic20x-config.c -- setup individual TLV320AIC2x registers over I2C
2  *
3  * This file is provided as part of 0cpm Firmerware.
4  *
5  * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
6  *
7  * 0cpm Firmerware is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation, version 3.
10  *
11  * 0cpm Firmerware is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20
21 /*
22  * Note: If this program works (which it does), it proves that the
23  * subregisters may be addressed directly by way of the distinguishing
24  * top bits.  This is not documented in the datasheet, but that is
25  * indeed not the best bit of technical work that TI has accomplished.
26  */
27
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <stdint.h>
32 #include <stdbool.h>
33
34 #include <fcntl.h>
35 #include <string.h>
36
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <sys/ioctl.h>
40
41 #include <linux/i2c-dev.h>
42
43
44 #define INTERPOLL_WAIT_MS 5
45
46
47 const char *  regname [13] = { "1", "2", "3A", "3B", "3C", "3D", "4", "5A", "5B", "5C", "5D", "6A", "6B" };
48 const uint8_t regmask [13] = { 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80 };
49 const uint8_t regseln [13] = { 0x00, 0x00, 0x00, 0x40, 0x80, 0xc0, 0x00, 0x00, 0x40, 0x80, 0xc0, 0x00, 0x80 };
50
51 uint8_t argval (char *strval) {
52         long intval;
53         int base = 10;
54         char *postfix;
55         if (strncasecmp (strval, "0x", 2) == 0) {
56                 base = 16;
57                 strval += 2;
58         } else if (*strval == '0') {
59                 base = 8;
60         } else if (! *strval) {
61                 strval = "(empty)";     // Cause error later
62         }
63         intval = strtol (strval, &postfix, base);
64         if ((*postfix) || (intval < 0) || (intval > 255)) {
65                 fprintf (stderr, "Value error: Value %s should be an integer in the range 0x00 to 0xff\n", strval);
66                 exit (1);
67         }
68         return (uint8_t) intval;
69 }
70
71 int main (int argc, char *argv []) {
72         int i;
73         uint8_t regs [13];
74         uint8_t slave;
75
76         if (argc < 4) {
77                 fprintf (stderr, "Usage: %s /dev/i2c-N SLAVEADDR REGISTER=VALUE\n"
78                         "\tThe slave address is usually 0x40, 0x41, ... 0x4f\n"
79                         "\tThe register may be a subregister, the value is a number\n"
80                         "\tNumbers may be prefixed with 0 for octal, or 0x for hex\n"
81                         "\tNote: All subregister indexes are assumed to be zero\n",
82                         argv [0]);
83                 exit (1);
84         }
85
86         slave = argval (argv [2]);
87         printf ("Slave address 0x%02x, channel %d\n", slave, slave & 0x0f);
88         if ((slave < 0x40) || (slave > 0x4f)) {
89                 fprintf (stderr, "Warning: The slave address usually falls in the range 0x40 to 0x4f\n");
90                 sleep (5);
91         }
92
93         int bus = open (argv [1], O_RDWR);
94         if (bus < 0) {
95                 perror ("Failed to open I2C bus");
96                 exit (1);
97         }
98         ioctl (bus, I2C_TIMEOUT, 1);
99         ioctl (bus, I2C_RETRIES, 2);
100
101         if (ioctl (bus, I2C_SLAVE, slave) == -1) {
102                 perror ("Failed to set channel as address");
103                 exit (1);
104         }
105
106         for (i=0; i < argc-3; i++) {
107                 char *strval = argv [3+i];
108                 int reglen = 0;
109                 if ((!*strval) || (!strval [1]) || (!strval [2])) {
110                         fprintf (stderr, "Argument too short, specify REGISTER=VALUE for %s\n", strval);
111                         exit (1);
112                 }
113                 if (strval [1] == '=') {
114                         reglen = 1;
115                 } else if (strval [2] == '=') {
116                         reglen = 2;
117                 } else {
118                         fprintf (stderr, "Specify REGISTER=VALUE with REGISTER 1 or 2 characters long, not \n", strval);
119                         exit (1);
120                 }
121                 uint8_t intval = argval (strval + reglen + 1);
122                 int j;
123                 bool found = false;
124                 for (j=0; j < 13; j++) {
125                         if (reglen != strlen (regname [j])) {
126                                 continue;
127                         }
128                         if (strncasecmp (regname [j], strval, reglen) != 0) {
129                                 continue;
130                         }
131                         if ((intval & regmask [j]) != regseln [j]) {
132                                 fprintf (stderr, "Error: Register %s value %s should fall between 0x%02x and 0x%02x\n", regname [j], strval + reglen + 1, regseln [j], regseln [j] + 255 - regmask [j]);
133                                 exit (1);
134                         }
135                         uint8_t buf [2];
136                         buf [0] = *regname [j] - '0';
137                         buf [1] = intval;
138                         printf ("%-2s := 0x%02x\n", regname [j], intval);
139                         usleep (INTERPOLL_WAIT_MS * 1000);
140                         if (write (bus, buf, sizeof (buf)) != sizeof (buf)) {
141                                 perror ("Failed to write to registers");
142                         }
143                         found = true;
144                 }
145                 if (!found) {
146                         fprintf (stderr, "Register for %s not found\n", strval);
147                         exit (1);
148                 }
149         }
150
151         close (bus);
152         return 0;
153 }