«

»

Jan 06

Beaglebone PCF8574A simple driver

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>;
  };
};

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);

After insmod module, if compatible device will be found – probe function will create blinking thread.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>