高通平台添加驱动如下:
----------- 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");