PCF8574A is 8-bit expander with I2C bus.
Driver will check presence of dev in device-tree, and will count from 0x00 to 0xff.
Device tree modifications(vs orginal TI device-trr for beaglebone)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| i2c1_pins: pinmux_i2c1_pins {
pinctrl-single,pins = <
AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | MUX_MODE2) /*spi0_d1.i2c1_sda*/
AM33XX_IOPAD(0x95c, PIN_INPUT_PULLUP | MUX_MODE2) /*spi0_cs0.i2c1_scl*/
>;
};
}
&i2c1 {
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins>;
clock-frequency = <100000>;
status = "ok";
i2c_pcf: i2c_pcf@3f {
compatible = "fei2c,pcfmodule";
reg = <0x3f>;
};
}; |
i2c1_pins: pinmux_i2c1_pins {
pinctrl-single,pins = <
AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | MUX_MODE2) /*spi0_d1.i2c1_sda*/
AM33XX_IOPAD(0x95c, PIN_INPUT_PULLUP | MUX_MODE2) /*spi0_cs0.i2c1_scl*/
>;
};
}
&i2c1 {
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins>;
clock-frequency = <100000>;
status = "ok";
i2c_pcf: i2c_pcf@3f {
compatible = "fei2c,pcfmodule";
reg = <0x3f>;
};
};
In driver we must create probe and remove functions, and “of” table to match driver with device-tree.
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
| static void pcf_timCallback( unsigned long args )
{
pr_info("PCF: timer callback\n");
}
int pcf_threadFunc( void *data )
{
struct pcf_data *dev = data;
while(1) {
if(kthread_should_stop())
return 0;
if( 1 != i2c_master_send(dev->client,&dev->out_state,1) )
{
pr_info("Error writing to pcf device\n");
}
dev->out_state += 1;
msleep(5);
}
}
int pcf_probe(struct i2c_client *client, const struct i2c_device_id *dev)
{
int ret;
char buf = 0x02;
pr_info("i2c:pcf -> probe. Addr: %x\n",client->addr);
ret = i2c_master_send(client,&buf,1);
if( ret < 0 )
{
pr_info("Error during communication with dev\n");
return -ENOSYS;
}
dev_data = devm_kzalloc(&client->dev,sizeof(struct pcf_data),GFP_KERNEL);
if( !dev_data )
{
pr_info("Memory alloc fail\n");
return -ENOMEM;
}
dev_data->client = client;
dev_data->out_state = 0x03;
setup_timer(&dev_data->tick_timer,pcf_timCallback,0);
mod_timer(&dev_data->tick_timer,jiffies+msecs_to_jiffies(10000));
dev_data->blinkThread = kthread_run(pcf_threadFunc,dev_data,"pcf_thread");
return 0;
}
int pcf_remove(struct i2c_client *client)
{
pr_info("i2c:pcf -> remove\n");
kthread_stop(dev_data->blinkThread);
return 0;
}
static const struct i2c_device_id pcf_id[] = {
{"pcf8574",0},
{}
};
MODULE_DEVICE_TABLE(i2c,pcf_id);
static const struct of_device_id pcf_dt_ids[] = {
{ .compatible = "fei2c,pcfmodule",},
{}
};
MODULE_DEVICE_TABLE(of,pcf_dt_ids);
static struct i2c_driver pcf_driver = {
.probe = pcf_probe,
.remove = pcf_remove,
.id_table = pcf_id,
.driver = {
.name = "pcf8574_driver",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(pcf_dt_ids),
},
};
module_i2c_driver(pcf_driver); |
static void pcf_timCallback( unsigned long args )
{
pr_info("PCF: timer callback\n");
}
int pcf_threadFunc( void *data )
{
struct pcf_data *dev = data;
while(1) {
if(kthread_should_stop())
return 0;
if( 1 != i2c_master_send(dev->client,&dev->out_state,1) )
{
pr_info("Error writing to pcf device\n");
}
dev->out_state += 1;
msleep(5);
}
}
int pcf_probe(struct i2c_client *client, const struct i2c_device_id *dev)
{
int ret;
char buf = 0x02;
pr_info("i2c:pcf -> probe. Addr: %x\n",client->addr);
ret = i2c_master_send(client,&buf,1);
if( ret < 0 )
{
pr_info("Error during communication with dev\n");
return -ENOSYS;
}
dev_data = devm_kzalloc(&client->dev,sizeof(struct pcf_data),GFP_KERNEL);
if( !dev_data )
{
pr_info("Memory alloc fail\n");
return -ENOMEM;
}
dev_data->client = client;
dev_data->out_state = 0x03;
setup_timer(&dev_data->tick_timer,pcf_timCallback,0);
mod_timer(&dev_data->tick_timer,jiffies+msecs_to_jiffies(10000));
dev_data->blinkThread = kthread_run(pcf_threadFunc,dev_data,"pcf_thread");
return 0;
}
int pcf_remove(struct i2c_client *client)
{
pr_info("i2c:pcf -> remove\n");
kthread_stop(dev_data->blinkThread);
return 0;
}
static const struct i2c_device_id pcf_id[] = {
{"pcf8574",0},
{}
};
MODULE_DEVICE_TABLE(i2c,pcf_id);
static const struct of_device_id pcf_dt_ids[] = {
{ .compatible = "fei2c,pcfmodule",},
{}
};
MODULE_DEVICE_TABLE(of,pcf_dt_ids);
static struct i2c_driver pcf_driver = {
.probe = pcf_probe,
.remove = pcf_remove,
.id_table = pcf_id,
.driver = {
.name = "pcf8574_driver",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(pcf_dt_ids),
},
};
module_i2c_driver(pcf_driver);
After insmod module, if compatible device will be found – probe function will create blinking thread.