WLED driver provides the interface to the display driver to
adjust the brightness of the display backlight.

Signed-off-by: Kiran Gunda <[email protected]>
---
 .../bindings/leds/backlight/qcom-spmi-wled.txt     |  90 ++++
 drivers/video/backlight/Kconfig                    |   9 +
 drivers/video/backlight/Makefile                   |   1 +
 drivers/video/backlight/qcom-spmi-wled.c           | 504 +++++++++++++++++++++
 4 files changed, 604 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt
 create mode 100644 drivers/video/backlight/qcom-spmi-wled.c

diff --git 
a/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt 
b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt
new file mode 100644
index 0000000..f1ea25b
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/backlight/qcom-spmi-wled.txt
@@ -0,0 +1,90 @@
+Binding for Qualcomm WLED driver
+
+WLED (White Light Emitting Diode) driver is used for controlling display
+backlight that is part of PMIC on Qualcomm Technologies reference platforms.
+The PMIC is connected to the host processor via SPMI bus.
+
+- compatible
+       Usage:      required
+       Value type: <string>
+       Definition: should be "qcom,pm8998-spmi-wled".
+
+- reg
+       Usage:      required
+       Value type: <prop-encoded-array>
+       Definition:  Base address and size of the WLED modules.
+
+- reg-names
+       Usage:      required
+       Value type: <string>
+       Definition:  Names associated with base addresses. should be
+                    "qcom-wled-ctrl-base", "qcom-wled-sink-base".
+
+- label
+       Usage:      required
+       Value type: <string>
+       Definition: The name of the backlight device.
+
+- default-brightness
+       Usage:      optional
+       Value type: <u32>
+       Definition: brightness value on boot, value from: 0-4095
+                   default: 2048
+
+- qcom,fs-current-limit
+       Usage:      optional
+       Value type: <u32>
+       Definition: per-string full scale current limit in uA. value from
+                   0 to 30000 with 5000 uA resolution. default: 25000 uA
+
+- qcom,current-boost-limit
+       Usage:      optional
+       Value type: <u32>
+       Definition: ILIM threshold in mA. values are 105, 280, 450, 620, 970,
+                   1150, 1300, 1500. default: 970 mA
+
+- qcom,switching-freq
+       Usage:      optional
+       Value type: <u32>
+       Definition: Switching frequency in KHz. values are
+                   600, 640, 685, 738, 800, 872, 960, 1066, 1200, 1371,
+                   1600, 1920, 2400, 3200, 4800, 9600.
+                   default: 800 KHz
+
+- qcom,ovp
+       Usage:      optional
+       Value type: <u32>
+       Definition: Over-voltage protection limit in mV. values are 31100,
+                   29600, 19600, 18100.
+                   default: 29600 mV
+
+- qcom,string-cfg
+       Usage:      optional
+       Value type: <u32>
+       Definition: Bit mask of the wled strings. Bit 0 to 3 indicates strings
+                   0 to 3 respectively. Wled module has four strings of leds
+                   numbered from 0 to 3. Each string of leds are operated
+                   individually. Specify the strings using the bit mask. Any
+                   combination of led strings can be used.
+                   default value is 15 (b1111).
+
+- qcom,en-cabc
+       Usage:      optional
+       Value type: <bool>
+       Definition: Specify if cabc (content adaptive backlight control) is
+                   needed.
+
+Example:
+
+qcom-wled@d800 {
+       compatible = "qcom,pm8998-spmi-wled";
+       reg = <0xd800 0xd900>;
+       reg-names = "qcom-wled-ctrl-base", "qcom-wled-sink-base";
+       label = "backlight";
+
+       qcom,fs-current-limit = <25000>;
+       qcom,current-boost-limit = <970>;
+       qcom,switching-freq = <800>;
+       qcom,ovp = <29600>;
+       qcom,string-cfg = <15>;
+};
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 4e1d2ad..19ea799 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -306,6 +306,15 @@ config BACKLIGHT_PM8941_WLED
          If you have the Qualcomm PM8941, say Y to enable a driver for the
          WLED block.
 
