blob: 4a57c978eebc479d1a921ae1c0b5affdb3e335fa [file] [log] [blame]
/************************************************************************************************/
/* */
/* Copyright 2010 Broadcom Corporation */
/* */
/* Unless you and Broadcom execute a separate written software license agreement governing */
/* use of this software, this software is licensed to you under the terms of the GNU */
/* General Public License version 2 (the GPL), available at */
/* */
/* http://www.broadcom.com/licenses/GPLv2.php */
/* */
/* with the following added to such license: */
/* */
/* As a special exception, the copyright holders of this software give you permission to */
/* link this software with independent modules, and to copy and distribute the resulting */
/* executable under terms of your choice, provided that you also meet, for each linked */
/* independent module, the terms and conditions of the license of that module. */
/* An independent module is a module which is not derived from this software. The special */
/* exception does not apply to any modifications of the software. */
/* */
/* Notwithstanding the above, under no circumstances may you combine this software in any */
/* way with any other Broadcom software provided under a license other than the GPL, */
/* without Broadcom's express prior written consent. */
/* */
/************************************************************************************************/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/wait.h>
#include <linux/input.h>
#include <linux/mfd/bcm590xx/bcm59055_A0.h>
#include <linux/mfd/bcm590xx/core.h>
#define BCM59055_PONKEYCTRL1_DEB_MASK 0x3F
#define PON_PRESS_DEB_OFFSET 0
#define PON_RELEASE_DEB_OFFSET 3
#define PON_PRESS_DEB_VAL 3 /* 100 ms */
#define PON_RELEASE_DEB_VAL 3 /* 100 ms */
struct bcm59055_onkey_info {
struct input_dev *idev;
struct bcm590xx *chip;
};
static void bcm59055_onkey_handler(int irq, void *data)
{
struct bcm59055_onkey_info *info = data;
int val = 0;
switch(irq) {
case BCM59055_IRQID_INT1_POK_PRESSED:
val = 1;
break;
case BCM59055_IRQID_INT1_POK_RELEASED:
val = 0;
break;
default:
dev_err(info->chip->dev, "Invalid IRQ %d\n", irq);
return;
break;
}
input_report_key(info->idev, KEY_POWER, val);
input_sync(info->idev);
}
static int __devinit bcm59055_onkey_probe(struct platform_device *pdev)
{
struct bcm590xx *chip = dev_get_drvdata(pdev->dev.parent);
struct bcm59055_onkey_info *info;
int ctrl1;
int error;
info = kzalloc(sizeof(struct bcm59055_onkey_info), GFP_KERNEL);
if (!info) {
dev_err(chip->dev, "Failed to allocate memory (%d bytes)\n", sizeof(struct bcm59055_onkey_info));
return -ENOMEM;
}
info->idev = input_allocate_device();
if (!info->idev) {
dev_err(chip->dev, "Failed to allocate input dev\n");
error = -ENOMEM;
goto out_input;
}
info->idev->name = "bcm59055_on";
info->idev->phys = "bcm59055_on/input0";
info->idev->dev.parent = &pdev->dev;
info->idev->evbit[0] = BIT_MASK(EV_KEY);
info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
info->chip = chip;
/* Request PRESSED and RELEASED interrupts.
*/
error = bcm590xx_request_irq(chip, BCM59055_IRQID_INT1_POK_PRESSED, true, bcm59055_onkey_handler, info);
if (error < 0) {
dev_err(chip->dev, "Failed to request bcm59055 IRQ %d: %d\n",
BCM59055_IRQID_INT1_POK_PRESSED, error);
goto out_irq_pressed;
}
error = bcm590xx_request_irq(chip, BCM59055_IRQID_INT1_POK_RELEASED, true, bcm59055_onkey_handler, info);
if (error < 0) {
dev_err(chip->dev, "Failed to request bcm59055 IRQ %d: %d\n",
BCM59055_IRQID_INT1_POK_RELEASED, error);
goto out_irq_released;
}
/* Adjust key press debounce time.
*/
ctrl1 = bcm590xx_reg_read(chip, BCM59055_REG_PONKEYCTRL1);
ctrl1 &= ~BCM59055_PONKEYCTRL1_DEB_MASK;
ctrl1 &= 0xFF;
ctrl1 |= (PON_PRESS_DEB_VAL << PON_PRESS_DEB_OFFSET) | (PON_RELEASE_DEB_VAL << PON_RELEASE_DEB_OFFSET);
bcm590xx_reg_write(chip, BCM59055_REG_PONKEYCTRL1, (uint16_t) ctrl1);
error = input_register_device(info->idev);
if (error) {
dev_err(chip->dev, "Can't register input device: %d\n", error);
goto out;
}
platform_set_drvdata(pdev, info);
return 0;
out:
bcm590xx_free_irq(chip, BCM59055_IRQID_INT1_POK_RELEASED);
out_irq_released:
bcm590xx_free_irq(chip, BCM59055_IRQID_INT1_POK_PRESSED);
out_irq_pressed:
input_free_device(info->idev);
out_input:
kfree(info);
return error;
}
static int __devexit bcm59055_onkey_remove(struct platform_device *pdev)
{
struct bcm59055_onkey_info *info = platform_get_drvdata(pdev);
bcm590xx_free_irq(info->chip, BCM59055_IRQID_INT1_POK_PRESSED);
bcm590xx_free_irq(info->chip, BCM59055_IRQID_INT1_POK_RELEASED);
input_unregister_device(info->idev);
kfree(info);
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver bcm59055_onkey_driver = {
.driver = {
.name = "bcm590xx-onkey",
.owner = THIS_MODULE,
},
.probe = bcm59055_onkey_probe,
.remove = __devexit_p(bcm59055_onkey_remove),
};
static int __init bcm59055_onkey_init(void)
{
return platform_driver_register(&bcm59055_onkey_driver);
}
static void __exit bcm59055_onkey_exit(void)
{
platform_driver_unregister(&bcm59055_onkey_driver);
}
/*
* module specification
*/
module_init(bcm59055_onkey_init);
module_exit(bcm59055_onkey_exit);
MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("BCM59055 Power-On Key device driver");
MODULE_LICENSE("GPL");