RE: [PATCH v3] input: tegra-kbc - Add tegra keyboard driver

From: Rakesh Iyer
Date: Mon Jan 10 2011 - 16:14:51 EST


Thanks for the review.

A quick response regarding the following comment.

>
> > +
> > +#include <linux/module.h>
> > +#include <linux/input.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/delay.h>
> > +#include <linux/io.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/clk.h>
> > +#include <linux/slab.h>
> > +#include <mach/clk.h>
>
> You may not need this.
>

The mach/clk.h file contains declarations for tegra_periph_reset_assert and tegra_periph_reset_deassert which are needed.

Regards
Rakesh

> -----Original Message-----
> From: Trilok Soni [mailto:tsoni@xxxxxxxxxxxxxx]
> Sent: Monday, January 10, 2011 12:54 PM
> To: Rakesh Iyer
> Cc: jj@xxxxxxxxxxxxx; shubhrajyoti@xxxxxx; ccross@xxxxxxxxxxx; konkers@xxxxxxxxxxx;
> olof@xxxxxxxxx; Andrew Chew; linux-tegra@xxxxxxxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx;
> linux-input@xxxxxxxxxxxxxxx
> Subject: Re: [PATCH v3] input: tegra-kbc - Add tegra keyboard driver
>
> Hi Rakesh,
>
> On 1/7/2011 11:15 PM, riyer@xxxxxxxxxx wrote:
> > From: Rakesh Iyer <riyer@xxxxxxxxxx>
> >
> > This patch adds support for the internal matrix keyboard controller for
> > Nvidia Tegra platforms.
> >
> > Signed-off-by: Rakesh Iyer <riyer@xxxxxxxxxx>
> > ---
> > Removed NULL check before input_free_device as suggested by Jesper Juhl.
>
> Sorry for the delay. Few comments.
>
> > +
> > +#include <linux/module.h>
> > +#include <linux/input.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/delay.h>
> > +#include <linux/io.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/clk.h>
> > +#include <linux/slab.h>
> > +#include <mach/clk.h>
>
> You may not need this.
>
> >
> > +
> > +static void tegra_kbc_keypress_timer(unsigned long data)
> > +{
> > + struct tegra_kbc *kbc = (struct tegra_kbc *)data;
> > + unsigned long flags;
> > + u32 val;
> > + int i;
> > +
>
> ...
>
> > + }
> > + return;
>
> No need.
>
> > +}
> > +
> > +
> > +
> > +
> > +static int tegra_kbc_open(struct input_dev *dev)
> > +{
> > + struct tegra_kbc *kbc = input_get_drvdata(dev);
> > + unsigned long flags;
> > + unsigned int debounce_cnt;
> > + u32 val = 0;
> > +
> > + clk_enable(kbc->clk);
> > +
> > + /* Reset the KBC controller to clear all previous status.*/
> > + tegra_periph_reset_assert(kbc->clk);
> > + udelay(100);
> > + tegra_periph_reset_deassert(kbc->clk);
> > + udelay(100);
> > +
> > + tegra_kbc_config_pins(kbc);
> > + tegra_kbc_setup_wakekeys(kbc, false);
> > +
> > + writel(kbc->pdata->repeat_cnt, kbc->mmio + KBC_RPT_DLY_0);
> > +
> > + debounce_cnt = min_t(unsigned int, kbc->pdata->debounce_cnt, 0x3fful);
> > + val = debounce_cnt << 4;
> > + val |= 1<<14; /* fifo interrupt threshold = 1 entry */
> > + val |= 1<<3; /* interrupt on FIFO threshold reached */
>
> As mentioned below, try to get driver out of these magic nos.
>
> > + val |= 1; /* enable */
> > + writel(val, kbc->mmio + KBC_CONTROL_0);
> > +
> > + /* Compute the delay(ns) from interrupt mode to continuous polling mode
> > + * so the timer routine is scheduled appropriately. */
> > + val = readl(kbc->mmio + KBC_INIT_DLY_0);
> > + kbc->cp_dly_jiffies = usecs_to_jiffies((val & 0xfffff) * 32);
> > +
> > + /* atomically clear out any remaining entries in the key FIFO
> > + * and enable keyboard interrupts */
> > + spin_lock_irqsave(&kbc->lock, flags);
> > + while (1) {
> > + val = readl(kbc->mmio + KBC_INT_0);
> > + val >>= 4;
> > + if (val) {
> > + val = readl(kbc->mmio + KBC_KP_ENT0_0);
> > + val = readl(kbc->mmio + KBC_KP_ENT1_0);
> > + } else {
> > + break;
> > + }
> > + }
> > + writel(0x7, kbc->mmio + KBC_INT_0);
> > + spin_unlock_irqrestore(&kbc->lock, flags);
> > +
> > + return 0;
> > +}
> > +
> > +
>
> > +
> > +static irqreturn_t tegra_kbc_isr(int irq, void *args)
> > +{
> > + struct tegra_kbc *kbc = args;
> > + u32 val, ctl;
> > +
> > + /* until all keys are released, defer further processing to
> > + * the polling loop in tegra_kbc_keypress_timer */
> > + ctl = readl(kbc->mmio + KBC_CONTROL_0);
> > + ctl &= ~(1<<3);
>
> No magic nos. please. Add relevant #defines for it.
>
> > + writel(ctl, kbc->mmio + KBC_CONTROL_0);
> > +
> > + /* quickly bail out & reenable interrupts if the interrupt source
> > + * wasn't fifo count threshold */
>
> "wasn't equal to fifo count threshold" ?
>
> > + val = readl(kbc->mmio + KBC_INT_0);
> > + writel(val, kbc->mmio + KBC_INT_0);
> > +
> > + if (!(val & (1<<2))) {
> > + ctl |= 1<<3;
>
> As mentioned above, no magic nos. please.
>
> > + writel(ctl, kbc->mmio + KBC_CONTROL_0);
> > + return IRQ_HANDLED;
> > + }
> > +
> > + /* Schedule timer to run when hardware is in continuous polling mode. */
> > + mod_timer(&kbc->timer, jiffies + kbc->cp_dly_jiffies);
> > + return IRQ_HANDLED;
> > +}
> > +
> > +static int __devinit tegra_kbc_probe(struct platform_device *pdev)
> > +{
> > + struct tegra_kbc *kbc;
> > + const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data;
> > + struct resource *res;
> > + int irq;
> > + int err;
> > + int rows[KBC_MAX_ROW];
> > + int cols[KBC_MAX_COL];
> > + int i, j;
> > + int nr = 0;
> > + unsigned int debounce_cnt;
> > +
> > + if (!pdata)
> > + return -EINVAL;
> > +
> > + kbc = kzalloc(sizeof(*kbc), GFP_KERNEL);
> > + if (!kbc)
> > + return -ENOMEM;
> > +
> > + kbc->pdata = pdata;
> > + kbc->irq = -EINVAL;
>
> You don't need such assignments for irq.
>
> > +
> > + memset(rows, 0, sizeof(rows));
> > + memset(cols, 0, sizeof(cols));
> > +
> > + kbc->idev = input_allocate_device();
> > + if (!kbc->idev) {
> > + err = -ENOMEM;
> > + goto fail;
> > + }
> > +
> > + debounce_cnt = min_t(unsigned int, pdata->debounce_cnt, 0x3fful);
> > + kbc->repoll_time = 5 + (16 + debounce_cnt) * nr + pdata->repeat_cnt;
> > + kbc->repoll_time = (kbc->repoll_time + 31) / 32;
>
> Care to add note on this equation? Lot's of magic nos. used in this, so they better
> get documented.
>
> > +
> > + kbc->idev->evbit[0] = BIT_MASK(EV_KEY);
> > +
> > + /* Override the default keycodes with the board supplied ones. */
> > + if (pdata->plain_keycode) {
> > + kbc->plain_keycode = pdata->plain_keycode;
> > + kbc->fn_keycode = pdata->fn_keycode;
> > + } else {
> > + kbc->plain_keycode = plain_kbd_keycode;
> > + kbc->fn_keycode = fn_kbd_keycode;
> > + }
> > +
> > + for (i = 0; i < KBC_MAX_COL; i++) {
> > + if (!cols[i])
> > + continue;
> > + for (j = 0; j < KBC_MAX_ROW; j++) {
> > + int keycode;
> > +
> > + if (!rows[j])
> > + continue;
> > +
> > + /* enable all the mapped keys. */
> > + keycode = tegra_kbc_keycode(kbc, j, i, false);
> > + if (keycode != -1)
> > + set_bit(keycode, kbc->idev->keybit);
> > +
> > + keycode = tegra_kbc_keycode(kbc, j, i, true);
> > + if (keycode != -1)
> > + set_bit(keycode, kbc->idev->keybit);
> > + }
> > + }
> > +
> > + setup_timer(&kbc->timer, tegra_kbc_keypress_timer, (unsigned long)kbc);
> > + /* Initialize the FIFO to invalid entries */
> > + for (i = 0; i < ARRAY_SIZE(kbc->fifo); i++)
> > + kbc->fifo[i] = -1;
> > +
> > + /* keycode FIFO needs to be read atomically; leave local
> > + * interrupts disabled when handling KBC interrupt */
> > + err = request_irq(irq, tegra_kbc_isr, IRQF_TRIGGER_HIGH,
> > + pdev->name, kbc);
> > + if (err) {
> > + dev_err(&pdev->dev, "failed to request keypad IRQ\n");
> > + goto fail;
> > + }
> > + kbc->irq = irq;
> > +
> > + err = input_register_device(kbc->idev);
> > + if (err) {
> > + dev_err(&pdev->dev, "failed to register input device\n");
> > + goto fail;
> > + }
> > +
> > + device_init_wakeup(&pdev->dev, pdata->wakeup);
> > + return 0;
> > +
> > +fail:
>
> It is better if you use multiple labels with differing names, as it will
> really improve your error patch and you don't need such if (...) checks against
> each of these resource release operations then. Please check other drivers..
>
> > + input_free_device(kbc->idev);
> > + if (kbc->irq >= 0)
> > + free_irq(kbc->irq, pdev);
> > + if (kbc->clk)
> > + clk_put(kbc->clk);
> > + if (kbc->mmio)
> > + iounmap(kbc->mmio);
>
>
>
> > + kfree(kbc);
> > + return err;
> > +}
> > +
> > +#ifdef CONFIG_PM
> > +static int tegra_kbc_suspend(struct platform_device *pdev, pm_message_t state)
> > +{
> > + struct tegra_kbc *kbc = platform_get_drvdata(pdev);
> > +
> > + if (device_may_wakeup(&pdev->dev)) {
> > + tegra_kbc_setup_wakekeys(kbc, true);
> > + enable_irq_wake(kbc->irq);
> > + /* Forcefully clear the interrupt status */
> > + writel(0x7, kbc->mmio + KBC_INT_0);
> > + msleep(30);
> > + } else {
> > + mutex_lock(&kbc->idev->mutex);
> > + tegra_kbc_close(kbc->idev);
>
> Only if there are any users. Please add that check.
>
> > + mutex_unlock(&kbc->idev->mutex);
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int tegra_kbc_resume(struct platform_device *pdev)
> > +{
> > + struct tegra_kbc *kbc = platform_get_drvdata(pdev);
> > + int err = 0;
> > +
> > + if (device_may_wakeup(&pdev->dev)) {
> > + disable_irq_wake(kbc->irq);
> > + tegra_kbc_setup_wakekeys(kbc, false);
> > + } else if (kbc->idev->users) {
> > + mutex_lock(&kbc->idev->mutex);
> > + err = tegra_kbc_open(kbc->idev);
>
> As mentioned above.
>
> > + mutex_unlock(&kbc->idev->mutex);
> > + }
> > +
> > + return err;
> > +}
> > +#endif
> > +
>
>
> --
> Sent by a consultant of the Qualcomm Innovation Center, Inc.
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/