高通平台添加设备驱动流程

高通平台添加驱动如下: 

----------- kernel/msm-3.18/arch/arm/boot/dts/qcom/msm-pmi8950.dtsi -----------
index a714654..d6c2c57 100644
@@ -192,7 +192,13 @@
             mpp@a300 {
                 reg = <0xa300 0x100>;
                 qcom,pin-num = <4>;
-                status = "disabled";
+                //status = "disabled";
+                qcom,mode = <1>;
+                qcom,invert = <0>;
+                qcom,src-sel = <5>; // notice: mpp4 need config DTETS2
+                qcom,pull = <1>;
+                qcom,vin-sel = <3>;
+                qcom,master-en = <1>;
             };
         };
 
@@ -410,6 +416,16 @@
             reg = <0xa100 0x100>;
             label = "mpp";
         };
+
+        pwm-beeper@a300 {
+            compatible = "ckt-pwm-beeper";
+            label = "mpp";
+            reg = <0xa300 0x100>;
+            pwms = <&pmi8950_pwm 0 0>;
+            //pinctrl-names = "default";
+            //pinctrl-0 = <&pwm0_pin>;
+            status = "okay";
+        };
     };
 
     qcom,pmi8950@3 {
@@ -419,13 +435,21 @@
         #size-cells = <1>;
 
         pmi8950_pwm: pwm@b000 {
-            status = "disabled";
+            //status = "disabled";
+            status = "okay";
             compatible = "qcom,qpnp-pwm";
             reg = <0xb000 0x100>;
             reg-names = "qpnp-lpg-channel-base";
             qcom,channel-id = <0>;
             qcom,supported-sizes = <6>, <9>;
+            qcom,period = <4000000>;
             #pwm-cells = <2>;
+            qcom,dtest-line = <2>; // notice: pwm need config DTETS2
+            qcom,dtest-output = <2>;
+            qcom,pwm {
+                qcom,duty = <2000000>; //PWM duty time in microseconds
+                 label = "pwm"; 
+            };
         };
 
         labibb: qpnp-labibb-regulator {

--------- kernel/msm-3.18/arch/arm64/configs/msmcortex-perf_defconfig ---------
index f5249bc..87d96b8 100755
@@ -596,6 +596,7 @@ CONFIG_SPDM_SCM=y
 CONFIG_DEVFREQ_SPDM=y
 CONFIG_PWM=y
 CONFIG_PWM_QPNP=y
+CONFIG_INPUT_CKT_PWM_BEEPER=y
 CONFIG_ARM_GIC_PANIC_HANDLER=y
 CONFIG_ARM_GIC_V3_ACL=y
 CONFIG_CORESIGHT=y

------------ kernel/msm-3.18/arch/arm64/configs/msmcortex_defconfig ------------
index 4b4a396..a4eaaa2 100755
@@ -623,6 +623,8 @@ CONFIG_SPDM_SCM=y
 CONFIG_DEVFREQ_SPDM=y
 CONFIG_PWM=y
 CONFIG_PWM_QPNP=y
+#Evan add
+CONFIG_INPUT_CKT_PWM_BEEPER=y
 CONFIG_ARM_GIC_PANIC_HANDLER=y
 CONFIG_ARM_GIC_V3_ACL=y
 CONFIG_CORESIGHT=y

------------------ kernel/msm-3.18/drivers/input/misc/Kconfig ------------------
index 4069df1..7e75ce5 100644
@@ -558,6 +558,17 @@ config INPUT_PWM_BEEPER
       To compile this driver as a module, choose M here: the module will be
       called pwm-beeper.
 
+config INPUT_CKT_PWM_BEEPER
+    tristate "CKT PWM beeper support"
+    depends on PWM
+    help
+      Say Y here to get support for PWM based beeper devices.
+
+      If unsure, say N.
+
+      To compile this driver as a module, choose M here: the module will be
+      called ckt-pwm-beeper.
+
 config INPUT_GPIO_ROTARY_ENCODER
     tristate "Rotary encoders connected to GPIO pins"
     depends on GPIOLIB

----------------- kernel/msm-3.18/drivers/input/misc/Makefile -----------------
index 1456a01..1efb67d 100644
@@ -57,6 +57,7 @@ obj-$(CONFIG_INPUT_PM8XXX_VIBRATOR)    += pm8xxx-vibrator.o
 obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY)    += pmic8xxx-pwrkey.o
 obj-$(CONFIG_INPUT_POWERMATE)        += powermate.o
 obj-$(CONFIG_INPUT_PWM_BEEPER)        += pwm-beeper.o
+obj-$(CONFIG_INPUT_CKT_PWM_BEEPER)    += ckt-pwm-beeper.o
 obj-$(CONFIG_INPUT_RB532_BUTTON)    += rb532_button.o
 obj-$(CONFIG_INPUT_RETU_PWRBUTTON)    += retu-pwrbutton.o
 obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER)    += rotary_encoder.o