+config BACKLIGHT_QCOM_SPMI_WLED
+       tristate "Qualcomm WLED Driver"
+       select REGMAP
+       help
+         If you have the Qualcomm WLED used for backlight control, say Y to
+         enable a driver for the  WLED block. This driver provides the
+         interface to the display driver to adjust the brightness of the
+         display backlight. This supports PMI8998 currently.
+
 config BACKLIGHT_SAHARA
        tristate "Tabletkiosk Sahara Touch-iT Backlight Driver"
        depends on X86
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 5e28f01..f6627e5 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_BACKLIGHT_PANDORA)               += pandora_bl.o
 obj-$(CONFIG_BACKLIGHT_PCF50633)       += pcf50633-backlight.o
 obj-$(CONFIG_BACKLIGHT_PM8941_WLED)    += pm8941-wled.o
 obj-$(CONFIG_BACKLIGHT_PWM)            += pwm_bl.o
+obj-$(CONFIG_BACKLIGHT_QCOM_SPMI_WLED) += qcom-spmi-wled.o
 obj-$(CONFIG_BACKLIGHT_SAHARA)         += kb3886_bl.o
 obj-$(CONFIG_BACKLIGHT_SKY81452)       += sky81452-backlight.o
 obj-$(CONFIG_BACKLIGHT_TOSA)           += tosa_bl.o
