-
Notifications
You must be signed in to change notification settings - Fork 4
/
mi2c-i2c.c
162 lines (123 loc) · 3.19 KB
/
mi2c-i2c.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
/*
* An example of how to implement an i2c Linux driver as a loadable module with
* dynamic device registration.
*
* This driver was meant to be included as a module in a bigger driver which
* is most likely why you would want to use a kernel i2c solution.
*
*/
#include <linux/init.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include "mi2c.h" /* for DRIVER_NAME */
#define BLINKM_DEVICE "blinkm"
#define ARDUINO_DEVICE "arduino"
#define BLINKM_1_ADDRESS 0x01
#define BLINKM_2_ADDRESS 0x03
#define ARDUINO_ADDRESS 0x10
#define NUM_DEVICES 3
static struct i2c_client *mi2c_i2c_client[NUM_DEVICES];
static struct i2c_board_info mi2c_board_info[NUM_DEVICES] = {
{
I2C_BOARD_INFO(BLINKM_DEVICE, BLINKM_1_ADDRESS),
},
{
I2C_BOARD_INFO(BLINKM_DEVICE, BLINKM_2_ADDRESS),
},
{
I2C_BOARD_INFO(ARDUINO_DEVICE, ARDUINO_ADDRESS),
}
};
int mi2c_i2c_get_address(unsigned int device_id)
{
if (device_id >= NUM_DEVICES)
return -EINVAL;
if (!mi2c_i2c_client[device_id])
return -ENODEV;
return mi2c_i2c_client[device_id]->addr;
}
int mi2c_i2c_write(unsigned int device_id, unsigned char *buf, int count)
{
if (device_id >= NUM_DEVICES)
return -EINVAL;
if (!mi2c_i2c_client[device_id])
return -ENODEV;
return i2c_master_send(mi2c_i2c_client[device_id], buf, count);
}
int mi2c_i2c_read(unsigned int device_id, unsigned char *buf, int count)
{
if (device_id >= NUM_DEVICES)
return -EINVAL;
if (!mi2c_i2c_client[device_id])
return -ENODEV;
return i2c_master_recv(mi2c_i2c_client[device_id], buf, count);
}
static int mi2c_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
printk(KERN_INFO "%s driver registered for device at address 0x%02x\n",
client->name, client->addr);
return 0;
}
static int mi2c_i2c_remove(struct i2c_client *client)
{
printk(KERN_INFO "removing %s driver for device at address 0x%02x\n",
client->name, client->addr);
return 0;
}
/* our driver handles two types of device */
static const struct i2c_device_id mi2c_id[] = {
{ BLINKM_DEVICE, 0 },
{ ARDUINO_DEVICE, 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, mi2c_id);
static struct i2c_driver mi2c_i2c_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
},
.id_table = mi2c_id,
.probe = mi2c_i2c_probe,
.remove = mi2c_i2c_remove,
};
#define I2C_BUS 3
int __init mi2c_init_i2c(void)
{
int i, ret;
struct i2c_adapter *adapter;
/* register our driver */
ret = i2c_add_driver(&mi2c_i2c_driver);
if (ret) {
printk(KERN_ALERT "Error registering i2c driver\n");
return ret;
}
/* add our devices */
adapter = i2c_get_adapter(I2C_BUS);
if (!adapter) {
printk(KERN_ALERT "i2c_get_adapter(%d) failed\n", I2C_BUS);
return -1;
}
for (i = 0; i < NUM_DEVICES; i++) {
mi2c_i2c_client[i] = i2c_new_device(adapter,
&mi2c_board_info[i]);
if (!mi2c_i2c_client[i]) {
printk(KERN_ALERT "i2c_new_device failed\n");
break;
}
}
i2c_put_adapter(adapter);
return i == NUM_DEVICES ? 0 : -1;
}
void __exit mi2c_cleanup_i2c(void)
{
int i;
for (i = 0; i < NUM_DEVICES; i++) {
if (mi2c_i2c_client[i]) {
i2c_unregister_device(mi2c_i2c_client[i]);
mi2c_i2c_client[i] = NULL;
}
}
i2c_del_driver(&mi2c_i2c_driver);
}