[PATCH] Added Support for STMicroelectronics 16 channels LED7708 LED Driver

From: Saurabh Rawat
Date: Thu Oct 06 2016 - 01:48:22 EST


---
.../devicetree/bindings/leds/leds-st.txt | 105 ++
KERNEL/Documentation/leds/leds-st7708.txt | 167 +++
KERNEL/drivers/leds/leds-st.c | 1210 ++++++++++++++++++++
KERNEL/include/linux/platform_data/leds-st.h | 170 +++
patches/defconfig | 3 +-
5 files changed, 1654 insertions(+), 1 deletion(-)
create mode 100644 KERNEL/Documentation/devicetree/bindings/leds/leds-st.txt
create mode 100644 KERNEL/Documentation/leds/leds-st7708.txt
create mode 100644 KERNEL/drivers/leds/leds-st.c
create mode 100644 KERNEL/include/linux/platform_data/leds-st.h

diff --git a/KERNEL/Documentation/devicetree/bindings/leds/leds-st.txt b/KERNEL/Documentation/devicetree/bindings/leds/leds-st.txt
new file mode 100644
index 0000000..dde53f9
--- /dev/null
+++ b/KERNEL/Documentation/devicetree/bindings/leds/leds-st.txt
@@ -0,0 +1,105 @@
+STMicroelectronics LED7708 Driver connected to BeagleboneBlack.This can be customized for any other
+hardware platform running linux depending on available free GPIOS
+
+Required properties:
+- compatible : should be : "st,st-leds".
+- sdo-gpio :contains a single GPIO specifier for the GPIO which is used for master to slave data OUT data.
+- sdi-gpio: contains a single GPIO specifier for the GPIO which is used for master to slave data IN data.
+- le-gpios: contains a single GPIO specifier for the GPIO which is used for Latch Enable data.
+- lren-gpios: contains a single GPIO specifier for the GPIO which is used for Lren data.This has to be High for Device to Operate.
+- sck-gpio: contains a single GPIO specifier for the GPIO which is used for the clock pin.
+- chanx :For controlling each LED channel Independently
+- chan-common: For controlling all the 16 channels in a single shot.
+
+Optional properties:
+ - None
+
+Example:
+
+st-leds {
+ compatible = "st,st-leds";
+ sdo-gpio = <&gpio1 16 1>;
+ sdi-gpio = <&gpio1 28 1>;
+ le-gpio = <&gpio3 21 1>;
+ lren-gpio = <&gpio1 19 1>;
+ sck-gpio = <&gpio1 17 1>;
+
+ chan1 {
+
+ chan-name = "led7708-chan1";
+ };
+
+ chan2 {
+
+ chan-name = "led7708-chan2";
+ };
+ chan3 {
+
+ chan-name = "led7708-chan3";
+ };
+
+ chan4 {
+
+ chan-name = "led7708-chan4";
+ };
+ chan5 {
+
+ chan-name = "led7708-chan5";
+ };
+
+ chan6 {
+
+ chan-name = "led7708-chan6";
+ };
+ chan7 {
+
+ chan-name = "led7708-chan7";
+ };
+
+ chan8 {
+
+ chan-name = "led7708-chan8";
+ };
+
+ chan9 {
+
+ chan-name = "led7708-chan9";
+ };
+
+ chan10 {
+
+ chan-name = "led7708-chan10";
+ };
+ chan11 {
+
+ chan-name = "led7708-chan11";
+ };
+
+ chan12 {
+
+ chan-name = "led7708-chan12";
+ };
+ chan13 {
+
+ chan-name = "led7708-chan13";
+ };
+
+ chan14 {
+
+ chan-name = "led7708-chan14";
+ };
+ chan15 {
+
+ chan-name = "led7708-chan15";
+ };
+
+ chan16 {
+
+ chan-name = "led7708-chan16";
+ };
+
+ chan-common {
+
+ chan-name = "led7708-chan-comm";
+ };
+};
diff --git a/KERNEL/Documentation/leds/leds-st7708.txt b/KERNEL/Documentation/leds/leds-st7708.txt
new file mode 100644
index 0000000..c1725ab
--- /dev/null
+++ b/KERNEL/Documentation/leds/leds-st7708.txt
@@ -0,0 +1,167 @@
+Kernel driver for led7708
+===========================
+
+* STMicroelectronics LED7708 Driver
+* Datasheet: www.st.com/resource/en/datasheet/led7708.pdf
+
+Authors: Saurabh Rawat
+Contact: Saurabh Rawat (saurabh.rawat-at-st.com)
+
+Description
+----------------------------------------------------------------------------------------------------------------
+LED7708 is a simple 16 channels LED driver hardware from STMicroelectronics. Leds can be controlled directly via
+the led class control interface.
+Each channel can be controlled independently in two modes - group-dimming mode or gray-scale dimming mode.
+In group dimming mode writing brightness to any one channel will configure the brightness of all the channels
+with the same brightness.This mode is enabled by default in the driver.
+In gray scale dimming mode each channel can be configured to have different brightness values and all the channels
+can be controlled in one shot.
+
+Follow these steps to configure the LED7708 channels in goup-dimming mode
+- Either select the channels from the sysfs by channel mask e.g ff00 -> echo ff00 > led_7708_select_channel for 9-16 channels
+ or
+- go to any channel's sysfs as described below, and write the brightness value to it , echo 122 > brightness .
+ All the seleted channels will get configured with this brightness value.
+
+Follow these steps to configure the channels of LED7708 in gray-scale mode
+- Select the mode - echo 1 > led_7708_dimming_mode
+- Select the data format - echo 3 or echo 2 or echo 1 > led_7708_data_fmt
+- Write brightness values to each channels , go to any channel sysfs and write brightness value to it , echo 213 > brightness
+- Enable sync - This will write the brightness for all the channels , echo 1 > led_7708_sync_brightness
+
+
+Scripts
+----------------------------------------------------------------------------------------------------------------
+----------------------------------------------------------------------------------------------------------------
+
+
+Follow these steps to use the direct commands.Custom scripts can be made using them with/without them using the debug interface - led_7708_dbg_rw
+echo "(0X,YY,ZZZZ)" > led_7708_dbg_rw
+0X --> Registers Identifier
+ W_BRT_DL 1
+ W_BRT_GL 2
+ W_CHSEL 4
+ R_CHSTA 7
+ W_DEVCFGx 8
+ R_DEVCFGx 11
+ W_GSLAT 13
+
+YY --> Number of Nibbles to be written
+ZZZZ --> Data to be written
+
+
+#script1 - Same brighntess on All channels (Group Dimming)
+$echo "(08,04,2130)" > led_7708_dbg_rw
+$echo "(08,04,8440)" > led_7708_dbg_rw
+$echo "(04,04,FFFF)" > led_7708_dbg_rw
+$echo "(08,04,2131)" > led_7708_dbg_rw
+$echo "(02,04,FFFF)" > led_7708_dbg_rw
+$echo "(02,04,0000)" > led_7708_dbg_rw
+
+#script2 - Different brighntess on All channels in one shot - 1X192 format (Gray Scale)
+$echo "(08,04,2530)" > led_7708_dbg_rw
+$echo "(08,04,C240)" > led_7708_dbg_rw
+$echo "(04,04,FFFF)" > led_7708_dbg_rw
+$echo "(08,04,2531)" > led_7708_dbg_rw
+$echo "(02,48,020111222333444555666777888999AAABBBCCCDDDEEEFFF)" > led_7708_dbg_rw
+$echo "(02,48,000000000000000000000000000000000000000000000000)" > led_7708_dbg_rw
+
+
+#script3 - Different brighntess on All channels in one shot - 1X256 format (Gray Scale)
+$echo "(08,04,2530)" > led_7708_dbg_rw
+$echo "(08,04,C640)" > led_7708_dbg_rw
+$echo "(08,04,2530)" > led_7708_dbg_rw
+$echo "(04,04,FFFF)" > led_7708_dbg_rw
+$echo "(08,04,2531)" > led_7708_dbg_rw
+$echo "(02,64,FFFFEEEEDDDDCCCCBBBBAAAA9900000000000000000000003333222211110000)" > led_7708_dbg_rw
+$echo "(02,64,0000000000000000000000000000000000000000000000000000000000000000)" > led_7708_dbg_rw
+
+
+#script4 - Different brighntess on All channels in one shot - 16X16 format (Gray Scale)
+$echo "(08,04,2500)" > led_7708_dbg_rw
+$echo "(08,04,8440)" > led_7708_dbg_rw
+$echo "(04,04,FFFF)" > led_7708_dbg_rw
+$echo "(08,04,2501)" > led_7708_dbg_rw
+$echo "(01,04,1111)" > led_7708_dbg_rw
+$echo "(01,04,2222)" > led_7708_dbg_rw
+$echo "(01,04,3333)" > led_7708_dbg_rw
+$echo "(01,04,4444)" > led_7708_dbg_rw
+$echo "(01,04,5555)" > led_7708_dbg_rw
+$echo "(01,04,6666)" > led_7708_dbg_rw
+$echo "(01,04,7777)" > led_7708_dbg_rw
+$echo "(01,04,8888)" > led_7708_dbg_rw
+$echo "(01,04,9999)" > led_7708_dbg_rw
+$echo "(01,04,AAAA)" > led_7708_dbg_rw
+$echo "(01,04,BBBB)" > led_7708_dbg_rw
+$echo "(01,04,CCCC)" > led_7708_dbg_rw
+$echo "(01,04,DDDD)" > led_7708_dbg_rw
+$echo "(01,04,EEEE)" > led_7708_dbg_rw
+$echo "(01,04,FFFF)" > led_7708_dbg_rw
+$echo "(02,04,AAAA)" > led_7708_dbg_rw
+
+#script5 - Independent Brightness Control (Group Dimming)
+e.g.1 => set 145 brightness value to 8 to 16 channels
+$lc
+$sdm
+$echo ff00 > led_7708_select_channel
+$l1
+$chb
+$echo 145 > brightness
+
+e.g.2=> set 250 brightness value to 1-4 ,7,8,9,10,14 and 16 channels
+$lc
+$sdm
+$echo a3cf > led_7708_select_channel
+$l1
+$chb
+$echo 250 > brightness
+
+
+#script6 - Gray-Scale Brightness Control for 1,7 and 15th channels
+$lc
+$sdm
+$echo 3 > led_7708_data_fmt
+$echo 1 > led_7708_dimming_mode
+$l1
+$chb
+$echo 213 > brightness
+$l7
+$chb
+$echo 123 > brightness
+$l15
+$chb
+$echo 213 > brightness
+$lc
+$echo 1 > led_7708_sync_brightness
+
+
+
+#lc,lx,sdm,chb are the aliases created as below in the ~/.bash_aliases :
+
+alias l<x>='cd /sys/class/leds/led7708-chan<x>'
+e.g.
+
+alias l1='cd /sys/class/leds/led7708-chan1'
+alias l2='cd /sys/class/leds/led7708-chan2'
+alias l3='cd /sys/class/leds/led7708-chan3'
+alias l4='cd /sys/class/leds/led7708-chan4'
+..
+and so on
+alias lc='cd /sys/class/leds/led7708-chan-comm'
+alias chb='sudo chmod 666 brightness'
+alias sdm='sudo chmod 666 led_*'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/KERNEL/drivers/leds/leds-st.c b/KERNEL/drivers/leds/leds-st.c
new file mode 100644
index 0000000..1dd9c5e
--- /dev/null
+++ b/KERNEL/drivers/leds/leds-st.c
@@ -0,0 +1,1210 @@
+/*
+ * Driver for STMicroelectronics LED7708 driver
+ *
+ * Copyright 2016 STMicroelectronics <saurabh.rawat@xxxxxx>
+ *
+ * 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.
+ */
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include "leds.h"
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/platform_data/leds-st.h>
+
+
+
+u16 channel_mask;
+char data_buff[Max_Packet_Length];
+struct device *dev_global;
+char data[Max_Packet_Length];
+/*default group dimming data for 16 bit resolution */
+char brightness_data_grp_dim_16[MAX_LENGTH] = "0000000000000000000000000000000000000000000000000000000000000000";
+/*default group dimming data for 12 bit resolution */
+char brightness_data_grp_dim_12[MAX_LENGTH] = "000000000000000000000000000000000000000000000000";
+struct led7708_chip *chip;
+static struct st7708_led *
+cdev_to_led7708_led(struct led_classdev *cdev)
+{
+return container_of(cdev, struct st7708_led, cdev);
+}
+
+/* Takes one character and returns it's hex value*/
+u16
+chartohex(char c)
+{
+int i;
+int d = 'a' - 'A';
+i = c - 'A';
+if (i > 0)
+ return ((i % d) % 6) + 10;
+ i = c - '0';
+ if (i > 0)
+ return i % 10;
+ return 0;
+}
+
+
+int
+inttochar(int x, char *res)
+{
+ if (x <= 0xFFFF) {
+ res[0] = TO_HEX(((x & 0xF000) >> 12));
+ res[1] = TO_HEX(((x & 0x0F00) >> 8));
+ res[2] = TO_HEX(((x & 0x00F0) >> 4));
+ res[3] = TO_HEX((x & 0x000F));
+ res[4] = '\0';
+ }
+ return 0;
+}
+
+void
+clock_out(struct led7708_platform_data *pdata)
+{
+ gpio_set_value(pdata->sck_gpio, 1);
+ msleep(MS50);
+ gpio_set_value(pdata->sck_gpio, 0);
+ msleep(MS50);
+
+
+}
+
+void
+led7708_create_brightness_data(struct led7708_platform_data *pdata,
+ u16 BrightnessData, char *brt_data_grp_dim)
+{
+
+ if (pdata->led_config->data_fmt == LED7708_1X256) {
+
+ inttochar(BrightnessData, &data[0]);
+ brt_data_grp_dim[0] = data[0];
+ brt_data_grp_dim[1] = data[1];
+ brt_data_grp_dim[2] = data[2];
+ brt_data_grp_dim[3] = data[3];
+ }
+ else if (pdata->led_config->data_fmt == LED7708_1X192) {
+ inttochar(BrightnessData, &data[0]);
+ brt_data_grp_dim[0] = data[0];
+ brt_data_grp_dim[1] = data[1];
+ brt_data_grp_dim[2] = data[2];
+ /* brt_data_grp_dim[3] = data[3]; */
+
+ }
+
+ return;
+
+}
+
+static int
+convert_to_hex(char x)
+{
+ int d;
+ if (x == 'F')
+ d = 15;
+ else if (x == 'E')
+ d = 14;
+ else if (x == 'D')
+ d = 13;
+ else if (x == 'C')
+ d = 12;
+ else if (x == 'B')
+ d = 11;
+ else if (x == 'A')
+ d = 10;
+ else
+ d = x;
+
+ return d;
+
+}
+
+static int
+write_led7708(struct led7708_platform_data *pdata, u8 pulse, char nbytes,
+ char *data_to_send)
+{
+
+ int pulses_before_lren = 0, i, j, flag, temp, mask;
+ u8 received_stream[Max_Packet_Length], mode = 2;
+
+
+ for (i = 0; i < nbytes; i++) {
+ temp = convert_to_hex(data_to_send[i]);
+ mask = 8;
+ received_stream[i] = 0;
+
+ for (j = 0; j <= 3; j++) {
+ flag = temp & mask;
+
+ if (flag) {
+
+ gpio_set_value(pdata->sdo_gpio, 1);
+ msleep(MS50);
+ gpio_set_value(pdata->sck_gpio, 1);
+ msleep(MS50);
+ gpio_set_value(pdata->sck_gpio, 0);
+ msleep(MS50);
+ if (gpio_get_value(pdata->sdi_gpio)) {
+ received_stream[i] = received_stream[i] | mask;
+ }
+ }
+ else {
+
+ gpio_set_value(pdata->sdo_gpio, 0);
+ msleep(MS50);
+ gpio_set_value(pdata->sck_gpio, 1);
+ msleep(MS50);
+ gpio_set_value(pdata->sck_gpio, 0);
+ msleep(MS50);
+ if (gpio_get_value(pdata->sdi_gpio)) {
+ received_stream[i] = received_stream[i] | mask;
+ }
+
+ }
+
+ pulses_before_lren++;
+
+ if (pulse != 0) {
+ if (pulses_before_lren == ((nbytes * 4) - pulse)) {
+ gpio_set_value(pdata->le_gpio, 1);
+ msleep(MS50);
+
+ }
+ if (pulses_before_lren == nbytes * 4) {
+ gpio_set_value(pdata->le_gpio, 0);
+ msleep(MS50);
+
+ }
+ }
+ mask = mask / 2;
+ }
+ }
+ if (pdata->led_config->mode == LED7708_R) {
+ for (i = 0; i < nbytes; i++) {
+ if ((received_stream[i] >= 0) && (received_stream[i] <= 9)) {
+ received_stream[i] = received_stream[i] + 48;
+ }
+ else if ((received_stream[i] >= 10) && (received_stream[i] <= 15)) {
+ received_stream[i] = received_stream[i] + 55;
+ }
+
+ }
+ dev_info(dev_global, "Continuous Brightness Reading = %s \n",
+ received_stream);
+ }
+ return 0;
+}
+
+
+static void
+led7708_led_brightness(struct st7708_led *led)
+{
+ struct led7708_chip *chip = led->chip;
+ struct led7708_platform_data *pdata = chip->pdata;
+
+ mutex_lock(&chip->lock);
+ if (led->chan_nr <= LED7708_MAX_CHANNELS) {
+ channel_mask = channel_mask | ((1 << (led->chan_nr)) & (0xFFFF));
+ }
+
+ /*Map the brightness to the LED7708 brightness value [0=255] - [0 - 65536] */
+ led->brightness =
+ led->brightness * (MAX_BRIGHTNESS) / (MAX_LED_SUBSYS_BRIGHTNESS);
+
+
+ /*Group Dimming mode Disabled by default */
+ if (!pdata->led_config->dimming_mode) {
+ inttochar(channel_mask, &data[0]);
+ write_led7708(chip->pdata, W_CHSEL, 4, data);
+ /*enable the device */
+ inttochar(0x2131, &data[0]);
+ write_led7708(chip->pdata, W_DEVCFGx, 4, data);
+ /*Write the common channel Brightness to the selected channels */
+ inttochar(led->brightness, &data[0]);
+ write_led7708(chip->pdata, W_BRT_GL, 4, data);
+ }
+ else {
+
+/*Select All channels
+ *inttochar(0xFFFF,&data[0]);
+ *write_led7708(chip->pdata,W_CHSEL,4,data);
+ *enable the device in GSME = 1 , group dimming mode
+ *inttochar(0x2501,&data[0]);
+ *write_led7708(chip->pdata,W_DEVCFGx,4,data);
+*/
+ if (pdata->led_config->data_fmt == LED7708_1X256) {
+ led7708_create_brightness_data(pdata, led->brightness,
+ &brightness_data_grp_dim_16[4 *
+ (15 -
+ led->
+ chan_nr)]);
+ dev_info(&chip->pd->dev,
+ "Current Brightness string = %s strlen = %x \n",
+ brightness_data_grp_dim_16,
+ strlen (brightness_data_grp_dim_16));
+ dev_info(&chip->pd->dev, "Channel_mask = %x \n", channel_mask);
+
+ }
+ else if (pdata->led_config->data_fmt == LED7708_1X192) {
+ led7708_create_brightness_data(pdata, led->brightness,
+ &brightness_data_grp_dim_12[3 *
+ (15 -
+ led->
+ chan_nr)]);
+ dev_info (&chip->pd->dev,
+ "Current Brightness string = %s strlen = %x \n",
+ brightness_data_grp_dim_12,
+ strlen (brightness_data_grp_dim_12));
+ dev_info (&chip->pd->dev, "Channel_mask = %x \n", channel_mask);
+
+ }
+ else if (pdata->led_config->data_fmt == LED7708_16X16) {
+ inttochar (led->brightness, &data[0]);
+ /* data Latch */
+ write_led7708 (chip->pdata, W_BRT_DL, 4, data);
+ }
+ else {
+ dev_info (&chip->pd->dev, "Incorrect Value for data format");
+
+ }
+ }
+
+ mutex_unlock (&chip->lock);
+}
+
+
+static char
+demodecodewriteCmd (struct led7708_platform_data *led_dat, char mode,
+ char buffer[Max_Packet_Length])
+{
+
+ char n_bytes = 0;
+ char le_pulses = 0;
+ char usb_received_bytes = strlen (buffer) - 1;
+ int i;
+
+ if ((buffer[0] == '(') && (buffer[3] == ',') && (buffer[6] == ',') &&
+ (buffer[usb_received_bytes - 1] == ')') && (buffer[1] >= '0') &&
+ (buffer[1] <= '9') && (buffer[2] >= '0') && (buffer[2] <= '9') &&
+ (buffer[4] >= '0') && (buffer[4] <= '9') && (buffer[5] >= '0')
+ && (buffer[5] <= '9')) {
+
+ le_pulses = (buffer[2] - 48) + 10 * (buffer[1] - 48);
+ n_bytes = (buffer[5] - 48) + 10 * (buffer[4] - 48);
+
+ if (n_bytes == (usb_received_bytes - 8)) {
+
+ /* Convert received data characters into ASCII value if nibble mode: */
+ if (mode != 0)
+ for (i = 7; i <= usb_received_bytes - 2; i++) {
+ if (buffer[i] >= 'A' && buffer[i] <= 'F')
+ buffer[i] = buffer[i] - 55;
+ else if (buffer[i] >= '0' && buffer[i] <= '9')
+ buffer[i] = buffer[i] - 48;
+ else
+ buffer[i] = 0;
+ }
+ write_led7708 (led_dat, le_pulses, n_bytes, &buffer[7]);
+
+ }
+ else {
+ return ERR;
+ }
+
+ }
+ else {
+ return ERR;
+ }
+
+
+ return NOERR;
+
+}
+
+
+static ssize_t
+led_7708_data_fmt_store (struct device *dev,
+ struct device_attribute *attr,
+ const char *buff, size_t count)
+{
+ /* struct st7708_led *led_dat = container_of(dev_get_drvdata (dev), struct st7708_led, cdev); */
+ struct led7708_chip *chip =
+ (container_of (dev_get_drvdata (dev), struct st7708_led, cdev))->chip;
+ struct led7708_platform_data *pdata = chip->pdata;
+ u16 data_fmt_reg_value = 0;
+ /*BDFS , BRLS
+ * 0 0 -> 0 => 16x16, 12-bit , (the 4 most significant bits are not used)
+ * 0 1 -> 1 => 16x16, 16-bit (default)
+ * 1 0 -> 2 => 192x1, 12-bit
+ * 1 1 -> 3 => 256x1, 16-bit
+ */
+
+ mutex_lock (&chip->lock);
+
+ if (!strncmp (buff, "0", 1)) {
+ pdata->led_config->data_fmt = LED7708_12X16;
+ data_fmt_reg_value = 0x8440;
+ dev_info (&chip->pd->dev,
+ " Current Brightness Data Format Set is = %d \n",
+ pdata->led_config->data_fmt);
+ }
+ else if (!strncmp (buff, "1", 1)) {
+ pdata->led_config->data_fmt = LED7708_16X16;
+ data_fmt_reg_value = 0x8440;
+ dev_info (&chip->pd->dev,
+ " Current Brightness Data Format Set is = %d \n",
+ pdata->led_config->data_fmt);
+ }
+ else if (!strncmp (buff, "2", 1)) {
+ pdata->led_config->data_fmt = LED7708_1X192;
+ data_fmt_reg_value = 0xC240;
+ dev_info (&chip->pd->dev,
+ " Current Brightness Data Format Set is = %d \n",
+ pdata->led_config->data_fmt);
+ }
+ else if (!strncmp (buff, "3", 1)) {
+ pdata->led_config->data_fmt = LED7708_1X256;
+ data_fmt_reg_value = 0xC640;
+ dev_info (&chip->pd->dev,
+ " Current Brightness Data Format Set is = %d \n",
+ pdata->led_config->data_fmt);
+ }
+ else
+ dev_info (&chip->pd->dev,
+ " Wrong value Set, [0-3] accepted only.Previous Value Retained = %d \n",
+ pdata->led_config->data_fmt);
+
+
+
+ if (pdata->led_config->data_fmt == LED7708_12X16) {
+ inttochar (0x2500, &data[0]);
+ dev_info (&chip->pd->dev, "16X16 : %s written \n", data);
+ write_led7708 (chip->pdata, W_DEVCFGx, 4, data);
+ }
+/*16 bit resolution*/
+ inttochar (data_fmt_reg_value, &data[0]);
+ dev_info (&chip->pd->dev, "data FMT : %s written \n", data);
+ write_led7708 (chip->pdata, W_DEVCFGx, 4, data);
+
+ mutex_unlock (&chip->lock);
+
+ return count;
+}
+
+static ssize_t
+led_7708_dimming_mode_store (struct device *dev,
+ struct device_attribute *attr,
+ const char *buff, size_t count)
+{
+ struct led7708_chip *chip =
+ (container_of (dev_get_drvdata (dev), struct st7708_led, cdev))->chip;
+ struct led7708_platform_data *pdata = chip->pdata;
+ /*GSME
+ * 0 GSME => Group Dimming mode Enabled
+ * 1 GSME => Group Dimming mode Disabled
+ */
+
+ mutex_lock (&chip->lock);
+
+ if (!strncmp (buff, "0", 1)) {
+ pdata->led_config->dimming_mode = LED7708_GREY_SCALE_MODE_GRP_DIM;
+ dev_info (&chip->pd->dev,
+ " Current Brightness Data Format Set is = %d \n",
+ pdata->led_config->dimming_mode);
+ inttochar (0x2130, &data[0]);
+ }
+ else if (!strncmp (buff, "1", 1)) {
+ pdata->led_config->dimming_mode = LED7708_GREY_SCALE_MODE_GRY_DIM;
+ dev_info (&chip->pd->dev,
+ " Current Brightness Data Format Set is = %d \n",
+ pdata->led_config->dimming_mode);
+ inttochar (0x2530, &data[0]);
+ }
+ else
+ dev_info (&chip->pd->dev,
+ " Wrong value Set, [0-1] accepted only.Previous Value Retained = %d \n",
+ pdata->led_config->dimming_mode);
+
+ dev_info (&chip->pd->dev, "Dimming mode : %s written \n", data);
+ write_led7708 (pdata, W_DEVCFGx, 4, data);
+ mutex_unlock (&chip->lock);
+
+
+ return count;
+}
+
+
+static ssize_t
+led_7708_sync_brightness_store (struct device *dev,
+ struct device_attribute *attr,
+ const char *buff, size_t count)
+{
+ struct led7708_chip *chip =
+ (container_of (dev_get_drvdata (dev), struct st7708_led, cdev))->chip;
+ struct led7708_platform_data *pdata = chip->pdata;
+
+ struct st7708_led *led =
+ container_of (dev_get_drvdata (dev), struct st7708_led, cdev);
+ mutex_lock (&chip->lock);
+
+ if (!strncmp (buff, "0", 1)) {
+ pdata->led_config->sync_brightness = 0;
+ }
+ else if (!strncmp (buff, "1", 1)) {
+ pdata->led_config->sync_brightness = 1;
+ }
+ else
+ dev_info (&chip->pd->dev,
+ " Wrong value Set, [0-1] accepted only.Previous Value Retained = %d \n",
+ pdata->led_config->sync_brightness);
+
+/* if Sync received then write both the channel mask and the Brightness string accumulated ar*/
+ if (pdata->led_config->sync_brightness) {
+
+ inttochar (channel_mask, &data[0]);
+ dev_info (&chip->pd->dev, "Channel Mask 0x: %s written \n", data);
+ write_led7708 (chip->pdata, W_CHSEL, 4, data);
+ dev_info (&chip->pd->dev, "Device Enabled 0x : %s written \n", data);
+
+ /*Device Enabled */
+ if (pdata->led_config->data_fmt == LED7708_16X16) {
+
+ inttochar (0x2501, &data[0]);
+ }
+ else {
+ inttochar (0x2531, &data[0]);
+ }
+
+ write_led7708 (chip->pdata, W_DEVCFGx, 4, data);
+
+ /*write the brightness data now
+ *dev_info(&chip->pd->dev, "Current Brightness Data value = %s \n",brightness_data_grp_dim);
+ * brightness_data_grp_dim[64] = '\n';
+ */
+ if (pdata->led_config->data_fmt == LED7708_1X256) {
+ dev_info (&chip->pd->dev,
+ "Final Brightness Data value = %s strlen = %d \n",
+ brightness_data_grp_dim_16,
+ strlen (brightness_data_grp_dim_16));
+ write_led7708 (chip->pdata, W_BRT_GL, 64,
+ brightness_data_grp_dim_16);
+
+ }
+ else if (pdata->led_config->data_fmt == LED7708_1X192) {
+ dev_info (&chip->pd->dev,
+ "Final Brightness Data value = %s strlen = %d \n",
+ brightness_data_grp_dim_12,
+ strlen (brightness_data_grp_dim_12));
+ write_led7708 (chip->pdata, W_BRT_GL, 48,
+ brightness_data_grp_dim_12);
+
+ }
+ else if (pdata->led_config->data_fmt == LED7708_16X16) {
+ inttochar (led->brightness, &data[0]);
+ /* Global Latch */
+ write_led7708 (chip->pdata, W_BRT_GL, 4, data);
+
+ }
+
+ }
+ else {
+ /*deselect all the channels */
+ write_led7708 (chip->pdata, W_CHSEL, 4, "0000");
+
+ }
+
+ mutex_unlock (&chip->lock);
+
+
+ return count;
+}
+
+
+static ssize_t
+led_7708_dbg_rw_store (struct device *dev,
+ struct device_attribute *attr,
+ const char *buff, size_t count)
+{
+ struct led7708_chip *chip =
+ (container_of (dev_get_drvdata (dev), struct st7708_led, cdev))->chip;
+ struct led7708_platform_data *pdata = chip->pdata;
+ mutex_lock (&chip->lock);
+
+ demodecodewriteCmd (pdata, 2, buff);
+
+ mutex_unlock (&chip->lock);
+
+
+ return count;
+}
+
+
+static ssize_t
+led_7708_enable_csrd_store (struct device *dev,
+ struct device_attribute *attr,
+ const char *buff, size_t count)
+{
+ struct led7708_chip *chip =
+ (container_of (dev_get_drvdata (dev), struct st7708_led, cdev))->chip;
+ struct led7708_platform_data *pdata = chip->pdata;
+ /*
+ * 0 W => Continuous Brightness Reading mode Enabled
+ * 1 R => Continuous Brightness Reding mode Disabled
+ */
+
+ mutex_lock (&chip->lock);
+ if (pdata->led_config->data_fmt == LED7708_1X192
+ || pdata->led_config->data_fmt == LED7708_1X256) {
+
+ if (!strncmp (buff, "0", 1)) {
+ pdata->led_config->mode = 0;
+ dev_info (&chip->pd->dev, " Current csrd mode is = %d \n",
+ pdata->led_config->mode);
+ }
+ else if (!strncmp (buff, "1", 1)) {
+ pdata->led_config->mode = 1;
+ dev_info (&chip->pd->dev, " Current csrd mode is = %d \n",
+ pdata->led_config->mode);
+ }
+ } else {
+
+ dev_err (&chip->pd->dev,
+ " CSRD not Available Only in 1X256 and 1X192 mode ,Current mode value remains = %d \n",
+ pdata->led_config->mode);
+
+ }
+
+ mutex_unlock (&chip->lock);
+
+
+ return count;
+}
+
+
+static ssize_t
+led_7708_select_channel_store (struct device *dev,
+ struct device_attribute *attr,
+ const char *buff, size_t count)
+{
+ int i, m = 1;
+ struct led7708_chip *chip =
+ (container_of (dev_get_drvdata (dev), struct st7708_led, cdev))->chip;
+
+ mutex_lock (&chip->lock);
+ channel_mask = 0;
+ for (i = sizeof (buff) - 1; i > -1; i--, m *= 16)
+ channel_mask += m * chartohex (buff[i]);
+
+ inttochar (channel_mask, &data[0]);
+ /*write select the channels */
+ write_led7708 (chip->pdata, W_CHSEL, 4, data);
+
+
+ mutex_unlock (&chip->lock);
+
+
+ return count;
+}
+
+
+static ssize_t
+led_7708_data_fmt_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct led7708_chip *chip =
+ (container_of (dev_get_drvdata (dev), struct st7708_led, cdev))->chip;
+ struct led7708_platform_data *pdata = chip->pdata;
+ char bufc[2] = "0";
+ dev_info (&chip->pd->dev, "current Dimming mode %d \n",
+ pdata->led_config->data_fmt);
+ switch (pdata->led_config->data_fmt) {
+ case 0:
+ strcpy (bufc, "0");
+ break;
+
+ case 1:
+ strcpy (bufc, "1");
+ break;
+
+ case 2:
+ strcpy (bufc, "2");
+ break;
+
+ case 3:
+ strcpy (bufc, "3");
+ break;
+
+ default:
+ break;
+
+ }
+ return sprintf (buf, "%s\n", bufc);
+
+}
+
+
+static ssize_t
+led_7708_dimming_mode_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct led7708_chip *chip =
+ (container_of (dev_get_drvdata (dev), struct st7708_led, cdev))->chip;
+ struct led7708_platform_data *pdata = chip->pdata;
+ char bufc[2] = "0";
+ dev_info (&chip->pd->dev, "current Dimming mode %d \n",
+ pdata->led_config->dimming_mode);
+ switch (pdata->led_config->dimming_mode) {
+ case 0:
+ strcpy (bufc, "0");
+ break;
+ case 1:
+ strcpy (bufc, "1");
+ break;
+ default:
+ break;
+
+ }
+ return sprintf (buf, "%s\n", bufc);
+
+}
+
+static ssize_t
+led_7708_sync_brightness_show (struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led7708_chip *chip =
+ (container_of (dev_get_drvdata (dev), struct st7708_led, cdev))->chip;
+ struct led7708_platform_data *pdata = chip->pdata;
+ char bufc[2] = "0";
+ dev_info (&chip->pd->dev, "current sync_brightness Enable %d \n",
+ pdata->led_config->sync_brightness);
+ switch (pdata->led_config->sync_brightness) {
+ case 0:
+ strcpy (bufc, "0");
+ break;
+
+ case 1:
+ strcpy (bufc, "1");
+ break;
+
+ default:
+ break;
+
+ }
+ return sprintf (buf, "%s\n", bufc);
+}
+
+static ssize_t
+led_7708_dbg_rw_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ /*struct led_classdev *led_cdev = dev_get_drvdata (dev);
+ * struct st7708_led *led_dat = container_of (led_cdev, struct st7708_led, cdev);
+ */
+ return sprintf (buf, "%d\n", 1);;
+}
+
+static ssize_t
+led_7708_enable_csrd_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct led7708_chip *chip =
+ (container_of (dev_get_drvdata (dev), struct st7708_led, cdev))->chip;
+ struct led7708_platform_data *pdata = chip->pdata;
+ char bufc[2] = "0";
+ dev_info (&chip->pd->dev, "current csrd mode %d \n",
+ pdata->led_config->mode);
+ switch (pdata->led_config->mode) {
+ case 0:
+ strcpy (bufc, "0");
+ break;
+
+ case 1:
+ strcpy (bufc, "1");
+ break;
+
+ default:
+ break;
+
+ }
+ return sprintf (buf, "%s\n", bufc);
+}
+
+
+static ssize_t
+led_7708_select_channel_show (struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led7708_chip *chip =
+ (container_of (dev_get_drvdata (dev), struct st7708_led, cdev))->chip;
+ struct led7708_platform_data *pdata = chip->pdata;
+
+ return sprintf (buf, "Channel Select Mask %x\n", channel_mask);
+}
+
+/*common device attribute for controlling all the 16 channels*/
+static DEVICE_ATTR (led_7708_dimming_mode, 0644, led_7708_dimming_mode_show,
+ led_7708_dimming_mode_store);
+static DEVICE_ATTR (led_7708_data_fmt, 0644, led_7708_data_fmt_show,
+ led_7708_data_fmt_store);
+static DEVICE_ATTR (led_7708_sync_brightness, 0644,
+ led_7708_sync_brightness_show,
+ led_7708_sync_brightness_store);
+static DEVICE_ATTR (led_7708_dbg_rw, 0644, led_7708_dbg_rw_show,
+ led_7708_dbg_rw_store);
+static DEVICE_ATTR (led_7708_enable_csrd, 0644, led_7708_enable_csrd_show,
+ led_7708_enable_csrd_store);
+static DEVICE_ATTR (led_7708_select_channel, 0644,
+ led_7708_select_channel_show,
+ led_7708_select_channel_store);
+
+
+static struct attribute *st7708_led_common_attrs[] = {
+ &dev_attr_led_7708_dimming_mode.attr,
+ &dev_attr_led_7708_data_fmt.attr,
+ &dev_attr_led_7708_sync_brightness.attr,
+ &dev_attr_led_7708_dbg_rw.attr,
+ &dev_attr_led_7708_enable_csrd.attr,
+ &dev_attr_led_7708_select_channel.attr,
+ NULL
+};
+
+ATTRIBUTE_GROUPS (st7708_led_common);
+
+
+/* Chip specific configurations */
+static struct led7708_device_config led_cfg = {
+
+/*Extra Channel is for Common Channel Configuration */
+ .max_channel = LED7708_MAX_CHANNELS + 1,
+ .brightness_fn = led7708_led_brightness,
+};
+
+
+static struct led7708_platform_data *
+led7708_of_populate_pdata (struct device *dev, struct device_node *np)
+{
+ struct device_node *child;
+ struct led7708_platform_data *pdata;
+ struct led7708_config *cfg;
+ int ret;
+ int num_channels;
+ int i = 0;
+
+ pdata = devm_kzalloc (dev, sizeof (*pdata), GFP_KERNEL);
+ if (!pdata)
+ return ERR_PTR (-ENOMEM);
+
+ num_channels = of_get_child_count (np);
+ if (num_channels == 0) {
+ dev_err (dev, "no LED channels\n");
+ return ERR_PTR (-EINVAL);
+ }
+
+ cfg = devm_kzalloc (dev, sizeof (*cfg) * num_channels, GFP_KERNEL);
+ if (!cfg)
+ return ERR_PTR (-ENOMEM);
+
+ pdata->led_config = &cfg[0];
+ pdata->num_channels = num_channels;
+
+ for_each_child_of_node (np, child) {
+ cfg[i].chan_nr = i;
+
+ of_property_read_string (child, "chan-name", &cfg[i].name);
+ cfg[i].default_trigger =
+ of_get_property (child, "linux,default-trigger", NULL);
+
+ i++;
+ }
+
+ of_property_read_string (np, "label", &pdata->label);
+
+ /*Parse all the GPIOs from the Device Tree */
+ ret = of_get_named_gpio (np, "sdo-gpio", 0);
+ if (ret > 0)
+ pdata->sdo_gpio = ret;
+ else
+ goto gpio_error;
+
+ ret = of_get_named_gpio (np, "sdi-gpio", 0);
+ if (ret > 0)
+ pdata->sdi_gpio = ret;
+ else
+ goto gpio_error;
+
+
+ ret = of_get_named_gpio (np, "le-gpio", 0);
+ if (ret > 0)
+ pdata->le_gpio = ret;
+ else
+ goto gpio_error;
+
+ ret = of_get_named_gpio (np, "lren-gpio", 0);
+ if (ret > 0)
+ pdata->lren_gpio = ret;
+ else
+ goto gpio_error;
+
+
+ ret = of_get_named_gpio (np, "sck-gpio", 0);
+ if (ret > 0)
+ pdata->sck_gpio = ret;
+ else
+ goto gpio_error;
+
+ return pdata;
+
+gpio_error:
+ return ret;
+
+}
+
+static int
+led7708_init_device (struct led7708_chip *chip)
+{
+ struct led7708_platform_data *pdata;
+ struct led7708_device_config *cfg;
+ struct device *dev = &chip->pd->dev;
+ int ret = 0;
+
+ pdata = chip->pdata;
+ cfg = chip->cfg;
+
+ if (!pdata || !cfg)
+ return -EINVAL;
+
+
+ if (gpio_is_valid (pdata->sdi_gpio)) {
+ ret =
+ devm_gpio_request_one (dev, pdata->sdi_gpio, GPIOF_DIR_IN,
+ "sdi-gpio");
+ if (ret < 0) {
+ dev_err (dev, "could not acquire sdi_gpio (err=%d)\n", ret);
+ goto err;
+ }
+
+ }
+
+ if (gpio_is_valid (pdata->sck_gpio)) {
+ ret =
+ devm_gpio_request_one (dev, pdata->sck_gpio, GPIOF_DIR_OUT,
+ "sck-gpio");
+ if (ret < 0) {
+ dev_err (dev, "could not acquire sck_gpio (err=%d)\n", ret);
+ goto err;
+ }
+
+ }
+
+
+ if (gpio_is_valid (pdata->lren_gpio)) {
+ ret =
+ devm_gpio_request_one (dev, pdata->lren_gpio, GPIOF_DIR_OUT,
+ "lren-gpio");
+ if (ret < 0) {
+ dev_err (dev, "could not acquire lren_gpio (err=%d)\n", ret);
+ goto err;
+ }
+
+ }
+
+ if (gpio_is_valid (pdata->le_gpio)) {
+ ret =
+ devm_gpio_request_one (dev, pdata->le_gpio, GPIOF_DIR_OUT, "le-gpio");
+ if (ret < 0) {
+ dev_err (dev, "could not acquire le_gpio (err=%d)\n", ret);
+ goto err;
+ }
+
+ }
+
+
+ if (gpio_is_valid (pdata->sdo_gpio)) {
+ ret =
+ devm_gpio_request_one (dev, pdata->sdo_gpio, GPIOF_DIR_OUT,
+ "sdo_gpio");
+ if (ret < 0) {
+ dev_err (dev, "could not acquire sdo_gpio (err=%d)\n", ret);
+ goto err;
+ }
+
+ }
+
+ gpio_set_value(pdata->lren_gpio, 0);
+ msleep(MS50);
+ gpio_set_value(pdata->lren_gpio, 1);
+ msleep(MS50);
+
+
+ return 0;
+
+err:
+ return ret;
+}
+
+
+static void
+led7708_set_brightness (struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct st7708_led *led = cdev_to_led7708_led (cdev);
+ struct led7708_device_config *cfg = led->chip->cfg;
+ led->brightness = (u8) brightness;
+ return cfg->brightness_fn(led);
+}
+
+static int
+led7708_init_led (struct st7708_led *led, struct led7708_chip *chip, int chan)
+{
+ struct led7708_platform_data *pdata = chip->pdata;
+ struct led7708_device_config *cfg = chip->cfg;
+ struct device *dev = &chip->pd->dev;
+ char name[32];
+ int ret;
+ int max_channel = cfg->max_channel;
+
+
+
+ if (chan >= max_channel) {
+ dev_err (dev, "invalid channel: %d / %d\n", chan, max_channel);
+ return -EINVAL;
+ }
+
+ led->chan_nr = pdata->led_config[chan].chan_nr;
+ led->cdev.default_trigger = pdata->led_config[chan].default_trigger;
+
+ if (led->chan_nr >= max_channel) {
+ dev_err (dev, "Use channel numbers between 0 and %d\n",
+ max_channel - 1);
+ return -EINVAL;
+ }
+
+ led->cdev.brightness_set = led7708_set_brightness;
+
+ if (pdata->led_config[chan].name) {
+ led->cdev.name = pdata->led_config[chan].name;
+ }
+ else {
+ snprintf (name, sizeof (name), "%s:channel%d",
+ pdata->label ? : chip->pd->name, chan);
+ led->cdev.name = name;
+ }
+
+ if (!strcmp (led->cdev.name, "led7708-chan-comm")) {
+ led->cdev.groups = st7708_led_common_groups;
+
+
+ }
+
+ ret = led_classdev_register (dev, &led->cdev);
+ if (ret) {
+ dev_err (dev, "led register err: %d\n", ret);
+ return ret;
+ }
+ else {
+
+
+ }
+
+ return 0;
+}
+
+static void
+led7708_unregister_leds (struct st7708_led *led, struct led7708_chip *chip)
+{
+ int i;
+ struct st7708_led *each;
+
+ for (i = 0; i < chip->num_leds; i++) {
+ each = led + i;
+ led_classdev_unregister (&each->cdev);
+ }
+}
+
+static int
+led7708_register_leds (struct st7708_led *led, struct led7708_chip *chip)
+{
+ struct led7708_platform_data *pdata = chip->pdata;
+ struct led7708_device_config *cfg = chip->cfg;
+ int num_channels = pdata->num_channels;
+ struct st7708_led *each;
+ int ret;
+ int i;
+
+ if (!cfg->brightness_fn) {
+ dev_err (&chip->pd->dev, "empty brightness configuration\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_channels; i++) {
+
+ each = led + i;
+ ret = led7708_init_led(each, chip, i);
+ if (ret) {
+ goto err_init_led;
+ }
+ else{
+
+ }
+
+ chip->num_leds++;
+ each->chip = chip;
+
+ }
+
+
+ return 0;
+
+err_init_led:
+ led7708_unregister_leds(led, chip);
+ return ret;
+}
+
+void
+led7708_deinit_device (struct led7708_chip *chip)
+{
+ struct led7708_platform_data *pdata = chip->pdata;
+ if (gpio_is_valid(pdata->lren_gpio))
+ /*Disables the device */
+ gpio_set_value(pdata->lren_gpio, 0);
+
+}
+
+static void
+st_led_7708_init (struct led7708_chip *chip)
+{
+ struct led7708_platform_data *pdata = chip->pdata;
+
+ mutex_lock(&chip->lock);
+ /*defautl configure in the 16 Bit resolution 1X256 bit data format mode , enable gray scale mode */
+ write_led7708(pdata, W_DEVCFGx, 4, "2530");
+ write_led7708(pdata, W_DEVCFGx, 4, "C640");
+ msleep(MS50);
+
+ mutex_unlock(&chip->lock);
+
+}
+
+
+static int
+st_led_7708_probe (struct platform_device *pdev)
+{
+ int ret;
+ struct led7708_chip *chip;
+ struct st7708_led *led;
+ struct led7708_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ struct device_node *np = pdev->dev.of_node;
+
+ if (!pdata) {
+ if (np) {
+ pdata = led7708_of_populate_pdata(&pdev->dev, np);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ }
+ else {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -EINVAL;
+ }
+ }
+
+ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ led = devm_kzalloc(&pdev->dev,
+ sizeof(*led) * pdata->num_channels, GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
+
+ chip->pd = pdev;
+ chip->pdata = pdata;
+ chip->cfg = &led_cfg;
+
+
+ mutex_init(&chip->lock);
+
+ platform_set_drvdata(pdev, led);
+
+
+ ret = led7708_init_device(chip);
+ if (ret)
+ goto err_init;
+
+ ret = led7708_register_leds(led, chip);
+
+ if (ret)
+ goto err_register_leds;
+
+ if (ret) {
+ dev_err(&pdev->dev, "registering sysfs failed\n");
+ goto err_register_sysfs;
+ }
+ else {
+
+ }
+
+ /*Initialize the led7708 with gsme =1 , 16 bit resolution and all channels de-selected */
+ st_led_7708_init(chip);
+
+ dev_global = &chip->pd->dev;
+
+
+ return 0;
+
+err_register_sysfs:
+ led7708_unregister_leds(led, chip);
+err_register_leds:
+ led7708_deinit_device(chip);
+err_init:
+ return ret;
+}
+
+
+
+static int
+st_led_7708_remove (struct platform_device *pdev)
+{
+ struct st7708_led *led = platform_get_drvdata(pdev);
+ struct led7708_chip *chip = led->chip;
+ chip->pdata->led_config->sync_brightness = 0;
+
+ led7708_unregister_leds(led, chip);
+ led7708_deinit_device(chip);
+
+ dev_info(&pdev->dev, "ST LED7708 Driver removed Successfully \n");
+
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id of_st_leds_match[] = {
+{.compatible = "st,st-leds",},
+{},
+};
+
+MODULE_DEVICE_TABLE(of, of_st_leds_match);
+#endif
+
+static struct platform_driver st_led_7708_driver = {
+.driver = {
+ .name = "leds-st",
+ .of_match_table = of_match_ptr(of_st_leds_match),
+ },
+.probe = st_led_7708_probe,
+.remove = st_led_7708_remove,
+};
+
+module_platform_driver(st_led_7708_driver);
+
+MODULE_AUTHOR("Saurabh Rawat <saurabh.rawat@xxxxxx>");
+MODULE_DESCRIPTION("ST LED7708 Driver");
+MODULE_LICENSE("GPL");
diff --git a/KERNEL/include/linux/platform_data/leds-st.h b/KERNEL/include/linux/platform_data/leds-st.h
new file mode 100644
index 0000000..4a5a31f
--- /dev/null
+++ b/KERNEL/include/linux/platform_data/leds-st.h
@@ -0,0 +1,170 @@
+/*
+ * Platform data structure for ST LED7708 driver
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __LEDS_7708_ST_H
+#define __LEDS_7708_ST_H
+
+#define W_BRT_DL 1
+#define W_BRT_GL 2
+#define W_CHSEL 4
+#define R_CHSTA 7
+#define W_DEVCFGx 8
+#define R_DEVCFGx 11
+#define W_GSLAT 13
+
+/* DEVCFG0 register bits */
+#define DEVCFG0_DEN (1 << 0) /* Device Enable */
+#define DEVCFG0_EDMI (1 << 1) /* Error Detection Mode Indctr */
+#define DEVCFG0_OVFW (1 << 2) /* Regulation DAC Overflow */
+#define DEVCFG0_OTAF (1 << 3) /* Over-Temperature Alert Flag */
+#define DEVCFG0_OCAD (1 << 4) /* Open Channels Auto Disconnect*/
+#define DEVCFG0_SCAD (1 << 5) /* Shorted Channels Auto Disconn*/
+#define DEVCFG0_CFP (1 << 6) /* Critical Fault Protection */
+#define DEVCFG0_RWAS (1 << 7) /* Regulation Wndw Amplitude Sel*/
+#define DEVCFG0_DTS_DIS (0 << 8) /* Regulation Wndw Amplitude Sel*/
+#define DEVCFG0_DTS_3_4 (1 << 8) /* Regulation Wndw Amplitude Sel*/
+#define DEVCFG0_DTS_6_8 (2 << 8) /* Regulation Wndw Amplitude Sel*/
+#define DEVCFG0_DTS_8_4 (3 << 8) /* Regulation Wndw Amplitude Sel*/
+#define DEVCFG0_GSME (1 << 10) /* Gray-Scale Mode Enable */
+#define DEVCFG0_CRS (1 << 11) /* Current Range Selector */
+#define DEVCFG0_OVRS (1 << 12) /* Output Volt Regulation Stat */
+#define DEVCFG0_OVRE (1 << 13) /* Output Volt Regulation Enbl */
+#define DEVCFG0_SDMS (1 << 14) /* Slave Device Mode Selection */
+#define DEVCFG0_DEST_CFG0 (0 << 15) /* FIFO loaded into DEVCFG0 */
+
+/* DEVCFG1 register bits */
+#define DEVCFG1_ADJ_SET(_val) (((_val) & 0x3f) << 0)
+/* Current Gain Adjust */
+#define DEVCFG1_CGRS (1 << 6) /* Current Gain Range Selector */
+#define DEVCFG1_LAT16 (1 << 7) /* Bits #16 of dimming latency */
+#define DEVCFG1_LAT17 (1 << 8) /* Bits #17 of dimming latency */
+#define DEVCFG1_BDFS (1 << 9) /* Brightness Data Format Sel */
+#define DEVCFG1_BRLS (1 << 10) /* Brightness Registers Len Sel */
+#define DEVCFG1_DTIN (1 << 11) /* Dimming Timing Inversion sel */
+#define DEVCFG1_DASS (1 << 12) /* Data Synchronization Selector*/
+#define DEVCFG1_DSYS (1 << 13) /* Dimming Synch Selector */
+#define DEVCFG1_CSRD (1 << 14) /* Continuous Status Reading */
+#define DEVCFG1_DEST_CFG1 (1 << 15) /* FIFO loaded into DEVCFG1 */
+
+#define TO_HEX(i) (i <= 9 ? '0' + i : 'A' - 10 + i)
+
+#define LED7708_MAX_CHANNELS 16
+#define MAX_BRIGHTNESS 0xffff
+#define MAX_LED_SUBSYS_BRIGHTNESS 0xff
+#define MAX_LENGTH 100
+#define Max_Packet_Length 100
+#define ERR 1
+#define NOERR 0
+
+
+#define MS50 0
+#define MS100 0
+
+enum st_led_modes {
+LED7708_W = 0,
+LED7708_R = 1,
+};
+
+enum st_led_datafmt {
+LED7708_12X16 = 0,
+LED7708_16X16 = 1,
+LED7708_1X192 = 2,
+LED7708_1X256 = 3,
+};
+
+enum st_led_gsme_mode {
+LED7708_GREY_SCALE_MODE_GRP_DIM = 0,
+LED7708_GREY_SCALE_MODE_GRY_DIM = 1,
+};
+
+
+struct st_led {
+const char *name;
+const char *default_trigger;
+unsigned le;
+unsigned lren;
+unsigned sdo;
+unsigned sck;
+unsigned sdi;
+};
+
+struct st_led_platform_data {
+int num_leds;
+struct st_led *leds;
+};
+
+/*
+ * struct led7708_chip
+ * @pdata : Platform specific data
+ * @lock : Lock for user-space interface
+ * @num_leds : Number of registered LEDs
+ * @cfg : Device specific configuration data
+ */
+struct led7708_chip {
+struct platform_device *pd;
+struct led7708_platform_data *pdata;
+struct mutex lock; /* lock for user-space interface */
+int num_leds;
+struct led7708_device_config *cfg;
+};
+
+
+/*
+ * struct st7708_led
+ * @chan_nr : Channel number
+ * @cdev : LED class device
+ * @brightness : Brightness value
+ * @chip : The led7708 chip data
+ */
+struct st7708_led {
+int chan_nr;
+struct led_classdev cdev;
+u16 brightness;
+struct led7708_chip *chip;
+};
+
+ /*
+ * struct led7708_platform_data
+ * @led_config : Configurable led class device
+ * @num_channels : Number of LED channels
+ * @label : Used for naming LEDs
+ */
+struct led7708_platform_data {
+
+ /* LED channel configuration */
+struct led7708_config *led_config;
+u8 num_channels;
+const char *label;
+int sdo_gpio;
+int sdi_gpio;
+int sck_gpio;
+int lren_gpio;
+int le_gpio;
+
+};
+
+struct led7708_config {
+const char *name;
+const char *default_trigger;
+u8 chan_nr;
+u8 dimming_mode;
+u8 data_fmt;
+u8 sync_brightness;
+u8 mode;
+};
+
+struct led7708_device_config {
+const int max_channel;
+
+/* access brightness register */
+void (*brightness_fn)(struct st7708_led *led);
+
+};
+
+
+#endif /* __LEDS_7708_ST_H */
diff --git a/patches/defconfig b/patches/defconfig
index 4c7f16f..856c245 100644
--- a/patches/defconfig
+++ b/patches/defconfig
@@ -1,6 +1,6 @@
#
# Automatically generated file; DO NOT EDIT.
-# Linux/arm 4.7.0 Kernel Configuration
+# Linux/arm 4.7.6 Kernel Configuration
#
CONFIG_ARM=y
CONFIG_ARM_HAS_SG_CHAIN=y
@@ -4693,6 +4693,7 @@ CONFIG_LEDS_PCA9532=m
CONFIG_LEDS_PCA9532_GPIO=y
CONFIG_LEDS_GPIO=m
CONFIG_LEDS_LP3944=m
+CONFIG_LEDS_STLED7708=y
CONFIG_LEDS_LP55XX_COMMON=m
CONFIG_LEDS_LP5521=m
CONFIG_LEDS_LP5523=m
--
2.1.4