Sunday, July 14, 2013

Linux Driver MPR121

3 tasks to achieve:

1. Configure MPR121: initialize registers, configure buttons, leds, gpio, calculate parameters, etc
2. Create a thread and handler for IRQ
3. Create these sysFs for a dynamic configuration

Prepare data and allocate memory

static int __devinit mpr_touchkey_probe(struct i2c_client *client, const struct i2c_device_id *id){
const struct mpr121_platform_data *pdata=client->dev.platform_data;
The client represent the device mpr121, the platform_data is predefined at board file.

struct mpr121_touchkey *mpr121;
struct input_dev *input_dev;
input_dev represent a device who produces the signal of input to the module ARM.

mpr121 = kzalloc(sizeof(struct mpr121_touchkey), GFP_KERNEL);
input_dev = input_allocate_device();
input_allocate_device() allocate memory for a new device and return a structure of input_dev.

mpr121->client = client;
mpr121->input_dev = input_dev;
mpr121->keycount = pdata->keymap;

input_dev->name = "mpr121";//name of the device
input_dev->id.bustype = BUS_I2C;//id of the device (struct input_id)
input_dev->dev.parent = &client->dev;//driver model's view of this device
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
//bitmap of types of events supported by the device (EV_KEY, EV_REL, etc.)
/* EV_KEY:- Used to describe state changes of keyboards, buttons, or other key-like devices.*/
/* EV_REP:- Used for autorepeating devices.*/   
input_dev->keycode = mpr121->keycodes; //map of scancodes to keycodes for this device
input_dev->keycodesize = sizeof(mpr121->keycodes[0]);
input_dev->keycodemax = mpr121->keycount;//size of keycode table
input_dev->name is an important parameter which must be also the name of the keylayout file(mpr121.kl) and input device configure file(mpr121.idc).

for (i = 0; i < pdata->keymap_size; i++) {
                 input_set_capability(input_dev, EV_KEY, pdata->keymap[i]);
                 mpr121->keycodes[i] = pdata->keymap[i];
}
//input_set_events_per_packet - mark device as capable of a certain event
//dev: device that is capable of emitting or accepting event
//type:type of the event (EV_KEY, EV_REL, etc...)
//code:event code
//In addition to setting up corresponding bit in appropriate capability bitmap 
// the function also adjusts dev->evbit.

Task 1: Configure MPR121

It's better to put all the configuration in an independent function  mpr121_phys_init(pdata, mpr121, client)

initialize touch/release threshold

for (i = 0; i < keynum_config; i++) {
        addr = ELE0_TOUCH_THRESHOLD_ADDR + ((key_matrix[i] + i) * 2);
        ret = i2c_smbus_write_byte_data(client, addr, TOUCH_THRESHOLD);
        ret = i2c_smbus_write_byte_data(client, addr+1, RELEASE_THRESHOLD);
    }

configure GPIO

 i2c_smbus_write_byte_data(client, GPIO_ENABLE_ADDR, gpio_config_value);
 i2c_smbus_write_byte_data(client, GPIO_DIRECTION_ADDR, gpio_config_value);
 i2c_smbus_write_byte_data(client, GPIO_CONTROL_0_ADDR, gpio_config_value);
 i2c_smbus_write_byte_data(client, GPIO_CONTROL_1_ADDR, gpio_config_value);

tache 2: Installer IRQ et handler

request_threaded_irq(client->irq, NULL,
    mpr_touchkey_interrupt,  //handler
    IRQF_TRIGGER_FALLING,
    client->dev.driver->name, mpr121);

Registrer device avec input core

input_register_device(input_dev);

Mettre à jour MPR121(client)

i2c_set_clientdata(client, mpr121);

Configurer capacité de "wake-up"

device_init_wakeup(&client->dev, pdata->wakeup);

tache 3: Creer sysFs

ret = sysfs_create_group(&client->dev.kobj, &mpr121_attr_group);
Until now, a generic driver for mpr121 is done. With the sysfs, the parameters like threshold and touch mask could be configured dynamically in the console without recompiling the driver. And if the correspondence of the led and the buttons changes, a simple modification in the board file is enough.

No comments:

Post a Comment