summaryrefslogtreecommitdiff
path: root/drivers/input/misc/hall_switch.c
blob: fb186c3be77f309129cfd0e659e28ac051528651 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
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");