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.