summaryrefslogtreecommitdiff
path: root/drivers/input/misc/hall_switch.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/misc/hall_switch.c')
-rw-r--r--drivers/input/misc/hall_switch.c269
1 files changed, 269 insertions, 0 deletions
diff --git a/drivers/input/misc/hall_switch.c b/drivers/input/misc/hall_switch.c
new file mode 100644
index 000000000000..fb186c3be77f
--- /dev/null
+++ b/drivers/input/misc/hall_switch.c
@@ -0,0 +1,269 @@
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/bitops.h>
+
+#include <linux/platform_device.h>
+
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+
+
+static volatile int key_debug = 5;
+#define HALL_GPIO 124
+
+#define SSC_VDD_2P85_HPM_LOAD 600000 //uA
+
+
+struct hall_switch_data{
+ struct regulator *vdd;
+ struct regulator *ssc_vdd;
+ struct input_dev *input_dev;
+ struct delayed_work hall_work;
+ struct workqueue_struct *hall_workqueue;
+ int irq_gpio;
+ int hall_irq;
+ int hall_gpio_val;
+ struct device *dev;
+};
+static struct hall_switch_data *hall_data = NULL;
+static irqreturn_t misc_hall_irq(int irq, void *data)
+{
+ struct hall_switch_data *hall_data = data;
+ int gpio_value;
+ //int ret;
+
+ if(hall_data == NULL)
+ return 0;
+ disable_irq_nosync(hall_data->hall_irq);
+ gpio_value = gpio_get_value(HALL_GPIO);
+ if(gpio_value){
+ /*----hall far----*/
+ if(key_debug == 5)
+ printk("hall-switch %d,report: far\n",HALL_GPIO);
+ input_event(hall_data->input_dev, EV_SW, SW_LID, 0);
+ input_sync(hall_data->input_dev);
+ }else{
+ /*----hall near----*/
+ if(key_debug == 5)
+ printk("hall-switch %d,report: near!!!\n",HALL_GPIO);
+ input_event(hall_data->input_dev, EV_SW, SW_LID, 1);
+ input_sync(hall_data->input_dev);
+ }
+ enable_irq(hall_data->hall_irq);
+ return IRQ_HANDLED;
+}
+
+static ssize_t hall_irq_gpio_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int tmp = gpio_get_value(HALL_GPIO);
+ return sprintf(buf, "%s\n", tmp==0?"0":"1");
+}
+
+static DEVICE_ATTR(hall_int_gpio, 0444, hall_irq_gpio_show, NULL);
+
+static struct attribute *hall_attributes[] = {
+ &dev_attr_hall_int_gpio.attr,
+ NULL,
+};
+
+static struct attribute_group hall_attr_group = {
+ .attrs = hall_attributes,
+};
+
+static int hall_probe(struct platform_device *pdev)
+{
+ static int is_probed = 0; /* Flag used to avoid double probe. */
+ int retval = 0;
+
+ int err = 0;
+ struct device_node *np = pdev->dev.of_node;
+
+ if (is_probed) {
+ printk("%s: Already probed succesfully, ignored\n", __FUNCTION__);
+ return 0;
+ }
+
+ hall_data = kzalloc(sizeof(struct hall_switch_data), GFP_KERNEL);
+ if (!hall_data){
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ /*hall_data->vdd = regulator_get(&pdev->dev,"vdd");
+ if (!IS_ERR(hall_data->vdd)) {
+ printk("%s,vdd is correct",__func__);
+ err = regulator_enable(hall_data->vdd);
+ if (err) {
+ printk("%s,Regulator vdd enable failed ret=%d\n", __func__,err);
+ }
+ }
+
+ hall_data->ssc_vdd = regulator_get(&pdev->dev,"ssc");
+ if (!IS_ERR(hall_data->ssc_vdd)) {
+ printk("%s,ssc_vdd is correct",__func__);
+ err = regulator_enable(hall_data->ssc_vdd);
+ if (err) {
+ printk("%s,Regulator ssc_vdd enable failed ret=%d\n", __func__,err);
+ }
+ }*/
+
+#if 1
+ hall_data->ssc_vdd = devm_regulator_get(&pdev->dev, "ssc_vdd");
+ if (IS_ERR(hall_data->ssc_vdd)) {
+ pr_err("%s - ssc_vdd regulator_get fail\n", __func__);
+ err = -ENODEV;
+ }
+
+ err = regulator_set_load(hall_data->ssc_vdd, SSC_VDD_2P85_HPM_LOAD);
+ if (err < 0) {
+ pr_err("%s:Unable to set current of ssc_vdd\n",__func__);
+ }
+
+ err = regulator_enable(hall_data->ssc_vdd);
+ if (err) {
+ pr_err("%s - enable ssc_vdd failed, err=%d\n",
+ __func__, err);
+ }
+
+
+ usleep_range(1000, 1100);
+
+#endif
+
+ /*----Register to Input Device----*/
+ hall_data->input_dev = input_allocate_device();
+ if (hall_data->input_dev == NULL){
+ err = -ENOMEM;
+ printk("hall-switch: Failed to allocate input device!!! \n");
+ goto exit_kfree;
+ }
+
+ hall_data->input_dev->name = "hall-switch";
+
+ set_bit(EV_SYN, hall_data->input_dev->evbit);
+ set_bit(EV_SW, hall_data->input_dev->evbit);
+ set_bit(EV_ABS, hall_data->input_dev->evbit);
+
+ set_bit(SW_LID, hall_data->input_dev->swbit);
+ input_set_capability(hall_data->input_dev, EV_SW, SW_LID);
+
+ /*set_bit(KEY_SPORT_B, hall_data->input_dev->keybit);
+ input_set_capability(hall_data->input_dev, EV_KEY, KEY_SPORT_B);
+ set_bit(KEY_SHOP_B, hall_data->input_dev->keybit);
+ input_set_capability(hall_data->input_dev, EV_KEY, KEY_SHOP_B);*/
+
+ retval = input_register_device(hall_data->input_dev);
+ if(retval){
+ printk("hall-switch: Failed to register input device!!!\n");
+ goto exit_register_input;
+ }
+
+ hall_data->irq_gpio = of_get_named_gpio(np, "shenqi,hall-irq-gpio", 0);
+ if (hall_data->irq_gpio < 0) {
+ pr_err("failed to get hall's \"shenqi,hall-irq-gpio\"\n");
+ goto exit_enable_irq;
+ }
+
+ retval = gpio_request(hall_data->irq_gpio, "hall_gpio");
+ if (retval) {
+ printk("hall-switch: irq gpio %d,request failed\n",hall_data->irq_gpio);
+ goto exit_enable_irq;
+ }
+ retval = gpio_direction_input(hall_data->irq_gpio);
+ if (retval) {
+ printk("hall-switch: irq gpio %d,direction set failed\n",hall_data->irq_gpio);
+ goto exit_free_gpio;
+ }
+
+ hall_data->hall_irq = gpio_to_irq(hall_data->irq_gpio);
+ retval = request_threaded_irq( hall_data->hall_irq, NULL, misc_hall_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "misc_hall_irq", hall_data);
+ if(retval < 0){
+ printk("hall-switch: Failed to create hall irq thread!!!i%d\n",hall_data->hall_irq);
+ goto exit_free_gpio;
+ }
+ enable_irq_wake(hall_data->hall_irq);
+
+ retval = sysfs_create_group(&pdev->dev.kobj, &hall_attr_group);
+ if(retval) {
+ printk(KERN_ERR "%s: Failed to create sysfs\n", __FUNCTION__);
+ }
+ printk("%s sysfs_create_group sucess\n", __func__);
+
+ is_probed = 1;
+ return retval;
+exit_free_gpio:
+ gpio_free(HALL_GPIO);
+exit_enable_irq:
+ input_unregister_device(hall_data->input_dev);
+
+exit_register_input:
+ input_free_device(hall_data->input_dev);
+ hall_data->input_dev = NULL;
+
+exit_kfree:
+ kfree(hall_data);
+exit:
+ return err;
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id hall_match_table[] = {
+ { .compatible = "shenqi,hall_switch",},
+ { },
+};
+#else
+#define hall_match_table NULL
+#endif
+
+static int hall_prepare(struct device *dev)
+{
+ /*int err = 0;
+ err = regulator_enable(hall_data->ssc_vdd);
+ if (err) {
+ printk("%s,Regulator ssc_vdd enable failed ret=%d\n", __func__,err);
+ }*/
+ return 0;
+}
+
+static void hall_complete(struct device *dev)
+{
+ /*int err = 0;
+ err = regulator_disable(hall_data->ssc_vdd);
+ if (err) {
+ printk("%s,Regulator ssc_vdd disable failed ret=%d\n", __func__,err);
+ }*/
+}
+
+static const struct dev_pm_ops hall_pm = {
+ .prepare = hall_prepare,
+ .complete = hall_complete
+};
+
+static struct platform_driver msm_hall_driver = {
+ .probe = hall_probe,
+ .driver = {
+ .name = "msm_hall_switch",
+ .owner = THIS_MODULE,
+ .of_match_table = hall_match_table,
+ .pm = &hall_pm,
+ },
+};
+
+static int __init hall_init(void)
+{
+ return platform_driver_register(&msm_hall_driver);
+}
+
+module_init(hall_init);
+MODULE_DESCRIPTION("Hall switch sensor driver");
+MODULE_LICENSE("GPL"); \ No newline at end of file