diff --git a/drivers/video/backlight/qcom-spmi-wled.c 
b/drivers/video/backlight/qcom-spmi-wled.c
new file mode 100644
index 0000000..14c3adc
--- /dev/null
+++ b/drivers/video/backlight/qcom-spmi-wled.c
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/backlight.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+
+/* General definitions */
+#define QCOM_WLED_DEFAULT_BRIGHTNESS           2048
+#define  QCOM_WLED_MAX_BRIGHTNESS              4095
+
+/* WLED control registers */
+#define QCOM_WLED_CTRL_MOD_ENABLE              0x46
+#define  QCOM_WLED_CTRL_MOD_EN_MASK            BIT(7)
+#define  QCOM_WLED_CTRL_MODULE_EN_SHIFT                7
+
+#define QCOM_WLED_CTRL_SWITCH_FREQ             0x4c
+#define  QCOM_WLED_CTRL_SWITCH_FREQ_MASK       GENMASK(3, 0)
+
+#define QCOM_WLED_CTRL_OVP                     0x4d
+#define  QCOM_WLED_CTRL_OVP_MASK               GENMASK(1, 0)
+
+#define QCOM_WLED_CTRL_ILIM                    0x4e
+#define  QCOM_WLED_CTRL_ILIM_MASK              GENMASK(2, 0)
+
+/* WLED sink registers */
+#define QCOM_WLED_SINK_CURR_SINK_EN            0x46
+#define  QCOM_WLED_SINK_CURR_SINK_MASK         GENMASK(7, 4)
+#define  QCOM_WLED_SINK_CURR_SINK_SHFT         0x04
+
+#define QCOM_WLED_SINK_SYNC                    0x47
+#define  QCOM_WLED_SINK_SYNC_MASK              GENMASK(3, 0)
+#define  QCOM_WLED_SINK_SYNC_LED1              BIT(0)
+#define  QCOM_WLED_SINK_SYNC_LED2              BIT(1)
+#define  QCOM_WLED_SINK_SYNC_LED3              BIT(2)
+#define  QCOM_WLED_SINK_SYNC_LED4              BIT(3)
+#define  QCOM_WLED_SINK_SYNC_CLEAR             0x00
+
+#define QCOM_WLED_SINK_MOD_EN_REG(n)           (0x50 + (n * 0x10))
+#define  QCOM_WLED_SINK_REG_STR_MOD_MASK       BIT(7)
+#define  QCOM_WLED_SINK_REG_STR_MOD_EN         BIT(7)
+
+#define QCOM_WLED_SINK_SYNC_DLY_REG(n)         (0x51 + (n * 0x10))
+#define QCOM_WLED_SINK_FS_CURR_REG(n)          (0x52 + (n * 0x10))
+#define  QCOM_WLED_SINK_FS_MASK                        GENMASK(3, 0)
+
+#define QCOM_WLED_SINK_CABC_REG(n)             (0x56 + (n * 0x10))
+#define  QCOM_WLED_SINK_CABC_MASK              BIT(7)
+#define  QCOM_WLED_SINK_CABC_EN                        BIT(7)
+
+#define QCOM_WLED_SINK_BRIGHT_LSB_REG(n)       (0x57 + (n * 0x10))
+#define QCOM_WLED_SINK_BRIGHT_MSB_REG(n)       (0x58 + (n * 0x10))
+
+struct qcom_wled_config {
+       u32 i_boost_limit;
+       u32 ovp;
+       u32 switch_freq;
+       u32 fs_current;
+       u32 string_cfg;
+       bool en_cabc;
+};
+
+struct qcom_wled {
+       const char *name;
+       struct platform_device *pdev;
+       struct regmap *regmap;
+       u16 sink_addr;
+       u16 ctrl_addr;
+       u32 brightness;
+       bool prev_state;
+
+       struct qcom_wled_config cfg;
+};
+
+static int qcom_wled_module_enable(struct qcom_wled *wled, int val)
+{
+       int rc;
+
+       rc = regmap_update_bits(wled->regmap, wled->ctrl_addr +
+                       QCOM_WLED_CTRL_MOD_ENABLE, QCOM_WLED_CTRL_MOD_EN_MASK,
+                       val << QCOM_WLED_CTRL_MODULE_EN_SHIFT);
+       return rc;
+}
+
+static int qcom_wled_get_brightness(struct backlight_device *bl)
+{
+       struct qcom_wled *wled = bl_get_data(bl);
+
+       return wled->brightness;
+}
+
+static int qcom_wled_sync_toggle(struct qcom_wled *wled)
+{
+       int rc;
+
+       rc = regmap_update_bits(wled->regmap,
+                       wled->sink_addr + QCOM_WLED_SINK_SYNC,
+                       QCOM_WLED_SINK_SYNC_MASK, QCOM_WLED_SINK_SYNC_MASK);
+       if (rc < 0)
+               return rc;
+
+       rc = regmap_update_bits(wled->regmap,
+                       wled->sink_addr + QCOM_WLED_SINK_SYNC,
+                       QCOM_WLED_SINK_SYNC_MASK, QCOM_WLED_SINK_SYNC_CLEAR);
+
+       return rc;
+}
+
+static int qcom_wled_set_brightness(struct qcom_wled *wled, u16 brightness)
+{
+       int rc, i;
+       u16 low_limit = QCOM_WLED_MAX_BRIGHTNESS * 4 / 1000;
+       u8 string_cfg = wled->cfg.string_cfg;
+       u8 v[2];
+
+       /* WLED's lower limit of operation is 0.4% */
+       if (brightness > 0 && brightness < low_limit)
+               brightness = low_limit;
+
+       v[0] = brightness & 0xff;
+       v[1] = (brightness >> 8) & 0xf;
+
+       for (i = 0; (string_cfg >> i) != 0; i++) {
+               if (string_cfg & BIT(i)) {
+                       rc = regmap_bulk_write(wled->regmap, wled->sink_addr +
+                                       QCOM_WLED_SINK_BRIGHT_LSB_REG(i), v, 2);
+                       if (rc < 0)
+                               return rc;
+               }
+       }
+
+       return 0;
+}
+
+static int qcom_wled_update_status(struct backlight_device *bl)
+{
+       struct qcom_wled *wled = bl_get_data(bl);
+       u16 brightness = bl->props.brightness;
+       int rc;
+
+       if (bl->props.power != FB_BLANK_UNBLANK ||
+           bl->props.fb_blank != FB_BLANK_UNBLANK ||
+           bl->props.state & BL_CORE_FBBLANK)
+               brightness = 0;
+
+       if (brightness) {
+               rc = qcom_wled_set_brightness(wled, brightness);
+               if (rc < 0) {
+                       pr_err("wled failed to set brightness rc:%d\n", rc);
+                       return rc;
+               }
+
+               if (!!brightness != wled->prev_state) {
+                       rc = qcom_wled_module_enable(wled, !!brightness);
+                       if (rc < 0) {
+                               pr_err("wled enable failed rc:%d\n", rc);
+                               return rc;
+                       }
+               }
+       } else {
+               rc = qcom_wled_module_enable(wled, brightness);
+               if (rc < 0) {
+                       pr_err("wled disable failed rc:%d\n", rc);
+                       return rc;
+               }
+       }
+
+       wled->prev_state = !!brightness;
+
+       rc = qcom_wled_sync_toggle(wled);
+       if (rc < 0) {
+               pr_err("wled sync failed rc:%d\n", rc);
+               return rc;
+       }
+
+       wled->brightness = brightness;
+
+       return rc;
+}
+
+static int qcom_wled_setup(struct qcom_wled *wled)
+{
+       int rc, temp, i;
+       u8 sink_en = 0;
+       u8 string_cfg = wled->cfg.string_cfg;
+
+       rc = regmap_update_bits(wled->regmap,
+                       wled->ctrl_addr + QCOM_WLED_CTRL_OVP,
+                       QCOM_WLED_CTRL_OVP_MASK, wled->cfg.ovp);
+       if (rc < 0)
+               return rc;
+
+       rc = regmap_update_bits(wled->regmap,
+                       wled->ctrl_addr + QCOM_WLED_CTRL_ILIM,
+                       QCOM_WLED_CTRL_ILIM_MASK, wled->cfg.i_boost_limit);
+       if (rc < 0)
+               return rc;
+
+       rc = regmap_update_bits(wled->regmap,
+                       wled->ctrl_addr + QCOM_WLED_CTRL_SWITCH_FREQ,
+                       QCOM_WLED_CTRL_SWITCH_FREQ_MASK, wled->cfg.switch_freq);
+       if (rc < 0)
+               return rc;
+
+       for (i = 0; (string_cfg >> i) != 0; i++) {
+               if (string_cfg & BIT(i)) {
+                       u16 addr = wled->sink_addr +
+                                       QCOM_WLED_SINK_MOD_EN_REG(i);
+
+                       rc = regmap_update_bits(wled->regmap, addr,
+                                       QCOM_WLED_SINK_REG_STR_MOD_MASK,
+                                       QCOM_WLED_SINK_REG_STR_MOD_EN);
+                       if (rc < 0)
+                               return rc;
+
+                       addr = wled->sink_addr +
+                                       QCOM_WLED_SINK_FS_CURR_REG(i);
+                       rc = regmap_update_bits(wled->regmap, addr,
+                                       QCOM_WLED_SINK_FS_MASK,
+                                       wled->cfg.fs_current);
+                       if (rc < 0)
+                               return rc;
+
+                       addr = wled->sink_addr +
+                                       QCOM_WLED_SINK_CABC_REG(i);
+                       rc = regmap_update_bits(wled->regmap, addr,
+                                       QCOM_WLED_SINK_CABC_MASK,
+                                       wled->cfg.en_cabc ?
+                                       QCOM_WLED_SINK_CABC_EN : 0);
+                       if (rc)
+                               return rc;
+
+                       temp = i + QCOM_WLED_SINK_CURR_SINK_SHFT;
+                       sink_en |= 1 << temp;
+               }
+       }
+
+       rc = regmap_update_bits(wled->regmap,
+                       wled->sink_addr + QCOM_WLED_SINK_CURR_SINK_EN,
+                       QCOM_WLED_SINK_CURR_SINK_MASK, sink_en);
+       if (rc < 0)
+               return rc;
+
+       rc = qcom_wled_sync_toggle(wled);
+       if (rc < 0) {
+               pr_err("Failed to toggle sync reg rc:%d\n", rc);
+               return rc;
+       }
+
+       return 0;
+}
+
+static const struct qcom_wled_config wled_config_defaults = {
+       .i_boost_limit = 4,
+       .fs_current = 10,
+       .ovp = 1,
+       .switch_freq = 11,
+       .string_cfg = 0xf,
+       .en_cabc = 0,
+};
+
+struct qcom_wled_var_cfg {
+       const u32 *values;
+       u32 (*fn)(u32);
+       int size;
+};
+
+static const u32 wled_i_boost_limit_values[] = {
+       105, 280, 450, 620, 970, 1150, 1300, 1500,
+};
+
+static const struct qcom_wled_var_cfg wled_i_boost_limit_cfg = {
+       .values = wled_i_boost_limit_values,
+       .size = ARRAY_SIZE(wled_i_boost_limit_values),
+};
+
+static const u32 wled_fs_current_values[] = {
+       0, 2500, 5000, 7500, 10000, 12500, 15000, 17500, 20000,
+       22500, 25000, 27500, 30000,
+};
+
+static const struct qcom_wled_var_cfg wled_fs_current_cfg = {
+       .values = wled_fs_current_values,
+       .size = ARRAY_SIZE(wled_fs_current_values),
+};
+
+static const u32 wled_ovp_values[] = {
+       31100, 29600, 19600, 18100,
+};
+
+static const struct qcom_wled_var_cfg wled_ovp_cfg = {
+       .values = wled_ovp_values,
+       .size = ARRAY_SIZE(wled_ovp_values),
+};
+
+static u32 qcom_wled_switch_freq_values_fn(u32 idx)
+{
+       return 19200 / (2 * (1 + idx));
+}
+
+static const struct qcom_wled_var_cfg wled_switch_freq_cfg = {
+       .fn = qcom_wled_switch_freq_values_fn,
+       .size = 16,
+};
+
+static const struct qcom_wled_var_cfg wled_string_cfg = {
+       .size = 16,
+};
+
+static u32 qcom_wled_values(const struct qcom_wled_var_cfg *cfg, u32 idx)
+{
+       if (idx >= cfg->size)
+               return UINT_MAX;
+       if (cfg->fn)
+               return cfg->fn(idx);
+       if (cfg->values)
+               return cfg->values[idx];
+       return idx;
+}
+
+static int qcom_wled_configure(struct qcom_wled *wled, struct device *dev)
+{
+       struct qcom_wled_config *cfg = &wled->cfg;
+       const __be32 *prop_addr;
+       u32 val, c;
+       int rc, i, j;
+
+       const struct {
+               const char *name;
+               u32 *val_ptr;
+               const struct qcom_wled_var_cfg *cfg;
+       } u32_opts[] = {
+               {
+                       "qcom,current-boost-limit",
+                       &cfg->i_boost_limit,
+                       .cfg = &wled_i_boost_limit_cfg,
+               },
+               {
+                       "qcom,fs-current-limit",
+                       &cfg->fs_current,
+                       .cfg = &wled_fs_current_cfg,
+               },
+               {
+                       "qcom,ovp",
+                       &cfg->ovp,
+                       .cfg = &wled_ovp_cfg,
+               },
+               {
+                       "qcom,switching-freq",
+                       &cfg->switch_freq,
+                       .cfg = &wled_switch_freq_cfg,
+               },
+               {
+                       "qcom,string-cfg",
+                       &cfg->string_cfg,
+                       .cfg = &wled_string_cfg,
+               },
+       };
+
+       const struct {
+               const char *name;
+               bool *val_ptr;
+       } bool_opts[] = {
+               { "qcom,en-cabc", &cfg->en_cabc, },
+       };
+
+       prop_addr = of_get_address(dev->of_node, 0, NULL, NULL);
+       if (!prop_addr) {
+               pr_err("invalid IO resources\n");
+               return -EINVAL;
+       }
+       wled->ctrl_addr = be32_to_cpu(*prop_addr);
+
+       prop_addr = of_get_address(dev->of_node, 1, NULL, NULL);
+       if (!prop_addr) {
+               pr_err("invalid IO resources\n");
+               return -EINVAL;
+       }
+       wled->sink_addr = be32_to_cpu(*prop_addr);
+       rc = of_property_read_string(dev->of_node, "label", &wled->name);
+       if (rc < 0)
+               wled->name = dev->of_node->name;
+
+       *cfg = wled_config_defaults;
+       for (i = 0; i < ARRAY_SIZE(u32_opts); ++i) {
+               rc = of_property_read_u32(dev->of_node, u32_opts[i].name, &val);
+               if (rc == -EINVAL) {
+                       continue;
+               } else if (rc < 0) {
+                       pr_err("error reading '%s'\n", u32_opts[i].name);
+                       return rc;
+               }
+
+               c = UINT_MAX;
+               for (j = 0; c != val; j++) {
+                       c = qcom_wled_values(u32_opts[i].cfg, j);
+                       if (c == UINT_MAX) {
+                               pr_err("invalid value for '%s'\n",
+                                       u32_opts[i].name);
+                               return -EINVAL;
+                       }
+
+                       if (c == val)
+                               break;
+               }
+
+               pr_debug("'%s' = %u\n", u32_opts[i].name, c);
+               *u32_opts[i].val_ptr = j;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(bool_opts); ++i) {
+               if (of_property_read_bool(dev->of_node, bool_opts[i].name))
+                       *bool_opts[i].val_ptr = true;
+       }
+
+       return 0;
+}
+
+static const struct backlight_ops qcom_wled_ops = {
+       .update_status = qcom_wled_update_status,
+       .get_brightness = qcom_wled_get_brightness,
+};
+
+static int qcom_wled_probe(struct platform_device *pdev)
+{
+       struct backlight_properties props;
+       struct backlight_device *bl;
+       struct qcom_wled *wled;
+       struct regmap *regmap;
+       u32 val;
+       int rc;
+
+       regmap = dev_get_regmap(pdev->dev.parent, NULL);
+       if (!regmap) {
+               pr_err("Unable to get regmap\n");
+               return -EINVAL;
+       }
+
+       wled = devm_kzalloc(&pdev->dev, sizeof(*wled), GFP_KERNEL);
+       if (!wled)
+               return -ENOMEM;
+
+       wled->regmap = regmap;
+       wled->pdev = pdev;
+
+       rc = qcom_wled_configure(wled, &pdev->dev);
+       if (rc < 0) {
+               pr_err("wled configure failed rc:%d\n", rc);
+               return rc;
+       }
+
+       rc = qcom_wled_setup(wled);
+       if (rc < 0) {
+               pr_err("wled setup failed rc:%d\n", rc);
+               return rc;
+       }
+
+       val = QCOM_WLED_DEFAULT_BRIGHTNESS;
+       of_property_read_u32(pdev->dev.of_node, "default-brightness", &val);
+       wled->brightness = val;
+
+       platform_set_drvdata(pdev, wled);
+
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
+       props.brightness = val;
+       props.max_brightness = QCOM_WLED_MAX_BRIGHTNESS;
+       bl = devm_backlight_device_register(&pdev->dev, pdev->name,
+                                           &pdev->dev, wled,
+                                           &qcom_wled_ops, &props);
+       return PTR_ERR_OR_ZERO(bl);
+}
+
+static const struct of_device_id qcom_wled_match_table[] = {
+       { .compatible = "qcom,pm8998-spmi-wled",},
+       { },
+};
+
+static struct platform_driver qcom_wled_driver = {
+       .probe = qcom_wled_probe,
+       .driver = {
+               .name = "qcom-spmi-wled",
+               .of_match_table = qcom_wled_match_table,
+       },
+};
+
+module_platform_driver(qcom_wled_driver);
+
+MODULE_DESCRIPTION("Qualcomm SPMI PMIC WLED driver");
+MODULE_LICENSE("GPL v2");
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

Reply via email to