[PATCH 2/2] input: samsung-keypad: Add device tree support

Thomas Abraham thomas.abraham at linaro.org
Thu Sep 8 00:31:46 EDT 2011


Hi Dmitry,

On 8 September 2011 02:20, Dmitry Torokhov <dmitry.torokhov at gmail.com> wrote:
> Hi Thomas,
>
> On Tue, Sep 06, 2011 at 07:25:17PM +0530, Thomas Abraham wrote:
>>  static int samsung_keypad_is_s5pv210(struct device *dev)
>>  {
>>       struct platform_device *pdev = to_platform_device(dev);
>> -     enum samsung_keypad_type type =
>> -             platform_get_device_id(pdev)->driver_data;
>> +     enum samsung_keypad_type type;
>>
>> +#ifdef CONFIG_OF
>> +     if (dev->of_node)
>> +             return of_device_is_compatible(dev->of_node,
>> +                             "samsung,s5pv210-keypad");
>> +#endif
>> +     type = platform_get_device_id(pdev)->driver_data;
>>       return type == KEYPAD_TYPE_S5PV210;
>
> This function is called every time we scan keypad matrix, I do not think
> you want to scan DT bindings here. You need to cache the device type at
> probe time and use it.

Ok. As you suggested, this will be changed to cache the type in driver
private data during probe and use the cached copy when required.

>
>>  }
>>
>> @@ -235,6 +246,130 @@ static void samsung_keypad_close(struct input_dev *input_dev)
>>       samsung_keypad_stop(keypad);
>>  }
>>
>> +#ifdef CONFIG_OF
>> +static
>> +struct samsung_keypad_platdata *samsung_keypad_parse_dt(struct device *dev)
>> +{
>> +     struct samsung_keypad_platdata *pdata;
>> +     struct matrix_keymap_data *keymap_data;
>> +     uint32_t *keymap;
>> +     struct device_node *np = dev->of_node, *key_np;
>> +     unsigned int key_count = 0;
>> +
>> +     pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
>> +     if (!pdata) {
>> +             dev_err(dev, "could not allocate memory for platform data\n");
>> +             return NULL;
>> +     }
>
> pdata is not used once probe() completes so it would be better to free
> it and not rely on devm_* facilities to free it for you once device
> unbinds from the driver.

Ok. That would be better. pdata will be freed after probe completes.

>
>> +
>> +     of_property_read_u32(np, "samsung,keypad-num-rows", &pdata->rows);
>> +     of_property_read_u32(np, "samsung,keypad-num-columns", &pdata->cols);
>> +     if (!pdata->rows || !pdata->cols) {
>> +             dev_err(dev, "number of keypad rows/columns not specified\n");
>> +             return NULL;
>> +     }
>> +
>> +     keymap_data = devm_kzalloc(dev, sizeof(*keymap_data), GFP_KERNEL);
>> +     if (!keymap_data) {
>> +             dev_err(dev, "could not allocate memory for keymap data\n");
>> +             return NULL;
>> +     }
>> +     pdata->keymap_data = keymap_data;
>> +
>> +     for_each_child_of_node(np, key_np)
>> +             key_count++;
>> +
>> +     keymap_data->keymap_size = key_count;
>> +     keymap = devm_kzalloc(dev, sizeof(uint32_t) * key_count, GFP_KERNEL);
>> +     if (!keymap) {
>> +             dev_err(dev, "could not allocate memory for keymap\n");
>> +             return NULL;
>> +     }
>> +     keymap_data->keymap = keymap;
>> +
>> +     for_each_child_of_node(np, key_np) {
>> +             unsigned int row, col, key_code;
>> +             of_property_read_u32(key_np, "keypad,row", &row);
>> +             of_property_read_u32(key_np, "keypad,column", &col);
>> +             of_property_read_u32(key_np, "keypad,key-code", &key_code);
>> +             *keymap++ = KEY(row, col, key_code);
>> +     }
>
> THis seems like generic mechanism that could be used by other drivers...
> Maybe move into matrix-keypad.c? You would also not need to allocate
> temporary buffer for intermediate keymap data.

Yes, this could be reused in other drivers as well. But, moving this
into matrix-keypad.c file means that KEYBOARD_MATRIX config option
would have to be selected for all platforms reusing this code. So, I
am not sure of the right place for this.

>
>> +
>> +     if (of_get_property(np, "linux,input-no-autorepeat", NULL))
>> +             pdata->no_autorepeat = true;
>> +     if (of_get_property(np, "linux,input-wakeup", NULL))
>> +             pdata->wakeup = true;
>> +
>> +     return pdata;
>> +}
>> +
>> +static void samsung_keypad_parse_dt_gpio(struct device *dev,
>> +                             struct samsung_keypad *keypad)
>> +{
>> +     struct device_node *np = dev->of_node;
>> +     int gpio, ret, row, col;
>> +
>> +     for (row = 0; row < keypad->rows; row++) {
>> +             gpio = of_get_named_gpio(np, "row-gpios", row);
>> +             keypad->row_gpios[row] = gpio;
>> +             if (!gpio_is_valid(gpio)) {
>> +                     dev_err(dev, "keypad row[%d]: invalid gpio %d\n",
>> +                                     row, gpio);
>> +                     continue;
>> +             }
>> +
>> +             ret = gpio_request(gpio, "keypad-row");
>> +             if (ret)
>> +                     dev_err(dev, "keypad row[%d] gpio request failed\n",
>> +                                     row);
>> +     }
>> +
>> +     for (col = 0; col < keypad->cols; col++) {
>> +             gpio = of_get_named_gpio(np, "col-gpios", col);
>> +             keypad->col_gpios[col] = gpio;
>> +             if (!gpio_is_valid(gpio)) {
>> +                     dev_err(dev, "keypad column[%d]: invalid gpio %d\n",
>> +                                     col, gpio);
>> +                     continue;
>> +             }
>> +
>> +             ret = gpio_request(col, "keypad-col");
>> +             if (ret)
>> +                     dev_err(dev, "keypad column[%d] gpio request failed\n",
>> +                                     col);
>
> I think we should bail out if one of the calls fails.

I intended to continue even if some request fails because there could
a partially usable keyboard. If there is a failure, there is a error
message to indicate that keyboard might not be fully functional. If
you are not too strict on this one, I would like to retain it this
way.

>
>> +     }
>> +}
>> +
>> +static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad)
>> +{
>> +     int cnt;
>> +
>> +     for (cnt = 0; cnt < keypad->rows; cnt++)
>> +             if (gpio_is_valid(keypad->row_gpios[cnt]))
>> +                     gpio_free(keypad->row_gpios[cnt]);
>> +
>> +     for (cnt = 0; cnt < keypad->cols; cnt++)
>> +             if (gpio_is_valid(keypad->col_gpios[cnt]))
>> +                     gpio_free(keypad->col_gpios[cnt]);
>> +}
>> +#else
>> +static
>> +struct samsung_keypad_platdata *samsung_keypad_parse_dt(struct device *dev)
>> +{
>> +     return NULL;
>> +}
>> +
>> +static void samsung_keypad_parse_dt_gpio(struct device_node *np,
>> +             struct samsung_keypad *keypad, unsigned int rows,
>> +             unsigned int cols)
>> +{
>> +}
>> +
>> +static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad)
>> +{
>> +}
>> +#endif
>> +
>>  static int __devinit samsung_keypad_probe(struct platform_device *pdev)
>>  {
>>       const struct samsung_keypad_platdata *pdata;
>> @@ -246,7 +381,10 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
>>       unsigned int keymap_size;
>>       int error;
>>
>> -     pdata = pdev->dev.platform_data;
>> +     if (pdev->dev.of_node)
>> +             pdata = samsung_keypad_parse_dt(&pdev->dev);
>> +     else
>> +             pdata = pdev->dev.platform_data;
>>       if (!pdata) {
>>               dev_err(&pdev->dev, "no platform data defined\n");
>>               return -EINVAL;
>> @@ -303,6 +441,9 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
>>       keypad->cols = pdata->cols;
>>       init_waitqueue_head(&keypad->wait);
>>
>> +     if (pdev->dev.of_node)
>> +             samsung_keypad_parse_dt_gpio(&pdev->dev, keypad);
>> +
>>       input_dev->name = pdev->name;
>>       input_dev->id.bustype = BUS_HOST;
>>       input_dev->dev.parent = &pdev->dev;
>> @@ -349,6 +490,7 @@ err_free_irq:
>>       free_irq(keypad->irq, keypad);
>>  err_put_clk:
>>       clk_put(keypad->clk);
>> +     samsung_keypad_dt_gpio_free(keypad);
>>  err_unmap_base:
>>       iounmap(keypad->base);
>>  err_free_mem:
>> @@ -374,6 +516,7 @@ static int __devexit samsung_keypad_remove(struct platform_device *pdev)
>>       free_irq(keypad->irq, keypad);
>>
>>       clk_put(keypad->clk);
>> +     samsung_keypad_dt_gpio_free(keypad);
>>
>>       iounmap(keypad->base);
>>       kfree(keypad);
>> @@ -447,6 +590,17 @@ static const struct dev_pm_ops samsung_keypad_pm_ops = {
>>  };
>>  #endif
>>
>> +#ifdef CONFIG_OF
>> +static const struct of_device_id samsung_keypad_dt_match[] = {
>> +     { .compatible = "samsung,s3c6410-keypad" },
>> +     { .compatible = "samsung,s5pv210-keypad" },
>> +     {},
>> +};
>> +MODULE_DEVICE_TABLE(of, samsung_keypad_dt_match);
>> +#else
>> +#define samsung_keypad_dt_match NULL
>> +#endif
>> +
>>  static struct platform_device_id samsung_keypad_driver_ids[] = {
>>       {
>>               .name           = "samsung-keypad",
>> @@ -465,6 +619,7 @@ static struct platform_driver samsung_keypad_driver = {
>>       .driver         = {
>>               .name   = "samsung-keypad",
>>               .owner  = THIS_MODULE,
>> +             .of_match_table = samsung_keypad_dt_match,
>>  #ifdef CONFIG_PM
>>               .pm     = &samsung_keypad_pm_ops,
>>  #endif
>> --
>> 1.6.6.rc2
>>
>
> Thanks.
>
> --
> Dmitry
>

Thanks for your review and comments.

Regards,
Thomas.



More information about the linux-arm-kernel mailing list