-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathi2c-sgp30.c
191 lines (163 loc) · 4.59 KB
/
i2c-sgp30.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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/***************************************************************************//**
* \file i2c-sgp30.c
*
* \details sgp30 i2c driver
*
* \author g8row
*
* *******************************************************************************/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#define I2C_BUS_AVAILABLE ( 1 ) // I2C Bus available in our Raspberry Pi
#define SLAVE_DEVICE_NAME ( "SGP30" ) // Device and Driver Name
#define SGP30_SLAVE_ADDR ( 0x58 ) // sgp30 Slave Address
static struct i2c_adapter *sgp30_i2c_adapter = NULL; // I2C Adapter Structure
static struct i2c_client *sgp30_i2c_client = NULL; // I2C Client Structure
/*
** This function writes the data into the I2C client
**
** Arguments:
** buff -> buffer to be sent
** len -> Length of the data
**
*/
static int I2C_Write(unsigned char *buf, unsigned int len)
{
/*
** Sending Start condition, Slave address with R/W bit,
** ACK/NACK and Stop condtions will be handled internally.
*/
int ret = i2c_master_send(sgp30_i2c_client, buf, len);
return ret;
}
/*
** This function reads one byte of the data from the I2C client
**
** Arguments:
** out_buff -> buffer wherer the data to be copied
** len -> Length of the data to be read
**
*/
static int I2C_Read(unsigned char *out_buf, unsigned int len)
{
/*
** Sending Start condition, Slave address with R/W bit,
** ACK/NACK and Stop condtions will be handled internally.
*/
int ret = i2c_master_recv(sgp30_i2c_client, out_buf, len);
return ret;
}
static int SGP30_Write(unsigned char command, unsigned char data)
{
unsigned char buf[2] = {0};
int ret;
buf[0] = command;
buf[1] = data;
return I2C_Write(buf, 2);
}
static int SGP30_Init(void)
{
pr_info("entered init");
msleep(100); // delay
SGP30_Write(0x20,0x03);
pr_info("exit init");
return 0;
}
struct sgp30_measurement {
int co2;
int tvoc;
};
static struct sgp30_measurement SGP30_Measure(void)
{
unsigned char buf[6];
struct sgp30_measurement s;
pr_info("wrote %i bytes to sgp30",SGP30_Write(0x20,0x08));
mdelay(10);
pr_info("read %d bytes from sgp30",I2C_Read(buf, 6));
s.co2 = (buf[0]<<8)|buf[1];
s.tvoc = (buf[3]<<8)|buf[4];
return s;
}
/*
** proc_fs
*/
static ssize_t sgp30_read(struct file *File, char *user_buffer, size_t count, loff_t *offs) {
struct sgp30_measurement s = SGP30_Measure();
return sprintf(user_buffer, "%d CO2, %d TVOC\n", s.co2, s.tvoc);
}
static struct proc_dir_entry *proc_file;
static struct proc_ops fops = {
.proc_read = sgp30_read,
};
/*
** This function getting called when the slave has been found
** Note : This will be called only once when we load the driver.
*/
static int sgp30_probe(struct i2c_client *client)
{
pr_info("sgp30 init started\n");
if(client->addr != SGP30_SLAVE_ADDR) {
printk("dt_i2c - Wrong I2C address!\n");
return -1;
}
sgp30_i2c_client = client;
proc_file = proc_create("sgp30", 0666, NULL, &fops);
if(proc_file == NULL) {
printk("dt_i2c - Error creating /proc/myadc\n");
return -ENOMEM;
}
SGP30_Init();
pr_info("sgp30 initialized and probed!!!\n");
return 0;
}
/*
** This function getting called when the slave has been removed
** Note : This will be called only once when we unload the driver.
*/
static void sgp30_remove(struct i2c_client *client)
{
proc_remove(proc_file);
pr_info("sgp30 removed\n");
}
/*
** Structure that has slave device id
*/
static const struct i2c_device_id sgp30_id[] = {
{ SLAVE_DEVICE_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, sgp30_id);
static struct of_device_id sgp30_driver_ids[] = {
{
.compatible = "sgp30",
}, { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sgp30_driver_ids);
/*
** I2C driver Structure that has to be added to linux
*/
static struct i2c_driver sgp30_driver = {
.driver = {
.name = SLAVE_DEVICE_NAME,
.of_match_table = sgp30_driver_ids,
},
.probe = sgp30_probe,
.remove = sgp30_remove,
.id_table = sgp30_id,
};
/*
** I2C Board Info strucutre
*/
static struct i2c_board_info sgp30_board_info = {
I2C_BOARD_INFO(SLAVE_DEVICE_NAME, SGP30_SLAVE_ADDR)
};
module_i2c_driver(sgp30_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("g8row <[email protected]>");
MODULE_DESCRIPTION("sgp30 i2c kernel driver");
MODULE_VERSION("0.0.1");