-
Notifications
You must be signed in to change notification settings - Fork 2
/
gpio_pcal6416a.c
executable file
·153 lines (128 loc) · 4.64 KB
/
gpio_pcal6416a.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
Copyright (C) 2020-2021 Vincent Buso <[email protected]>
Copyright (C) 2021 Michel Stempin <[email protected]>
This file is part of the FunKey S GPIO keyboard daemon.
This is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
*/
/**
* @file gpio_pcal6416a.c
* This is userland GPIO driver for the PCAL6416AHB I2C GPIO expander chip
*/
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <syslog.h>
#include <unistd.h>
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include "gpio_pcal6416a.h"
#include "smbus.h"
//#define DEBUG_PCAL6416A
#define ERROR_PCAL6416A
#ifdef DEBUG_PCAL6416A
#define FK_DEBUG(...) syslog(LOG_DEBUG, __VA_ARGS__);
#else
#define FK_DEBUG(...)
#endif
#ifdef ERROR_PCAL6416A
#define FK_ERROR(...) syslog(LOG_ERR, __VA_ARGS__);
#else
#define FK_ERROR(...)
#endif
/* Structure to map I2C address and I2C GPIO expander name */
typedef struct {
unsigned int address;
char *name;
} i2c_expander_t;
/* PCAL6416A/PCAL9539A I2C GPIO expander chip pseudo-file descriptor */
static int fd_i2c_expander;
/* The I2C bus pseudo-file name */
static char i2c0_sysfs_filename[] = "/dev/i2c-0";
/* PCAL6416A/PCAL9539A I2C GPIO expander chip I2C address */
static unsigned int i2c_expander_addr;
/* Map of I2C addresses / GPIO expander name */
static i2c_expander_t i2c_chip[] = {
{PCAL9539A_I2C_ADDR, "PCAL9539A"},
{PCAL6416A_I2C_ADDR, "PCAL6416A"},
{0, NULL}
};
/* Initialize the PCAL6416A/PCAL9539A I2C GPIO expander chip */
bool pcal6416a_init(void)
{
int i;
/* Open the I2C bus pseudo-file */
if ((fd_i2c_expander = open(i2c0_sysfs_filename,O_RDWR)) < 0) {
FK_ERROR("Failed to open the I2C bus %s", i2c0_sysfs_filename);
return false;
}
/* Probing known I2C GPIO expander chips */
for (i = 0, i2c_expander_addr = 0; i2c_chip[i].address; i++) {
if (ioctl(fd_i2c_expander, I2C_SLAVE_FORCE, i2c_chip[i]) < 0 ||
pcal6416a_read_mask_interrupts() < 0) {
FK_DEBUG("Failed to acquire bus access and/or talk to slave %s at address 0x%02X.\n",
i2c_chip[i].name, i2c_chip[i].address);
} else {
FK_DEBUG("Found I2C gpio expander chip %s at address 0x%02X\n",
i2c_chip[i].name, i2c_chip[i].address);
i2c_expander_addr = i2c_chip[i].address;
break;
}
}
/* GPIO expander chip found? */
if (!i2c_expander_addr) {
FK_ERROR("Failed to acquire bus access and/or talk to slave, exit\n");
return false;
}
i2c_smbus_write_word_data ( fd_i2c_expander, PCAL6416A_CONFIG, 0xffff);
i2c_smbus_write_word_data ( fd_i2c_expander, PCAL6416A_INPUT_LATCH, 0x0000);
i2c_smbus_write_word_data ( fd_i2c_expander, PCAL6416A_EN_PULLUPDOWN, 0xffff);
i2c_smbus_write_word_data ( fd_i2c_expander, PCAL6416A_SEL_PULLUPDOWN, 0xffff);
i2c_smbus_write_word_data ( fd_i2c_expander, PCAL6416A_INT_MASK, 0x0320);
return true;
}
/* Deinitialize the PCAL6416A/PCAL9539A I2C GPIO expander chip */
bool pcal6416a_deinit(void)
{
/* Close the I2C bus pseudo-file */
close(fd_i2c_expander);
return true;
}
/* Read the PCAL6416A/PCAL9539A I2C GPIO expander chip interrupt register */
int pcal6416a_read_mask_interrupts(void)
{
int val_int;
uint16_t val;
val_int = i2c_smbus_read_word_data(fd_i2c_expander, PCAL6416A_INT_STATUS);
if (val_int < 0) {
return val_int;
}
val = val_int & 0xFFFF;
FK_DEBUG("READ PCAL6416A_INT_STATUS : 0x%04X\n", val);
return (int) val;
}
/* Read the PCAL6416A/PCAL9539A I2C GPIO expander chip active GPIO register */
int pcal6416a_read_mask_active_GPIOs(void)
{
int val_int;
uint16_t val;
val_int = i2c_smbus_read_word_data(fd_i2c_expander, PCAL6416A_INPUT);
if (val_int < 0){
return val_int;
}
val = val_int & 0xFFFF;
val = 0xFFFF - val;
FK_DEBUG("READ PCAL6416A_INPUT (active GPIOs) : 0x%04X\n", val);
return (int) val;
}