------------- kernel/msm-3.18/drivers/input/misc/ckt-pwm-beeper.c -------------
new file mode 100644
index 0000000..1d82031
@@ -0,0 +1,285 @@
+/*
+ *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ *  PWM beeper driver
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under  the terms of the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+
+struct pwm_beeper {
+    struct input_dev *input;
+    struct pwm_device *pwm;
+    unsigned long period;
+    struct class *beeper_class;
+};
+
+static struct pwm_beeper *beeper;
+
+#define HZ_TO_NANOSECONDS(x) (1000000000UL/(x))
+#define BEEPER_DEF_HZ   4000
+
+static ssize_t beeper_bell(struct class *class,
+            struct class_attribute *attr,
+            const char *buf, size_t count)
+{
+    ssize_t ret = -EINVAL;
+    int value,period;
+
+    pr_debug("%s\n",__func__);
+    ret = kstrtoint(buf, 10, &value);
+    if (ret)
+        return ret;
+    
+    if (value == 0) {
+        pwm_config(beeper->pwm, 0, 0);
+        pwm_disable(beeper->pwm);
+        beeper->period = 0;
+    } else {
+        period = HZ_TO_NANOSECONDS(BEEPER_DEF_HZ);
+        ret = pwm_config(beeper->pwm, period / 2, period);
+        if (ret)
+            return ret;
+        ret = pwm_enable(beeper->pwm);
+        if (ret)
+            return ret;
+        beeper->period = period;
+    }
+    
+    return count;
+}
+
+static ssize_t beeper_tone(struct class *class,
+            struct class_attribute *attr,
+            const char *buf, size_t count)
+{
+
+    ssize_t ret = -EINVAL;
+    int value,period;
+
+    pr_debug("%s\n",__func__);
+    ret = kstrtoint(buf, 10, &value);
+    if (ret)
+        return ret;
+    if (value == 0) {
+        pwm_config(beeper->pwm, 0, 0);
+        pwm_disable(beeper->pwm);
+        beeper->period = 0;
+    } else {
+        period = HZ_TO_NANOSECONDS(value);
+        ret = pwm_config(beeper->pwm, period / 2, period);
+        if (ret)
+            return ret;
+        ret = pwm_enable(beeper->pwm);
+        if (ret)
+            return ret;
+        beeper->period = period;
+    }
+
+    return count;
+}
+
+static CLASS_ATTR(bell, 0644, NULL, beeper_bell);
+static CLASS_ATTR(tone, 0644, NULL, beeper_tone);
+
+
+static int pwm_beeper_event(struct input_dev *input,
+                unsigned int type, unsigned int code, int value)
+{
+    int ret = 0;
+    struct pwm_beeper *beeper = input_get_drvdata(input);
+    unsigned long period;
+    pr_debug("%s:code=%d,value=%d\n",__func__,code,value);
+    if (type != EV_SND || value < 0)
+        return -EINVAL;
+
+    switch (code) {
+    case SND_BELL:
+        value = value ? 1000 : 0;
+        break;
+    case SND_TONE:
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    if (value == 0) {
+        pwm_config(beeper->pwm, 0, 0);
+        pwm_disable(beeper->pwm);
+        beeper->period = 0;
+    } else {
+        period = HZ_TO_NANOSECONDS(value);
+        ret = pwm_config(beeper->pwm, period / 2, period);
+        if (ret)
+            return ret;
+        ret = pwm_enable(beeper->pwm);
+        if (ret)
+            return ret;
+        beeper->period = period;
+    }
+
+    return 0;
+}
+
+static int pwm_beeper_probe(struct spmi_device *spmi)
+{
+    struct device_node *node;
+    int error;
+
+    node = spmi->dev.of_node;
+    if (node == NULL)
+        return -ENODEV;
+    
+    beeper = kzalloc(sizeof(*beeper), GFP_KERNEL);
+    if (!beeper)
+        return -ENOMEM;
+
+    beeper->pwm = of_pwm_get(node, NULL);
+    if (IS_ERR(beeper->pwm)) {
+        pr_err("%s: Error, pwm device\n",__func__);
+        beeper->pwm = NULL;
+        goto err_free;
+    }
+
+    beeper->input = input_allocate_device();
+    if (!beeper->input) {
+        dev_err(&spmi->dev, "Failed to allocate input device\n");
+        error = -ENOMEM;
+        goto err_pwm_free;
+    }
+    beeper->input->dev.parent = &spmi->dev;
+
+    beeper->input->name = "pwm-beeper";
+    beeper->input->phys = "pwm/input0";
+    beeper->input->id.bustype = BUS_HOST;
+    beeper->input->id.vendor = 0x001f;
+    beeper->input->id.product = 0x0001;
+    beeper->input->id.version = 0x0100;
+
+    beeper->input->evbit[0] = BIT(EV_SND);
+    beeper->input->sndbit[0] = BIT(SND_TONE) | BIT(SND_BELL);
+
+    beeper->input->event = pwm_beeper_event;
+
+    input_set_drvdata(beeper->input, beeper);
+
+    error = input_register_device(beeper->input);
+    if (error) {
+        dev_err(&spmi->dev, "Failed to register input device: %d\n", error);
+        goto err_input_free;
+    }
+
+    beeper->beeper_class= class_create(THIS_MODULE, "beeper");
+    if (IS_ERR(beeper->beeper_class))
+        return PTR_ERR(beeper->beeper_class);
+    error = class_create_file(beeper->beeper_class, &class_attr_bell);
+    error = class_create_file(beeper->beeper_class, &class_attr_tone);
+
+    dev_set_drvdata(&spmi->dev, beeper);
+
+    return 0;
+
+err_input_free:
+    input_free_device(beeper->input);
+err_pwm_free:
+    pwm_free(beeper->pwm);
+err_free:
+    kfree(beeper);
+
+    return error;
+}
+
+static int pwm_beeper_remove(struct spmi_device *spmi)
+{
+    //struct pwm_beeper *beeper = dev_get_drvdata(&spmi->dev);
+    class_remove_file(beeper->beeper_class, &class_attr_bell);
+    class_remove_file(beeper->beeper_class, &class_attr_tone);
+    class_destroy(beeper->beeper_class);
+        
+    input_unregister_device(beeper->input);
+
+    pwm_disable(beeper->pwm);
+    pwm_free(beeper->pwm);
+
+    kfree(beeper);
+
+    return 0;
+}
+
+#if 0 //#ifdef CONFIG_PM_SLEEP
+static int pwm_beeper_suspend(struct spmi_device *spmi)
+{
+    //struct pwm_beeper *beeper = dev_get_drvdata(&spmi->dev);
+
+    if (beeper->period)
+        pwm_disable(beeper->pwm);
+
+    return 0;
+}
+
+static int pwm_beeper_resume(struct spmi_device *spmi)
+{
+    //struct pwm_beeper *beeper = dev_get_drvdata(&spmi->dev);
+
+    if (beeper->period) {
+        pwm_config(beeper->pwm, beeper->period / 2, beeper->period);
+        pwm_enable(beeper->pwm);
+    }
+
+    return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(pwm_beeper_pm_ops,
+             pwm_beeper_suspend, pwm_beeper_resume);
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id pwm_beeper_match[] = {
+    { .compatible = "ckt-pwm-beeper", },
+    { },
+};
+#endif
+
+static struct spmi_driver pwm_beeper_driver = {
+    .probe    = pwm_beeper_probe,
+    .remove = pwm_beeper_remove,
+    .driver = {
+        .name    = "pwm-beeper",
+        .owner    = THIS_MODULE,
+        //.pm    = PWM_BEEPER_PM_OPS,
+        .of_match_table = of_match_ptr(pwm_beeper_match),
+    },
+};
+
+static int __init pwm_beeper_init(void)
+{
+    return spmi_driver_register(&pwm_beeper_driver);
+}
+module_init(pwm_beeper_init);
+
+static void __exit pwm_beeper_exit(void)
+{
+    spmi_driver_unregister(&pwm_beeper_driver);
+}
+module_exit(pwm_beeper_exit);
+
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("PWM beeper driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pwm-beeper");

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值