Devicetree
 help / color / mirror / Atom feed
* [PATCH linux v1 4/4] arm: dts: Add dt-binding to support seven segment display on zaius
From: Jaghathiswari Rankappagounder Natarajan @ 2016-12-14  7:55 UTC (permalink / raw)
  To: openbmc, robh+dt, mark.rutland, linux, arnd, gregkh
  Cc: Jaghathiswari Rankappagounder Natarajan, devicetree, linux-kernel,
	linux-arm-kernel, joel
In-Reply-To: <1481702104-8617-1-git-send-email-jaghu@google.com>

Add clock, data and clear signal GPIO lines to control seven segment display on
zaius platform.

Signed-off-by: Jaghathiswari Rankappagounder Natarajan <jaghu@google.com>
---
 arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts b/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts
index 8ef4ece..ccb8147 100644
--- a/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts
@@ -43,6 +43,14 @@
 			gpios = <&gpio ASPEED_GPIO(H, 7) GPIO_ACTIVE_LOW>;
 		};
 	};
+
+	seven-seg-disp {
+		compatible = "seven-seg-gpio-dev";
+		refresh-interval-ms = "1000";
+		clock-gpios = <&gpio ASPEED_GPIO(J, 0) GPIO_ACTIVE_HIGH>;
+		data-gpios = <&gpio ASPEED_GPIO(J, 2) GPIO_ACTIVE_HIGH>;
+		clear-gpios = <&gpio ASPEED_GPIO(J, 1) GPIO_ACTIVE_HIGH>;
+	};
 };

 &fmc {
--
2.8.0.rc3.226.g39d4020

^ permalink raw reply related

* [PATCH linux v1 3/4] drivers: misc: Platform driver for seven segment display support
From: Jaghathiswari Rankappagounder Natarajan @ 2016-12-14  7:55 UTC (permalink / raw)
  To: openbmc, robh+dt, mark.rutland, linux, arnd, gregkh
  Cc: Jaghathiswari Rankappagounder Natarajan, devicetree, linux-kernel,
	linux-arm-kernel, joel
In-Reply-To: <1481702104-8617-1-git-send-email-jaghu@google.com>

Platform device driver which provides an API for displaying on two
7-segment displays, and implements the required bit-banging.
The hardware assumed is 74HC164 wired to two 7-segment displays.

Signed-off-by: Jaghathiswari Rankappagounder Natarajan <jaghu@google.com>
---
 drivers/misc/Kconfig          |   8 ++
 drivers/misc/Makefile         |   1 +
 drivers/misc/seven_seg_gpio.c | 206 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 215 insertions(+)
 create mode 100644 drivers/misc/seven_seg_gpio.c

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index a21aec1..6508108 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -812,6 +812,14 @@ config PANEL_BOOT_MESSAGE
 	  An empty message will only clear the display at driver init time. Any other
 	  printf()-formatted message is valid with newline and escape codes.

+config SEVEN_SEGMENT_GPIO
+	tristate "Platform driver to update seven segment display"
+	depends on SEVEN_SEGMENT_DISPLAY
+	help
+	  Platform device driver which provides an API for displaying on two
+	  7-segment displays, and implements the required bit-banging.
+	  The hardware assumed is 74HC164 wired to two 7-segment displays.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index c2defbd..d9c0d20 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -58,3 +58,4 @@ obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
 obj-$(CONFIG_CXL_BASE)		+= cxl/
 obj-$(CONFIG_SEVEN_SEGMENT_DISPLAY)	+= seven_seg_disp.o
 obj-$(CONFIG_PANEL)             += panel.o
+obj-$(CONFIG_SEVEN_SEGMENT_GPIO)	+= seven_seg_gpio.o
diff --git a/drivers/misc/seven_seg_gpio.c b/drivers/misc/seven_seg_gpio.c
new file mode 100644
index 0000000..3dcb903
--- /dev/null
+++ b/drivers/misc/seven_seg_gpio.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2016 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or later as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/sizes.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/of_platform.h>
+#include <linux/gpio/consumer.h>
+
+#include "seven_seg_disp.h"
+
+#define DELAY_INTVL_US 1
+
+#define CLOCK_GPIO_NAME "clock"
+#define DATA_GPIO_NAME "data"
+#define CLEAR_GPIO_NAME "clear"
+
+struct seven_seg_gpio_info {
+	u16 curr_disp_value;
+	u16 refresh_interval;
+	struct timer_list update_timer;
+	struct gpio_desc *clock_gpio;
+	struct gpio_desc *data_gpio;
+	struct gpio_desc *clear_gpio;
+};
+
+static void update_seven_seg_gpio_data(struct device *dev, u16 data)
+{
+	struct platform_device *pdev;
+	struct seven_seg_gpio_info *gpio_info;
+
+	pdev = container_of(dev, struct platform_device, dev);
+	if (pdev == NULL) {
+		pr_err("invalid NULL platform_device\n");
+		return;
+	}
+
+	gpio_info = platform_get_drvdata(pdev);
+	if (gpio_info == NULL) {
+		pr_err("invalid NULL gpio_info\n");
+		return;
+	}
+
+	gpio_info->curr_disp_value = data;
+}
+
+static void clear_seven_seg_gpio_data(struct device *dev, u16 data)
+{
+	struct platform_device *pdev;
+	struct seven_seg_gpio_info *gpio_info;
+
+	pdev = container_of(dev, struct platform_device, dev);
+	if (pdev == NULL) {
+		pr_err("invalid NULL platform_device\n");
+		return;
+	}
+
+	gpio_info = platform_get_drvdata(pdev);
+	if (gpio_info == NULL) {
+		pr_err("invalid NULL gpio_info\n");
+		return;
+	}
+
+	gpio_info->curr_disp_value = 0;
+}
+
+static void send_seven_seg_gpio_data(u16 disp_data,
+		struct seven_seg_gpio_info *gpio_info)
+{
+	int i;
+
+	gpiod_set_value(gpio_info->clear_gpio, 0);
+	udelay(DELAY_INTVL_US);
+	gpiod_set_value(gpio_info->clear_gpio, 1);
+	udelay(DELAY_INTVL_US);
+
+	for (i = 0; i < 16; i++) {
+		if (disp_data & 0x01)
+			gpiod_set_value(gpio_info->data_gpio, 1);
+		else
+			gpiod_set_value(gpio_info->data_gpio, 0);
+
+		udelay(DELAY_INTVL_US);
+
+		gpiod_set_value(gpio_info->clock_gpio, 0);
+		udelay(DELAY_INTVL_US);
+		gpiod_set_value(gpio_info->clock_gpio, 1);
+		udelay(DELAY_INTVL_US);
+
+		disp_data >>= 1;
+	}
+}
+
+static void disp_refresh_timer_handler(unsigned long data)
+{
+	u16 disp_data;
+	struct seven_seg_gpio_info *gpio_info =
+		(struct seven_seg_gpio_info *)data;
+	disp_data = gpio_info->curr_disp_value;
+
+	send_seven_seg_gpio_data(disp_data, gpio_info);
+	mod_timer(&gpio_info->update_timer,
+		jiffies + msecs_to_jiffies(gpio_info->refresh_interval));
+}
+
+static const struct of_device_id of_seven_seg_gpio_match[] = {
+		{ .compatible = "seven-seg-gpio-dev" },
+		{},
+};
+
+MODULE_DEVICE_TABLE(of, of_seven_seg_gpio_match);
+
+static int seven_seg_gpio_probe(struct platform_device *pdev)
+{
+	u16 interval;
+	int result;
+	struct seven_seg_gpio_info *gpio_info;
+	struct device *dev = &pdev->dev;
+	struct seven_seg_disp_dev *disp_dev;
+
+	gpio_info = devm_kzalloc(dev,
+			sizeof(struct seven_seg_gpio_info),
+			GFP_KERNEL);
+	if (gpio_info == NULL)
+		return -ENOMEM;
+
+	/* Requesting the clock gpio */
+	gpio_info->clock_gpio = devm_gpiod_get(dev, CLOCK_GPIO_NAME,
+		GPIOD_OUT_HIGH);
+	if (IS_ERR(gpio_info->clock_gpio))
+		return PTR_ERR(gpio_info->clock_gpio);
+
+	/* Requesting the data gpio */
+	gpio_info->data_gpio = devm_gpiod_get(dev, DATA_GPIO_NAME,
+		GPIOD_OUT_HIGH);
+	if (IS_ERR(gpio_info->data_gpio))
+		return PTR_ERR(gpio_info->data_gpio);
+
+	/* Requesting the clear gpio */
+	gpio_info->clear_gpio = devm_gpiod_get(dev, CLEAR_GPIO_NAME,
+		GPIOD_OUT_HIGH);
+	if (IS_ERR(gpio_info->clear_gpio))
+		return PTR_ERR(gpio_info->clear_gpio);
+
+	result = of_property_read_u16(pdev->dev.of_node,
+		"refresh-interval-ms", &interval);
+	gpio_info->refresh_interval = result ? DEFAULT_REFRESH_INTERVAL_MS :
+		interval;
+
+	/* Start timer to update seven segment display every second */
+	setup_timer(&gpio_info->update_timer, disp_refresh_timer_handler,
+			(unsigned long)gpio_info);
+	result = mod_timer(&gpio_info->update_timer,
+			jiffies +
+			msecs_to_jiffies(gpio_info->refresh_interval));
+	if (result)
+		return result;
+
+	gpio_info->curr_disp_value = 0;
+
+	platform_set_drvdata(pdev, gpio_info);
+
+	disp_dev = devm_kzalloc(dev, sizeof(struct seven_seg_disp_dev),
+				GFP_KERNEL);
+	disp_dev->parent = *dev;
+	seven_seg_setup_cdev(disp_dev, &update_seven_seg_gpio_data);
+	return 0;
+}
+
+static int seven_seg_gpio_remove(struct platform_device *pdev)
+{
+	struct seven_seg_gpio_info *gpio_info = platform_get_drvdata(pdev);
+	struct seven_seg_disp_dev *disp_dev =
+				container_of(&pdev->dev,
+				struct seven_seg_disp_dev, parent);
+	seven_seg_rem_cdev(disp_dev);
+	del_timer_sync(&gpio_info->update_timer);
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static struct platform_driver seven_seg_gpio_driver = {
+	.probe		= seven_seg_gpio_probe,
+	.remove		= seven_seg_gpio_remove,
+	.driver		= {
+		.name	= "seven-seg-gpio",
+		.of_match_table = of_seven_seg_gpio_match,
+	},
+};
+
+module_platform_driver(seven_seg_gpio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jaghathiswari Rankappagounder Natarajan <jaghu@google.com>");
+MODULE_DESCRIPTION("Seven segment display driver using GPIO config");
--
2.8.0.rc3.226.g39d4020

^ permalink raw reply related

* [PATCH linux v1 2/4] drivers: misc: Character device driver for seven segment display
From: Jaghathiswari Rankappagounder Natarajan @ 2016-12-14  7:55 UTC (permalink / raw)
  To: openbmc-uLR06cmDAlY/bJ5BZ2RsiQ, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
	arnd-r2nGTMty4D4, gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r
  Cc: Jaghathiswari Rankappagounder Natarajan,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	joel-U3u1mxZcP9KHXe+LvDLADg
In-Reply-To: <1481702104-8617-1-git-send-email-jaghu-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>

Character device driver which implements the user-space
API for letting a user write to two 7-segment displays including
any conversion methods necessary to map the user input
to two 7-segment displays.

Signed-off-by: Jaghathiswari Rankappagounder Natarajan <jaghu-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
---
 drivers/misc/Kconfig          |   8 ++
 drivers/misc/Makefile         |   1 +
 drivers/misc/seven_seg_disp.c | 197 ++++++++++++++++++++++++++++++++++++++++++
 drivers/misc/seven_seg_disp.h |  34 ++++++++
 4 files changed, 240 insertions(+)
 create mode 100644 drivers/misc/seven_seg_disp.c
 create mode 100644 drivers/misc/seven_seg_disp.h

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index a216b46..a21aec1 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -791,6 +791,14 @@ config PANEL_CHANGE_MESSAGE
 	  If you say 'Y' here, you'll be able to choose a message yourself. Otherwise,
 	  say 'N' and keep the default message with the version.

+config SEVEN_SEGMENT_DISPLAY
+	tristate "Character driver for seven segment display support"
+	help
+	  Character device driver which implements the user-space
+	  API for letting a user write to two 7-segment displays including
+	  any conversion methods necessary to map the user input
+	  to two 7-segment displays.
+
 config PANEL_BOOT_MESSAGE
 	depends on PANEL && PANEL_CHANGE_MESSAGE="y"
 	string "New initialization message"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index b2fb6dbf..c2defbd 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -56,4 +56,5 @@ obj-$(CONFIG_GENWQE)		+= genwqe/
 obj-$(CONFIG_ECHO)		+= echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)	+= vexpress-syscfg.o
 obj-$(CONFIG_CXL_BASE)		+= cxl/
+obj-$(CONFIG_SEVEN_SEGMENT_DISPLAY)	+= seven_seg_disp.o
 obj-$(CONFIG_PANEL)             += panel.o
diff --git a/drivers/misc/seven_seg_disp.c b/drivers/misc/seven_seg_disp.c
new file mode 100644
index 0000000..4daeac5
--- /dev/null
+++ b/drivers/misc/seven_seg_disp.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2016 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or later as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/ctype.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include "seven_seg_disp.h"
+
+#define LED_DOT 0x01
+
+/*
+ * 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+ *  _       _   _       _   _   _   _   _   _       _       _   _
+ * | |   |  _|  _| |_| |_  |_    | |_| |_| |_| |_  |    _| |_  |_
+ * |_|   | |_   _|   |  _| |_|   | |_|   | | | |_| |_  |_| |_  |
+ *
+ * data[7:1] = led[a:g]
+ */
+const u8 seven_seg_bits[] = {
+	0xFC, 0x60, 0xDA, 0xF2, 0x66, 0xB6, 0xBE, 0xE0,
+	0xFE, 0xF6, 0xEE, 0x3E, 0x9C, 0x7A, 0x9E, 0x8E
+	};
+
+/*
+ * 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+ *      _       _   _                              _            _
+ *     |   |_  |_| |_  _   _   _   _   _   _   _  |_    _|  _| | |
+ *     |_  |_  |   |                               _|  |_| |_| | |
+ *
+ * data[7:1] = led[a:g]
+ */
+const u8 special_seven_seg_bits[] = {
+	0x00, 0x9C, 0x1E, 0xCE, 0x8E, 0x02, 0x02, 0x02,
+	0x02, 0x02, 0x02, 0x02, 0xB6, 0x7A, 0x7A, 0xEC
+	};
+
+static dev_t seven_seg_devno;
+static struct class *seven_seg_disp_class;
+
+static int seven_seg_disp_open(struct inode *inode, struct file *filp)
+{
+	struct seven_seg_disp_dev *disp_dev;
+
+	disp_dev = container_of(inode->i_cdev,
+				 struct seven_seg_disp_dev, cdev);
+	filp->private_data = disp_dev;
+	return 0;
+}
+
+static int seven_seg_disp_close(struct inode *inode, struct file *filp)
+{
+	filp->private_data = NULL;
+	return 0;
+}
+
+static ssize_t seven_seg_disp_read(struct file *filp, char __user *buf, size_t
+				len, loff_t *off)
+{
+	struct seven_seg_disp_dev *disp_dev = filp->private_data;
+
+	if (disp_dev->disp_data_valid)
+		return -EINVAL;
+
+	if (copy_to_user(buf, disp_dev->seven_seg_disp_data_array,
+				MAX_DISP_CHAR_SIZE) != 0) {
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static u16 convert_to_disp_data(char *buf)
+{
+	u8 low_display;
+	u8 high_display;
+	u16 led_value;
+
+	low_display = seven_seg_bits[hex_to_bin(buf[2])];
+
+	high_display = (buf[0] == '1') ?
+	special_seven_seg_bits[hex_to_bin(buf[1])] :
+	seven_seg_bits[hex_to_bin(buf[1])];
+
+	led_value = low_display | (high_display << 8);
+	if (buf[0] == '1')
+		led_value |= LED_DOT | (LED_DOT << 8);
+
+	return led_value;
+}
+
+static ssize_t seven_seg_disp_write(struct file *filp, const char __user *buf,
+				size_t len, loff_t *off)
+{
+	int length = len - 1;
+	int i;
+
+	struct seven_seg_disp_dev *disp_dev = filp->private_data;
+
+	if (length != MAX_DISP_CHAR_SIZE)
+		return -EINVAL;
+
+	if (copy_from_user(disp_dev->seven_seg_disp_data_array,
+				buf, length) != 0) {
+		return -EFAULT;
+	}
+
+	for (i = 0; i < MAX_DISP_CHAR_SIZE; i++) {
+		if (!isxdigit(disp_dev->seven_seg_disp_data_array[i]))
+			return -EINVAL;
+	}
+
+	disp_dev->current_seven_seg_disp_data = convert_to_disp_data(
+			disp_dev->seven_seg_disp_data_array);
+	disp_dev->disp_data_valid = true;
+	disp_dev->update_seven_seg_data(&disp_dev->parent,
+			disp_dev->current_seven_seg_disp_data);
+
+	return len;
+}
+
+static const struct file_operations seven_seg_disp_fops = {
+
+	.owner = THIS_MODULE,
+	.open = seven_seg_disp_open,
+	.release = seven_seg_disp_close,
+	.read = seven_seg_disp_read,
+	.write = seven_seg_disp_write
+};
+
+void seven_seg_rem_cdev(struct seven_seg_disp_dev *disp_dev)
+{
+	cdev_del(&disp_dev->cdev);
+	device_destroy(seven_seg_disp_class, seven_seg_devno);
+}
+
+int seven_seg_setup_cdev(struct seven_seg_disp_dev *disp_dev,
+	void (*update_disp_data)(struct device *, u16 data))
+{
+	struct device *dev;
+	int err;
+
+	dev = device_create(seven_seg_disp_class, &disp_dev->parent,
+			seven_seg_devno,
+			NULL, "seven_seg_disp_val");
+	if (dev == NULL)
+		return -1;
+	disp_dev->dev = dev;
+	disp_dev->update_seven_seg_data = update_disp_data;
+	disp_dev->disp_data_valid = false;
+
+	cdev_init(&disp_dev->cdev, &seven_seg_disp_fops);
+	err = cdev_add(&disp_dev->cdev, seven_seg_devno, 1);
+	if (err)
+		device_destroy(seven_seg_disp_class, seven_seg_devno);
+	return err;
+}
+
+static int __init seven_seg_disp_init(void)
+{
+	if (alloc_chrdev_region(&seven_seg_devno, 0, 1, "disp_state") < 0)
+		return -1;
+
+	seven_seg_disp_class = class_create(THIS_MODULE, "disp_state");
+	if (seven_seg_disp_class == NULL)
+		goto unreg_chrdev;
+
+unreg_chrdev:
+	unregister_chrdev_region(seven_seg_devno, 1);
+	return -1;
+}
+
+static void __exit seven_seg_disp_exit(void)
+{
+	class_destroy(seven_seg_disp_class);
+	unregister_chrdev_region(seven_seg_devno, 1);
+}
+
+module_init(seven_seg_disp_init);
+module_exit(seven_seg_disp_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jaghathiswari Rankappagounder Natarajan <jaghu-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>");
+MODULE_DESCRIPTION("Seven segment display character driver");
diff --git a/drivers/misc/seven_seg_disp.h b/drivers/misc/seven_seg_disp.h
new file mode 100644
index 0000000..b0f93c5
--- /dev/null
+++ b/drivers/misc/seven_seg_disp.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or later as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SEVEN_SEG_DISP_H
+#define SEVEN_SEG_DISP_H
+
+#include <linux/device.h>
+#include <linux/cdev.h>
+
+#define MAX_DISP_CHAR_SIZE 3
+
+#define DEFAULT_REFRESH_INTERVAL_MS 1000
+
+struct seven_seg_disp_dev {
+	bool disp_data_valid;
+	u16 current_seven_seg_disp_data;
+	char seven_seg_disp_data_array[MAX_DISP_CHAR_SIZE];
+	struct device parent;
+	struct device *dev;
+	struct cdev cdev;
+	void (*update_seven_seg_data)(struct device *, u16 data);
+};
+
+int seven_seg_setup_cdev(struct seven_seg_disp_dev *disp_dev,
+	void (*update_disp_data)(struct device *, u16 data));
+
+void seven_seg_rem_cdev(struct seven_seg_disp_dev *disp_dev);
+
+#endif
--
2.8.0.rc3.226.g39d4020

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH linux v1 1/4] Documentation: dt-bindings: Document bindings for seven segment display support
From: Jaghathiswari Rankappagounder Natarajan @ 2016-12-14  7:55 UTC (permalink / raw)
  To: openbmc-uLR06cmDAlY/bJ5BZ2RsiQ, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
	arnd-r2nGTMty4D4, gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r
  Cc: Jaghathiswari Rankappagounder Natarajan,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	joel-U3u1mxZcP9KHXe+LvDLADg
In-Reply-To: <1481702104-8617-1-git-send-email-jaghu-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>

This binding provides interface for adding clock, data and clear signal GPIO
lines to control seven segment display.

Signed-off-by: Jaghathiswari Rankappagounder Natarajan <jaghu-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
---
 .../devicetree/bindings/misc/seven-seg-gpio.txt    | 27 ++++++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/misc/seven-seg-gpio.txt

diff --git a/Documentation/devicetree/bindings/misc/seven-seg-gpio.txt b/Documentation/devicetree/bindings/misc/seven-seg-gpio.txt
new file mode 100644
index 0000000..9a4e255
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/seven-seg-gpio.txt
@@ -0,0 +1,27 @@
+This binding defines interface to add clock, data and clear GPIO lines required
+for seven segment display support.
+
+Required properties:
+- compatible : should be "seven-seg-gpio-dev".
+- clock-gpios :  Should specify the GPIO pin connected to the Clock line on the
+  hardware.
+- data-gpios : Should specify the GPIO pin connected to Data line on the
+  hardware.
+- clear-gpios : Should specify the GPIO pin connected to Clear line on the
+  hardware.
+
+Optional properties:
+- refresh-interval-ms : The interval at which to refresh the display.
+  If this property is not present, the default value is 1000.
+
+Examples:
+
+#include <dt-bindings/gpio/gpio.h>
+
+seven-seg-disp {
+	compatible = "seven-seg-gpio-dev";
+	refresh-interval-ms = "1000";
+	clock-gpios = <&gpio 0 GPIO_ACTIVE_LOW>;
+	data-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>;
+	clear-gpios = <&gpio 2 GPIO_ACTIVE_HIGH>;
+};
--
2.8.0.rc3.226.g39d4020

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH linux v1 0/4] Seven segment display support
From: Jaghathiswari Rankappagounder Natarajan @ 2016-12-14  7:55 UTC (permalink / raw)
  To: openbmc, robh+dt, mark.rutland, linux, arnd, gregkh
  Cc: Jaghathiswari Rankappagounder Natarajan, devicetree, linux-kernel,
	linux-arm-kernel, joel

This patchset includes:

Documentation for the binding which provides an interface for adding clock,
data and clear signal GPIO lines to control seven segment display.

The platform device driver provides an API for displaying on two 7-segment
displays, and implements the required bit-banging. The hardware assumed is
74HC164 wired to two 7-segment displays.

The character device driver implements the user-space API for letting a user
write to two 7-segment displays including any conversion methods necessary
to map the user input to two 7-segment displays.

Adding clock, data and clear signal GPIO lines in the devicetree to control
seven segment display on zaius platform.

The platform driver matches on the device tree node; the platform driver also
initializes the character device.

Tested that the seven segment display works properly by writing to the
character device file on a EVB AST2500 board which also has 74HC164 wired
to two 7-segment displays.

Jaghathiswari Rankappagounder Natarajan (4):
  Documentation: dt-bindings: Document bindings for seven segment
    display support
  drivers: misc: Character device driver for seven segment display
  drivers: misc: Platform driver for seven segment display support
  arm: dts: Add dt-binding to support seven segment display on zaius

 .../devicetree/bindings/misc/seven-seg-gpio.txt    |  27 +++
 arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts         |   8 +
 drivers/misc/Kconfig                               |  16 ++
 drivers/misc/Makefile                              |   2 +
 drivers/misc/seven_seg_disp.c                      | 197 ++++++++++++++++++++
 drivers/misc/seven_seg_disp.h                      |  34 ++++
 drivers/misc/seven_seg_gpio.c                      | 206 +++++++++++++++++++++
 7 files changed, 490 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/misc/seven-seg-gpio.txt
 create mode 100644 drivers/misc/seven_seg_disp.c
 create mode 100644 drivers/misc/seven_seg_disp.h
 create mode 100644 drivers/misc/seven_seg_gpio.c

--
2.8.0.rc3.226.g39d4020

^ permalink raw reply

* RE: [PATCH 5/5] Documentation: fsl-quadspi: Add fsl, ls1012a-qspi compatible string
From: Yao Yuan @ 2016-12-14  7:52 UTC (permalink / raw)
  To: Rob Herring
  Cc: Yuan Yao, shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	mark.rutland-5wv7dgnIgG8@public.gmane.org,
	computersforpeace-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
	dwmw2-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CAL_Jsq+jp_2m7D=Hv6TRa+1nQZhPis-0MPK5kOAWge_7RvN4Qg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Thu, Dec 14, 2016 at 05:23:02PM +0800, Rob Herring wrote:
> On Mon, Dec 12, 2016 at 8:47 PM, Yao Yuan <yao.yuan@nxp.com> wrote:
> > On Thu, Dec 13, 2016 at 05:23:02PM +0800, Rob Herring wrote:
> >> On Thu, Dec 08, 2016 at 05:23:04PM +0800, Yuan Yao wrote:
> >> > From: Yuan Yao <yao.yuan@nxp.com>
> >>
> >> Same problem in this subject too.
> >>
> >> >
> >> > new compatible string: "fsl,ls1012a-qspi".
> >> >
> >> > Signed-off-by: Yuan Yao <yao.yuan@nxp.com>
> >> > ---
> >> >  Documentation/devicetree/bindings/mtd/fsl-quadspi.txt | 1 +
> >> >  1 file changed, 1 insertion(+)
> >>
> >> Acked-by: Rob Herring <robh@kernel.org>
> >
> > Thanks for your review.
> > And do you have any suggestion for this subject?
> 
> The problem is you have a space in the compatible string: "fsl, ls1012a-qspi"
> rather than "fsl,ls1012a-qspi"
> 
> Also, I prefer "dt/bindings: " as the beginning of binding patch subjects.
> 

Ok, Get it.

Thanks for your comments.
I will send v2 soon.

^ permalink raw reply

* Re: [PATCH v8 2/4] vcodec: mediatek: Add Mediatek JPEG Decoder Driver
From: Ricky Liang @ 2016-12-14  7:29 UTC (permalink / raw)
  To: Rick Chang
  Cc: Hans Verkuil, Laurent Pinchart, Mauro Carvalho Chehab,
	Matthias Brugger, Rob Herring, open list, linux-media,
	srv_heupstream, moderated list:ARM/Mediatek SoC...,
	moderated list:ARM/Mediatek SoC...,
	open list:OPEN FIRMWARE AND..., Minghsiu Tsai, Bin Liu
In-Reply-To: <1481533621.13825.2.camel@mtksdaap41>

Hi Rick,

Can you upload patchset v9 to address the issue? Thanks!

On Mon, Dec 12, 2016 at 5:07 PM, Rick Chang <rick.chang@mediatek.com> wrote:
> Hi Ricky,
>
> Thanks for your feedback. We will fix the problem in another patch.
>
> On Mon, 2016-12-12 at 12:34 +0800, Ricky Liang wrote:
>> Hi Rick,
>>
>> On Wed, Nov 30, 2016 at 11:08 AM, Rick Chang <rick.chang@mediatek.com> wrote:
>> > Add v4l2 driver for Mediatek JPEG Decoder
>> >
>> > Signed-off-by: Rick Chang <rick.chang@mediatek.com>
>> > Signed-off-by: Minghsiu Tsai <minghsiu.tsai@mediatek.com>
>>
>> <snip...>
>>
>> > +static bool mtk_jpeg_check_resolution_change(struct mtk_jpeg_ctx *ctx,
>> > +                                            struct mtk_jpeg_dec_param *param)
>> > +{
>> > +       struct mtk_jpeg_dev *jpeg = ctx->jpeg;
>> > +       struct mtk_jpeg_q_data *q_data;
>> > +
>> > +       q_data = &ctx->out_q;
>> > +       if (q_data->w != param->pic_w || q_data->h != param->pic_h) {
>> > +               v4l2_dbg(1, debug, &jpeg->v4l2_dev, "Picture size change\n");
>> > +               return true;
>> > +       }
>> > +
>> > +       q_data = &ctx->cap_q;
>> > +       if (q_data->fmt != mtk_jpeg_find_format(ctx, param->dst_fourcc,
>> > +                                               MTK_JPEG_FMT_TYPE_CAPTURE)) {
>> > +               v4l2_dbg(1, debug, &jpeg->v4l2_dev, "format change\n");
>> > +               return true;
>> > +       }
>> > +       return false;
>>
>> <snip...>
>>
>> > +static void mtk_jpeg_device_run(void *priv)
>> > +{
>> > +       struct mtk_jpeg_ctx *ctx = priv;
>> > +       struct mtk_jpeg_dev *jpeg = ctx->jpeg;
>> > +       struct vb2_buffer *src_buf, *dst_buf;
>> > +       enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
>> > +       unsigned long flags;
>> > +       struct mtk_jpeg_src_buf *jpeg_src_buf;
>> > +       struct mtk_jpeg_bs bs;
>> > +       struct mtk_jpeg_fb fb;
>> > +       int i;
>> > +
>> > +       src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
>> > +       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
>> > +       jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(src_buf);
>> > +
>> > +       if (jpeg_src_buf->flags & MTK_JPEG_BUF_FLAGS_LAST_FRAME) {
>> > +               for (i = 0; i < dst_buf->num_planes; i++)
>> > +                       vb2_set_plane_payload(dst_buf, i, 0);
>> > +               buf_state = VB2_BUF_STATE_DONE;
>> > +               goto dec_end;
>> > +       }
>> > +
>> > +       if (mtk_jpeg_check_resolution_change(ctx, &jpeg_src_buf->dec_param)) {
>> > +               mtk_jpeg_queue_src_chg_event(ctx);
>> > +               ctx->state = MTK_JPEG_SOURCE_CHANGE;
>> > +               v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
>> > +               return;
>> > +       }
>>
>> This only detects source change if multiple OUPUT buffers are queued.
>> It does not catch the source change in the following scenario:
>>
>> - OUPUT buffers for jpeg1 enqueued
>> - OUTPUT queue STREAMON
>> - userspace creates CAPTURE buffers
>> - CAPTURE buffers enqueued
>> - CAPTURE queue STREAMON
>> - decode
>> - OUTPUT queue STREAMOFF
>> - userspace recreates OUTPUT buffers for jpeg2
>> - OUTPUT buffers for jpeg2 enqueued
>> - OUTPUT queue STREAMON
>>
>> In the above sequence if jpeg2's decoded size is larger than jpeg1 the
>> function fails to detect that the existing CAPTURE buffers are not big
>> enough to hold the decoded data.
>>
>> A possible fix is to pass *dst_buf to
>> mtk_jpeg_check_resolution_change(), and check in the function that all
>> the dst_buf planes are large enough to hold the decoded data.
>>
>> > +
>> > +       mtk_jpeg_set_dec_src(ctx, src_buf, &bs);
>> > +       if (mtk_jpeg_set_dec_dst(ctx, &jpeg_src_buf->dec_param, dst_buf, &fb))
>> > +               goto dec_end;
>> > +
>> > +       spin_lock_irqsave(&jpeg->hw_lock, flags);
>> > +       mtk_jpeg_dec_reset(jpeg->dec_reg_base);
>> > +       mtk_jpeg_dec_set_config(jpeg->dec_reg_base,
>> > +                               &jpeg_src_buf->dec_param, &bs, &fb);
>> > +
>> > +       mtk_jpeg_dec_start(jpeg->dec_reg_base);
>> > +       spin_unlock_irqrestore(&jpeg->hw_lock, flags);
>> > +       return;
>> > +
>> > +dec_end:
>> > +       v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
>> > +       v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
>> > +       v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), buf_state);
>> > +       v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), buf_state);
>> > +       v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
>> > +}
>>
>> <snip...>
>
>

^ permalink raw reply

* Re: [PATCH v4 2/4] cpuidle:powernv: Add helper function to populate powernv idle states.
From: Gautham R Shenoy @ 2016-12-14  7:14 UTC (permalink / raw)
  To: Balbir Singh
  Cc: Stewart Smith, Gautham R. Shenoy, Michael Neuling, linux-pm,
	Shreyas B. Prabhu, Daniel Lezcano, Rafael J. Wysocki,
	linux-kernel, devicetree, Rob Herring, Paul Mackerras,
	Shilpasri G Bhat, Oliver O'Halloran, Mark Rutland,
	linuxppc-dev
In-Reply-To: <d50fa1c4-9f48-c463-ddf8-293c23053b8f@gmail.com>

Hi Balbir,

On Tue, Dec 13, 2016 at 10:51:04PM +1100, Balbir Singh wrote:
> 
> 
> On 10/12/16 00:32, Gautham R. Shenoy wrote:
> > From: "Gautham R. Shenoy" <ego@linux.vnet.ibm.com>
> > 
> > In the current code for powernv_add_idle_states, there is a lot of code
> > duplication while initializing an idle state in powernv_states table.
> > 
> > Add an inline helper function to populate the powernv_states[] table for
> > a given idle state. Invoke this for populating the "Nap", "Fastsleep"
> > and the stop states in powernv_add_idle_states.
> > 
> > Signed-off-by: Gautham R. Shenoy <ego@linux.vnet.ibm.com>
> > ---
> >  drivers/cpuidle/cpuidle-powernv.c | 85 ++++++++++++++++++++++-----------------
> >  include/linux/cpuidle.h           |  1 +
> >  2 files changed, 50 insertions(+), 36 deletions(-)
> > 
> > diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c
> > index 7fe442c..db18af1 100644
> > --- a/drivers/cpuidle/cpuidle-powernv.c
> > +++ b/drivers/cpuidle/cpuidle-powernv.c
> > @@ -167,6 +167,24 @@ static int powernv_cpuidle_driver_init(void)
> >  	return 0;
> >  }
> >  
> > +static inline void add_powernv_state(int index, const char *name,
> > +				     unsigned int flags,
> > +				     int (*idle_fn)(struct cpuidle_device *,
> > +						    struct cpuidle_driver *,
> > +						    int),
> > +				     unsigned int target_residency,
> > +				     unsigned int exit_latency,
> > +				     u64 psscr_val)
> > +{
> > +	strlcpy(powernv_states[index].name, name, CPUIDLE_NAME_LEN);
> > +	strlcpy(powernv_states[index].desc, name, CPUIDLE_NAME_LEN);
> 
> Do name and desc ever diverge?

On some other architectures, like kirkwood (see
drivers/cpuidle/cpuidle-kirkwood.c) they do. "desc" field is used to
provide a more descriptive information regarding the idle state.

On POWER, the names were self-explanatory. So, we have desc same as
the name.

> 
> > +	powernv_states[index].flags = flags;
> > +	powernv_states[index].target_residency = target_residency;
> > +	powernv_states[index].exit_latency = exit_latency;
> > +	powernv_states[index].enter = idle_fn;
> 
> Why not call it idle_fn instead of enter?

"enter" is a field name in the generic cpuidle_state structure and
powernv_states[] is an instance of that structure.

> 
> > +	stop_psscr_table[index] = psscr_val;
> > +}
> > +
> >  static int powernv_add_idle_states(void)
> >  {
> >  	struct device_node *power_mgt;
> > @@ -236,6 +254,7 @@ static int powernv_add_idle_states(void)
> >  		"ibm,cpu-idle-state-residency-ns", residency_ns, dt_idle_states);
> >  
> >  	for (i = 0; i < dt_idle_states; i++) {
> > +		unsigned int exit_latency, target_residency;
> >  		/*
> >  		 * If an idle state has exit latency beyond
> >  		 * POWERNV_THRESHOLD_LATENCY_NS then don't use it
> > @@ -243,28 +262,33 @@ static int powernv_add_idle_states(void)
> >  		 */
> >  		if (latency_ns[i] > POWERNV_THRESHOLD_LATENCY_NS)
> 
> Ideally this should be called POWERNV_MAX_THRESHOLD_LATENCY_NS then

Yes, it can be called that. But then again, we're only interested in
the upper threshold in this code. I will add a comment near the macro
definition.

> 
> >  			continue;
> > +		/*
> > +		 * Firmware passes residency and latency values in ns.
> > +		 * cpuidle expects it in us.
> > +		 */
> > +		exit_latency = ((unsigned int)latency_ns[i]) / 1000;
> > +		if (!rc)
> > +			target_residency = residency_ns[i] / 1000;
> > +		else
> > +			target_residency = 0;
> 
> Where do we get rc from? what does target_residency = 0 mean?

The rc value comes from the
of_property_read_u32_array(power_mgt,
		"ibm,cpu-idle-state-residency-ns", residency_ns,
		dt_idle_states);

just before the for-loop. This tells us whether the firmware has
populated the residency information for the idle state or not.

rc != 0 indicates that the firmware has not populated the value.

Since the governor will pick the first idle state whose
target_residency matches the predicted residency, setting
target_residency = 0 implies that if any stop state is selected at
all, it is the earliest state.


> Balbir Singh
> 

^ permalink raw reply

* Re: [PATCH] Input: imx6ul_tsc - generalize the averaging property
From: Guy Shapiro @ 2016-12-14  7:09 UTC (permalink / raw)
  To: Rob Herring
  Cc: Fabio Estevam, Mark Rutland, devicetree@vger.kernel.org,
	Haibo Chen, Dmitry Torokhov, linux-input@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <CAL_JsqJAdxrUGL5pjTPDkrXTsKJU-vL1Y4TpqhP79bESs9vR-g@mail.gmail.com>

On 13/12/2016 21:54, Rob Herring wrote:

> On Sun, Dec 11, 2016 at 1:06 AM, Guy Shapiro <guy.shapiro@mobi-wize.com> wrote:
>> Make the avarage-samples property a general touchscreen property
>> rather than imx6ul device specific.
>>
>> Signed-off-by: Guy Shapiro <guy.shapiro@mobi-wize.com>
>> ---
>>   .../bindings/input/touchscreen/imx6ul_tsc.txt      | 11 ++----
>>   .../bindings/input/touchscreen/touchscreen.txt     |  3 ++
>>   drivers/input/touchscreen/imx6ul_tsc.c             | 46 ++++++++++++++++------
>>   3 files changed, 41 insertions(+), 19 deletions(-)
> [...]
>
>> +       switch (average_samples) {
>> +       case 1:
>> +               tsc->average_enable = false;
>> +               tsc->average_select = 0; /* value unused; initialize anyway */
>> +               break;
>> +       case 4:
>> +               tsc->average_enable = true;
>> +               tsc->average_select = 0;
>> +               break;
>> +       case 8:
>> +               tsc->average_enable = true;
>> +               tsc->average_select = 1;
>> +               break;
>> +       case 16:
>> +               tsc->average_enable = true;
>> +               tsc->average_select = 2;
>> +               break;
>> +       case 32:
>> +               tsc->average_enable = true;
>> +               tsc->average_select = 3;
>> +               break;
> This could be more efficiently written as
>
> tsc->average_select = log2(average_samples) - 2;
>
> Then enable if >=0.

Using '1' to indicate no averaging is more consistent then using '0'.
I think it is better to validate the values rather then round them.

What do you think about:
+       switch (average_samples) {
+       case 1:
+               tsc->average_enable = false;
+               tsc->average_select = 0; /* value unused; initialize 
anyway */
+               break;
+       case 4:
+       case 8:
+       case 16:
+       case 32:
+               tsc->average_enable = true;
+               tsc->average_select = ilog2(average_samples) - 2;
+               break;
+       default:
+               dev_err(&pdev->dev,
+                       "touchscreen-average-samples (%u) must be 1, 4, 
8, 16 or 32\n",
+                       average_samples);

Guy.

^ permalink raw reply

* Re: [PATCH v2 0/7] ath9k: EEPROM swapping improvements
From: Adrian Chadd @ 2016-12-14  6:45 UTC (permalink / raw)
  To: Martin Blumenstingl
  Cc: devicetree@vger.kernel.org, arnd@arndb.de,
	linux-wireless@vger.kernel.org, ath9k-devel, Valo, Kalle,
	ath9k-devel@lists.ath9k.org, chunkeey@googlemail.com,
	nbd@nbd.name
In-Reply-To: <CAFBinCC6JWBhZwma=66fBi3_to2SaHOMNDQS23jHNhcc+RUcYQ@mail.gmail.com>

hi,

On 12 December 2016 at 12:05, Martin Blumenstingl
<martin.blumenstingl@googlemail.com> wrote:

>
> It seems that there are a few devices out there where the whole EEPROM
> is swab16'ed which switches the position of the 1-byte fields
> opCapFlags and eepMisc.
> those still work fine with the new code, however I had a second patch
> in LEDE [0] which results in ath9k_platform_data.endian_check NOT
> being set anymore.
> that endian_check flag was used before to swab16 the whole EEPROM, to
> correct the position of the 1-byte fields again.
> Currently we are fixing this in the firmware hotplug script: [1]
> This is definitely not a blocker for this series though (if we want to
> have a devicetree replacement for "ath9k_platform_data.endian_check"
> then I'd work on that within a separate series, but I somewhat
> consider these EEPROMs as "broken" so fixing them in
> userspace/firmware hotplug script is fine for me)

As a reference - the reference driver has been doign this for a while.
It attempts to detect the endianness by looking at the 0xa55a
signature endian and figuring out which endian the actual contents are
in.

So just FYI yeah, this is a "thing" for reasons I don't quite know.



-adrian

>
>
> Regards,
> Martin
>
>
> [0] https://git.lede-project.org/?p=source.git;a=commitdiff;h=a20616863d32d91163043b6657a63c836bd9c5ba
> [1] https://git.lede-project.org/?p=source.git;a=commitdiff;h=afa37092663d00aa0abf8c61943d9a1b5558b144

^ permalink raw reply

* Re: [PATCH v4 1/4] powernv:idle: Add IDLE_STATE_ENTER_SEQ_NORET macro
From: Gautham R Shenoy @ 2016-12-14  6:35 UTC (permalink / raw)
  To: Balbir Singh
  Cc: Gautham R. Shenoy, Michael Ellerman, Benjamin Herrenschmidt,
	Paul Mackerras, Rafael J. Wysocki, Daniel Lezcano,
	Michael Neuling, Vaidyanathan Srinivasan, Shreyas B. Prabhu,
	Shilpasri G Bhat, Stewart Smith, Oliver O'Halloran,
	linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Mark Rutland
In-Reply-To: <f1bc3387-1118-6fd7-8e1b-2e59bfabdad1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

Hi Balbir,

On Tue, Dec 13, 2016 at 09:13:26PM +1100, Balbir Singh wrote:
> 
> 
> On 10/12/16 00:32, Gautham R. Shenoy wrote:
> > From: "Gautham R. Shenoy" <ego-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
> > diff --git a/arch/powerpc/include/asm/cpuidle.h b/arch/powerpc/include/asm/cpuidle.h
> > index 3919332..0a3255b 100644
> > --- a/arch/powerpc/include/asm/cpuidle.h
> > +++ b/arch/powerpc/include/asm/cpuidle.h
> > @@ -21,7 +21,7 @@
> >  
> >  /* Idle state entry routines */
> >  #ifdef	CONFIG_PPC_P7_NAP
> > -#define	IDLE_STATE_ENTER_SEQ(IDLE_INST)				\
> > +#define IDLE_STATE_ENTER_SEQ(IDLE_INST)                         \
> >  	/* Magic NAP/SLEEP/WINKLE mode enter sequence */	\
> >  	std	r0,0(r1);					\
> >  	ptesync;						\
> > @@ -29,6 +29,9 @@
> >  1:	cmpd	cr0,r0,r0;					\
> >  	bne	1b;						\
> >  	IDLE_INST;						\
> > +
> 
> Is the power saving magic sequence the same as before for power 9
> as well?

Yes, this is the same magic sequence for POWER9.

--
Thanks and Regards
gautham.

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH 2/2] arm64: dts: exynos: Add support for S6E3HA2 panel device on TM2 board
From: Hoegeun Kwon @ 2016-12-14  6:04 UTC (permalink / raw)
  To: thierry.reding, kgene, krzk
  Cc: devicetree, linux-samsung-soc, Chanwoo Choi, linux-kernel,
	dri-devel, Hyungwon Hwang, Hoegeun Kwon
In-Reply-To: <1481695445-13088-1-git-send-email-hoegeun.kwon@samsung.com>

From: Hyungwon Hwang <human.hwang@samsung.com>

This patch add the panel device tree node for S6E3HA2 display
controller to TM2 dts.

Signed-off-by: Hyungwon Hwang <human.hwang@samsung.com>
Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Hoegeun Kwon <hoegeun.kwon@samsung.com>
---
 arch/arm64/boot/dts/exynos/exynos5433-tm2.dts | 33 +++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
index db879f4..4ad2332 100644
--- a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
+++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
@@ -252,11 +252,44 @@
 			reg = <1>;
 
 			dsi_out: endpoint {
+				remote-endpoint = <&dsi_in>;
 				samsung,burst-clock-frequency = <512000000>;
 				samsung,esc-clock-frequency = <16000000>;
 			};
 		};
 	};
+
+	panel@0 {
+		compatible = "samsung,s6e3ha2";
+		reg = <0>;
+		vdd3-supply = <&ldo27_reg>;
+		vci-supply = <&ldo28_reg>;
+		reset-gpios = <&gpg0 0 GPIO_ACTIVE_HIGH>;
+		enable-gpios = <&gpf1 5 GPIO_ACTIVE_HIGH>;
+		te-gpios = <&gpf1 3 GPIO_ACTIVE_HIGH>;
+		power-on-delay = <120>;
+		reset-delay = <5>;
+
+		display-timings {
+			timing-0 {
+				clock-frequency = <14874444>;
+				hactive = <1440>;
+				vactive = <2560>;
+				hfront-porch = <1>;
+				hback-porch = <1>;
+				hsync-len = <1>;
+				vfront-porch = <1>;
+				vback-porch = <15>;
+				vsync-len = <1>;
+			};
+		};
+
+		port {
+			dsi_in: endpoint {
+				remote-endpoint = <&dsi_out>;
+			};
+		};
+	};
 };
 
 &hsi2c_0 {
-- 
1.9.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related

* [PATCH 1/2] drm/panel: Add support for S6E3HA2 panel driver on TM2 board
From: Hoegeun Kwon @ 2016-12-14  6:04 UTC (permalink / raw)
  To: thierry.reding, kgene, krzk
  Cc: devicetree, linux-samsung-soc, Donghwa Lee, linux-kernel,
	dri-devel, Hyungwon Hwang, Hoegeun Kwon
In-Reply-To: <1481695445-13088-1-git-send-email-hoegeun.kwon@samsung.com>

This patch add support for MIPI-DSI based S6E3HA2 AMOLED panel
driver. This panel has 1440x2560 resolution in 5.7-inch physical
panel in the TM2 device.

Signed-off-by: Donghwa Lee <dh09.lee@samsung.com>
Signed-off-by: Hyungwon Hwang <human.hwang@samsung.com>
Signed-off-by: Hoegeun Kwon <hoegeun.kwon@samsung.com>
---
 .../bindings/display/panel/samsung,s6e3ha2.txt     |  52 ++
 drivers/gpu/drm/panel/Kconfig                      |   6 +
 drivers/gpu/drm/panel/Makefile                     |   1 +
 drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c      | 756 +++++++++++++++++++++
 4 files changed, 815 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/samsung,s6e3ha2.txt
 create mode 100644 drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c

diff --git a/Documentation/devicetree/bindings/display/panel/samsung,s6e3ha2.txt b/Documentation/devicetree/bindings/display/panel/samsung,s6e3ha2.txt
new file mode 100644
index 0000000..1f41f24
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/samsung,s6e3ha2.txt
@@ -0,0 +1,52 @@
+Samsung S6E3HA2 5.7" 1440x2560 AMOLED panel
+
+Required properties:
+  - compatible: "samsung,s6e3ha2"
+  - reg: the virtual channel number of a DSI peripheral
+  - vdd3-supply: core voltage supply
+  - vci-supply: voltage supply for analog circuits
+  - reset-gpios: a GPIO spec for the reset pin
+  - enable-gpios: a GPIO spec for the panel enable pin
+  - te-gpios: a GPIO spec for the tearing effect synchronization signal gpio pin
+
+Optional properties:
+  - display-timings: timings for the connected panel as described by [1]
+
+The device node can contain one 'port' child node with one child
+'endpoint' node, according to the bindings defined in [2]. This
+node should describe panel's video bus.
+
+[1]: Documentation/devicetree/bindings/display/panel/display-timing.txt
+[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+
+	panel@0 {
+		compatible = "samsung,s6e3ha2";
+		reg = <0>;
+		vdd3-supply = <&ldo27_reg>;
+		vci-supply = <&ldo28_reg>;
+		reset-gpios = <&gpg0 0 GPIO_ACTIVE_HIGH>;
+		enable-gpios = <&gpf1 5 GPIO_ACTIVE_HIGH>;
+		te-gpios = <&gpf1 3 GPIO_ACTIVE_HIGH>;
+
+		display-timings {
+			timing-0 {
+				clock-frequency = <0>;
+				hactive = <1440>;
+				vactive = <2560>;
+				hfront-porch = <1>;
+				hback-porch = <1>;
+				hsync-len = <1>;
+				vfront-porch = <1>;
+				vback-porch = <15>;
+				vsync-len = <1>;
+			};
+		};
+
+		port {
+			dsi_in: endpoint {
+				remote-endpoint = <&dsi_out>;
+			};
+		};
+	};
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 62aba97..e1a2fcd 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -58,6 +58,12 @@ config DRM_PANEL_SAMSUNG_S6E8AA0
 	select DRM_MIPI_DSI
 	select VIDEOMODE_HELPERS
 
+config DRM_PANEL_SAMSUNG_S6E3HA2
+	tristate "Samsung S6E3HA2 DSI video mode panel"
+	depends on OF
+	select DRM_MIPI_DSI
+	select VIDEOMODE_HELPERS
+
 config DRM_PANEL_SHARP_LQ101R1SX01
 	tristate "Sharp LQ101R1SX01 panel"
 	depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index a5c7ec0..993699b 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -4,5 +4,6 @@ obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
 obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
+obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o
 obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
 obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o
diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
new file mode 100644
index 0000000..a6ad63b
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
@@ -0,0 +1,756 @@
+/*
+ * MIPI-DSI based s6e3ha2 AMOLED 5.7 inch panel driver.
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Donghwa Lee <dh09.lee@samsung.com>
+ * Hyungwon Hwang <human.hwang@samsung.com>
+ * Hoegeun Kwon <hoegeun.kwon@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <drm/drmP.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <video/mipi_display.h>
+#include <video/of_videomode.h>
+#include <video/videomode.h>
+#include <linux/backlight.h>
+
+#define S6E3HA2_MIN_BRIGHTNESS		0
+#define S6E3HA2_MAX_BRIGHTNESS		100
+#define S6E3HA2_DEFAULT_BRIGHTNESS	80
+
+#define S6E3HA2_NUM_GAMMA_STEPS		46
+#define S6E3HA2_GAMMA_CMD_CNT		35
+#define S6E3HA2_VINT_STATUS_MAX		10
+
+static const u8 gamma_tbl[S6E3HA2_NUM_GAMMA_STEPS][S6E3HA2_GAMMA_CMD_CNT] = {
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x82, 0x83,
+	  0x85, 0x88, 0x8b, 0x8b, 0x84, 0x88, 0x82, 0x82, 0x89, 0x86, 0x8c,
+	  0x94, 0x84, 0xb1, 0xaf, 0x8e, 0xcf, 0xad, 0xc9, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x84, 0x84,
+	  0x85, 0x87, 0x8b, 0x8a, 0x84, 0x88, 0x82, 0x82, 0x89, 0x86, 0x8a,
+	  0x93, 0x84, 0xb0, 0xae, 0x8e, 0xc9, 0xa8, 0xc5, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
+	  0x85, 0x86, 0x8a, 0x8a, 0x84, 0x88, 0x81, 0x84, 0x8a, 0x88, 0x8a,
+	  0x91, 0x84, 0xb1, 0xae, 0x8b, 0xd5, 0xb2, 0xcc, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
+	  0x85, 0x86, 0x8a, 0x8a, 0x84, 0x87, 0x81, 0x84, 0x8a, 0x87, 0x8a,
+	  0x91, 0x85, 0xae, 0xac, 0x8a, 0xc3, 0xa3, 0xc0, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x85, 0x85,
+	  0x86, 0x85, 0x88, 0x89, 0x84, 0x89, 0x82, 0x84, 0x87, 0x85, 0x8b,
+	  0x91, 0x88, 0xad, 0xab, 0x8a, 0xb7, 0x9b, 0xb6, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
+	  0x85, 0x86, 0x89, 0x8a, 0x84, 0x89, 0x83, 0x83, 0x86, 0x84, 0x8b,
+	  0x90, 0x84, 0xb0, 0xae, 0x8b, 0xce, 0xad, 0xc8, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
+	  0x85, 0x87, 0x89, 0x8a, 0x83, 0x87, 0x82, 0x85, 0x88, 0x87, 0x89,
+	  0x8f, 0x84, 0xac, 0xaa, 0x89, 0xb1, 0x98, 0xaf, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
+	  0x85, 0x86, 0x88, 0x89, 0x84, 0x88, 0x83, 0x82, 0x85, 0x84, 0x8c,
+	  0x91, 0x86, 0xac, 0xaa, 0x89, 0xc2, 0xa5, 0xbd, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
+	  0x85, 0x87, 0x89, 0x8a, 0x83, 0x87, 0x82, 0x85, 0x88, 0x87, 0x88,
+	  0x8b, 0x82, 0xad, 0xaa, 0x8a, 0xc2, 0xa5, 0xbd, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83,
+	  0x85, 0x86, 0x87, 0x89, 0x84, 0x88, 0x83, 0x82, 0x85, 0x84, 0x8a,
+	  0x8e, 0x84, 0xae, 0xac, 0x89, 0xda, 0xb7, 0xd0, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
+	  0x85, 0x86, 0x87, 0x89, 0x84, 0x88, 0x83, 0x80, 0x83, 0x82, 0x8b,
+	  0x8e, 0x85, 0xac, 0xaa, 0x89, 0xc8, 0xaa, 0xc1, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
+	  0x85, 0x86, 0x87, 0x89, 0x81, 0x85, 0x81, 0x84, 0x86, 0x84, 0x8c,
+	  0x8c, 0x84, 0xa9, 0xa8, 0x87, 0xa3, 0x92, 0xa1, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
+	  0x85, 0x86, 0x87, 0x89, 0x84, 0x86, 0x83, 0x80, 0x83, 0x81, 0x8c,
+	  0x8d, 0x84, 0xaa, 0xaa, 0x89, 0xce, 0xaf, 0xc5, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
+	  0x85, 0x86, 0x87, 0x89, 0x81, 0x83, 0x80, 0x83, 0x85, 0x85, 0x8c,
+	  0x8c, 0x84, 0xa8, 0xa8, 0x88, 0xb5, 0x9f, 0xb0, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
+	  0x86, 0x86, 0x87, 0x88, 0x81, 0x83, 0x80, 0x83, 0x85, 0x85, 0x8c,
+	  0x8b, 0x84, 0xab, 0xa8, 0x86, 0xd4, 0xb4, 0xc9, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
+	  0x86, 0x86, 0x87, 0x88, 0x81, 0x83, 0x80, 0x84, 0x84, 0x85, 0x8b,
+	  0x8a, 0x83, 0xa6, 0xa5, 0x84, 0xbb, 0xa4, 0xb3, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84,
+	  0x86, 0x85, 0x86, 0x86, 0x82, 0x85, 0x81, 0x82, 0x83, 0x84, 0x8e,
+	  0x8b, 0x83, 0xa4, 0xa3, 0x8a, 0xa1, 0x93, 0x9d, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83,
+	  0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x82, 0x82, 0x84, 0x8e,
+	  0x8b, 0x83, 0xa4, 0xa2, 0x86, 0xc1, 0xa9, 0xb7, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83,
+	  0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x82, 0x82, 0x84, 0x8d,
+	  0x89, 0x82, 0xa2, 0xa1, 0x84, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83,
+	  0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x83, 0x83, 0x85, 0x8c,
+	  0x87, 0x7f, 0xa2, 0x9d, 0x88, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xbb, 0x00, 0xc5, 0x00, 0xb4, 0x87, 0x86, 0x86, 0x84, 0x83,
+	  0x86, 0x87, 0x87, 0x87, 0x80, 0x82, 0x7f, 0x86, 0x86, 0x88, 0x8a,
+	  0x84, 0x7e, 0x9d, 0x9c, 0x82, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xbd, 0x00, 0xc7, 0x00, 0xb7, 0x87, 0x85, 0x85, 0x84, 0x83,
+	  0x86, 0x86, 0x86, 0x88, 0x81, 0x83, 0x80, 0x83, 0x84, 0x85, 0x8a,
+	  0x85, 0x7e, 0x9c, 0x9b, 0x85, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xc0, 0x00, 0xca, 0x00, 0xbb, 0x87, 0x86, 0x85, 0x83, 0x83,
+	  0x85, 0x86, 0x86, 0x88, 0x81, 0x83, 0x80, 0x84, 0x85, 0x86, 0x89,
+	  0x83, 0x7d, 0x9c, 0x99, 0x87, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xc4, 0x00, 0xcd, 0x00, 0xbe, 0x87, 0x86, 0x85, 0x83, 0x83,
+	  0x86, 0x85, 0x85, 0x87, 0x81, 0x82, 0x80, 0x82, 0x82, 0x83, 0x8a,
+	  0x85, 0x7f, 0x9f, 0x9b, 0x86, 0xb4, 0xa1, 0xac, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xc7, 0x00, 0xd0, 0x00, 0xc2, 0x87, 0x85, 0x85, 0x83, 0x82,
+	  0x85, 0x85, 0x85, 0x86, 0x82, 0x83, 0x80, 0x82, 0x82, 0x84, 0x87,
+	  0x86, 0x80, 0x9e, 0x9a, 0x87, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xca, 0x00, 0xd2, 0x00, 0xc5, 0x87, 0x85, 0x84, 0x82, 0x82,
+	  0x84, 0x85, 0x85, 0x86, 0x81, 0x82, 0x7f, 0x82, 0x82, 0x84, 0x88,
+	  0x86, 0x81, 0x9d, 0x98, 0x86, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xce, 0x00, 0xd6, 0x00, 0xca, 0x86, 0x85, 0x84, 0x83, 0x83,
+	  0x85, 0x84, 0x84, 0x85, 0x81, 0x82, 0x80, 0x81, 0x81, 0x82, 0x89,
+	  0x86, 0x81, 0x9c, 0x97, 0x86, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xd1, 0x00, 0xd9, 0x00, 0xce, 0x86, 0x84, 0x83, 0x83, 0x82,
+	  0x85, 0x85, 0x85, 0x86, 0x81, 0x83, 0x81, 0x82, 0x82, 0x83, 0x86,
+	  0x83, 0x7f, 0x99, 0x95, 0x86, 0xbb, 0xa4, 0xb3, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xd4, 0x00, 0xdb, 0x00, 0xd1, 0x86, 0x85, 0x83, 0x83, 0x82,
+	  0x85, 0x84, 0x84, 0x85, 0x80, 0x83, 0x82, 0x80, 0x80, 0x81, 0x87,
+	  0x84, 0x81, 0x98, 0x93, 0x85, 0xae, 0x9c, 0xa8, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xd8, 0x00, 0xde, 0x00, 0xd6, 0x86, 0x84, 0x83, 0x81, 0x81,
+	  0x83, 0x85, 0x85, 0x85, 0x82, 0x83, 0x81, 0x81, 0x81, 0x83, 0x86,
+	  0x84, 0x80, 0x98, 0x91, 0x85, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xdc, 0x00, 0xe2, 0x00, 0xda, 0x85, 0x84, 0x83, 0x82, 0x82,
+	  0x84, 0x84, 0x84, 0x85, 0x81, 0x82, 0x82, 0x80, 0x80, 0x81, 0x83,
+	  0x82, 0x7f, 0x99, 0x93, 0x86, 0x94, 0x8b, 0x92, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xdf, 0x00, 0xe5, 0x00, 0xde, 0x85, 0x84, 0x82, 0x82, 0x82,
+	  0x84, 0x83, 0x83, 0x84, 0x81, 0x81, 0x80, 0x83, 0x82, 0x84, 0x82,
+	  0x81, 0x7f, 0x99, 0x92, 0x86, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
+	  0x82, 0x83, 0x83, 0x84, 0x80, 0x81, 0x80, 0x83, 0x83, 0x84, 0x80,
+	  0x81, 0x7c, 0x99, 0x92, 0x87, 0xa1, 0x93, 0x9d, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x85, 0x84, 0x83, 0x81, 0x81,
+	  0x82, 0x82, 0x82, 0x83, 0x80, 0x81, 0x80, 0x81, 0x80, 0x82, 0x83,
+	  0x82, 0x80, 0x91, 0x8d, 0x83, 0x9a, 0x90, 0x96, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
+	  0x82, 0x83, 0x83, 0x84, 0x80, 0x81, 0x80, 0x81, 0x80, 0x82, 0x83,
+	  0x81, 0x7f, 0x91, 0x8c, 0x82, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
+	  0x82, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x80, 0x82, 0x82,
+	  0x82, 0x7f, 0x94, 0x89, 0x84, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
+	  0x82, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x80, 0x82, 0x83,
+	  0x82, 0x7f, 0x91, 0x85, 0x81, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81,
+	  0x82, 0x83, 0x83, 0x83, 0x80, 0x80, 0x7f, 0x83, 0x82, 0x84, 0x83,
+	  0x82, 0x7f, 0x90, 0x84, 0x81, 0x9a, 0x90, 0x96, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x80, 0x80,
+	  0x82, 0x83, 0x83, 0x83, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x81, 0x81,
+	  0x82, 0x83, 0x7e, 0x80, 0x7c, 0xa4, 0x97, 0x9f, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xe9, 0x00, 0xec, 0x00, 0xe8, 0x84, 0x83, 0x82, 0x81, 0x81,
+	  0x82, 0x82, 0x82, 0x83, 0x7f, 0x7f, 0x7f, 0x81, 0x80, 0x82, 0x83,
+	  0x83, 0x84, 0x79, 0x7c, 0x79, 0xb1, 0xa0, 0xaa, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xed, 0x00, 0xf0, 0x00, 0xec, 0x83, 0x83, 0x82, 0x80, 0x80,
+	  0x81, 0x82, 0x82, 0x82, 0x7f, 0x7f, 0x7e, 0x81, 0x81, 0x82, 0x80,
+	  0x81, 0x81, 0x84, 0x84, 0x83, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xf1, 0x00, 0xf4, 0x00, 0xf1, 0x83, 0x82, 0x82, 0x80, 0x80,
+	  0x81, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x7d,
+	  0x7e, 0x7f, 0x84, 0x84, 0x83, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xf6, 0x00, 0xf7, 0x00, 0xf5, 0x82, 0x82, 0x81, 0x80, 0x80,
+	  0x80, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x82,
+	  0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x00, 0xfa, 0x00, 0xfb, 0x00, 0xfa, 0x81, 0x81, 0x81, 0x80, 0x80,
+	  0x80, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80,
+	  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
+	  0x00, 0x00 },
+	{ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80,
+	  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+	  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
+	  0x00, 0x00 }
+};
+
+unsigned char VINT_TABLE[S6E3HA2_VINT_STATUS_MAX] = {
+	0x18, 0x19, 0x1a, 0x1b, 0x1c,
+	0x1d, 0x1e, 0x1f, 0x20, 0x21
+};
+
+struct s6e3ha2 {
+	struct device *dev;
+	struct drm_panel panel;
+	struct backlight_device *bl_dev;
+
+	struct regulator_bulk_data supplies[2];
+	struct gpio_desc *reset_gpio;
+	struct gpio_desc *enable_gpio;
+	u32 power_on_delay;
+	u32 reset_delay;
+	struct videomode vm;
+
+	/* This field is tested by functions directly accessing DSI bus before
+	 * transfer, transfer is skipped if it is set. In case of transfer
+	 * failure or unexpected response the field is set to error value.
+	 * Such construct allows to eliminate many checks in higher level
+	 * functions.
+	 */
+	int error;
+};
+
+static int  s6e3ha2_clear_error(struct s6e3ha2 *ctx)
+{
+	int ret = ctx->error;
+
+	ctx->error = 0;
+	return ret;
+}
+
+static void s6e3ha2_dcs_write(struct s6e3ha2 *ctx, const void *data, size_t len)
+{
+	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+	ssize_t ret;
+
+	if (ctx->error < 0)
+		return;
+
+	ret = mipi_dsi_dcs_write_buffer(dsi, data, len);
+	if (ret < 0) {
+		dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n",
+						ret, (int)len, data);
+		ctx->error = ret;
+	}
+}
+
+#define s6e3ha2_dcs_write_seq_static(ctx, seq...) do {	\
+	static const u8 d[] = { seq };			\
+	s6e3ha2_dcs_write(ctx, d, ARRAY_SIZE(d));	\
+} while (0)
+
+static void s6e3ha2_test_key_on_f0(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0xf0, 0x5a, 0x5a);
+}
+
+static void s6e3ha2_test_key_off_f0(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0xf0, 0xa5, 0xa5);
+}
+
+static void s6e3ha2_test_key_on_fc(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0xfc, 0x5a, 0x5a);
+}
+
+static void s6e3ha2_test_key_off_fc(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0xfc, 0xa5, 0xa5);
+}
+
+static void s6e3ha2_single_dsi_set(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0xf2, 0x67);
+	s6e3ha2_dcs_write_seq_static(ctx, 0xf9, 0x09);
+}
+
+static void s6e3ha2_freq_calibration(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0xfd, 0x1c);
+	s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x20, 0x39);
+	s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0xa0);
+	s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x20);
+	s6e3ha2_dcs_write_seq_static(ctx, 0xce, 0x03, 0x3b, 0x12, 0x62,
+		0x40, 0x80, 0xc0, 0x28, 0x28, 0x28, 0x28, 0x39, 0xc5);
+}
+
+static void s6e3ha2_aor_control(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0xb2, 0x03, 0x10);
+}
+
+static void s6e3ha2_caps_elvss_set(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0xb6, 0x9c, 0x0a);
+}
+
+static void s6e3ha2_acl_off(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0x55, 0x00);
+}
+
+static void s6e3ha2_acl_off_opr(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0xb5, 0x40);
+}
+
+static void s6e3ha2_test_global(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0xb0, 0x07);
+}
+
+static void s6e3ha2_test(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0xb8, 0x19);
+}
+
+static void s6e3ha2_touch_hsync_on1(struct s6e3ha2 *ctx) {
+	s6e3ha2_dcs_write_seq_static(ctx,
+			0xbd, 0x33, 0x11, 0x02, 0x16, 0x02, 0x16);
+}
+
+static void s6e3ha2_pentile_control(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0xc0, 0x00, 0x00, 0xd8, 0xd8);
+}
+
+static void s6e3ha2_poc_global(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0xb0, 0x20);
+}
+
+static void s6e3ha2_poc_setting(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x08);
+}
+
+static void s6e3ha2_pcd_set_off(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0xcc, 0x40, 0x51);
+}
+
+static void s6e3ha2_err_fg_set(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0xed, 0x44);
+}
+
+static void s6e3ha2_hbm_off(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0x53, 0x00);
+}
+
+static void s6e3ha2_te_start_setting(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0xb9, 0x10, 0x09, 0xff, 0x00, 0x09);
+}
+
+static void s6e3ha2_gamma_update(struct s6e3ha2 *ctx)
+{
+	s6e3ha2_dcs_write_seq_static(ctx, 0xf7, 0x03);
+	ndelay(100); /* need for 100ns delay */
+	s6e3ha2_dcs_write_seq_static(ctx, 0xf7, 0x00);
+}
+
+static int s6e3ha2_get_brightness(struct backlight_device *bl_dev)
+{
+	return bl_dev->props.brightness;
+}
+
+static void s6e3ha2_set_vint(struct s6e3ha2 *ctx) {
+	struct backlight_device *bl_dev = ctx->bl_dev;
+	unsigned int brightness = bl_dev->props.brightness;
+	unsigned char data[] = { 0xf4, 0x8b,
+			VINT_TABLE[brightness * (S6E3HA2_VINT_STATUS_MAX - 1) /
+			S6E3HA2_MAX_BRIGHTNESS] };
+
+	s6e3ha2_dcs_write(ctx, data, 3);
+}
+
+static unsigned int s6e3ha2_get_brightness_index(unsigned int brightness)
+{
+	return (brightness * (S6E3HA2_NUM_GAMMA_STEPS - 1)) /
+		S6E3HA2_MAX_BRIGHTNESS;
+}
+
+static int s6e3ha2_update_gamma(struct s6e3ha2 *ctx, unsigned int brightness)
+{
+	struct backlight_device *bl_dev = ctx->bl_dev;
+	unsigned int index = s6e3ha2_get_brightness_index(brightness);
+	u8 data[S6E3HA2_GAMMA_CMD_CNT + 1] = { 0xca, };
+
+	memcpy(data + 1, gamma_tbl + index, S6E3HA2_GAMMA_CMD_CNT);
+	s6e3ha2_dcs_write(ctx, data, ARRAY_SIZE(data));
+
+	s6e3ha2_gamma_update(ctx);
+	bl_dev->props.brightness = brightness;
+
+	return 0;
+}
+
+static int s6e3ha2_set_brightness(struct backlight_device *bl_dev)
+{
+	struct s6e3ha2 *ctx = (struct s6e3ha2 *)bl_get_data(bl_dev);
+	unsigned int brightness = bl_dev->props.brightness;
+
+	if (brightness < S6E3HA2_MIN_BRIGHTNESS ||
+		brightness > bl_dev->props.max_brightness) {
+		dev_err(ctx->dev, "Invalid brightness: %u\n", brightness);
+		return -EINVAL;
+	}
+
+	if (bl_dev->props.power > FB_BLANK_NORMAL) {
+		dev_err(ctx->dev,
+			"panel must be at least in fb blank normal state\n");
+		return -EPERM;
+	}
+
+	s6e3ha2_test_key_on_f0(ctx);
+	s6e3ha2_update_gamma(ctx, brightness);
+	s6e3ha2_aor_control(ctx);
+	s6e3ha2_set_vint(ctx);
+	s6e3ha2_test_key_off_f0(ctx);
+
+	return ctx->error;
+}
+
+static const struct backlight_ops s6e3ha2_bl_ops = {
+	.get_brightness = s6e3ha2_get_brightness,
+	.update_status = s6e3ha2_set_brightness,
+};
+
+static void s6e3ha2_panel_init(struct s6e3ha2 *ctx)
+{
+	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+	u32 reset_delay = ctx->reset_delay * 1000;
+
+	mipi_dsi_dcs_exit_sleep_mode(dsi);
+	usleep_range(reset_delay, reset_delay + 1000);
+
+	s6e3ha2_test_key_on_f0(ctx);
+	s6e3ha2_single_dsi_set(ctx);
+	s6e3ha2_test_key_on_fc(ctx);
+	s6e3ha2_freq_calibration(ctx);
+	s6e3ha2_test_key_off_fc(ctx);
+	s6e3ha2_test_key_off_f0(ctx);
+}
+
+static int s6e3ha2_power_off(struct s6e3ha2 *ctx)
+{
+	return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+}
+
+static int s6e3ha2_disable(struct drm_panel *panel)
+{
+	struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
+	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+
+	mipi_dsi_dcs_enter_sleep_mode(dsi);
+	if (ctx->error != 0)
+		goto err;
+
+	mipi_dsi_dcs_set_display_off(dsi);
+	if (ctx->error != 0)
+		goto err;
+
+	msleep(40);
+	ctx->bl_dev->props.power = FB_BLANK_NORMAL;
+
+	return 0;
+err:
+	return ctx->error;
+}
+
+static int s6e3ha2_unprepare(struct drm_panel *panel)
+{
+	struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
+	int ret;
+
+	ret = s6e3ha2_clear_error(ctx);
+	if (!ret)
+		ctx->bl_dev->props.power = FB_BLANK_POWERDOWN;
+
+	return s6e3ha2_power_off(ctx);
+}
+
+static int s6e3ha2_power_on(struct s6e3ha2 *ctx)
+{
+	u32 reset_delay = ctx->reset_delay * 1000;
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+	if (ret < 0)
+		return ret;
+
+	msleep(ctx->power_on_delay);
+
+	gpiod_set_value(ctx->enable_gpio, 0);
+	usleep_range(reset_delay, reset_delay + 1000);
+	gpiod_set_value(ctx->enable_gpio, 1);
+
+	gpiod_set_value(ctx->reset_gpio, 0);
+	usleep_range(reset_delay, reset_delay + 1000);
+	gpiod_set_value(ctx->reset_gpio, 1);
+	usleep_range(reset_delay, reset_delay + 1000);
+
+	return 0;
+}
+static int s6e3ha2_prepare(struct drm_panel *panel)
+{
+	struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
+	int ret;
+
+	ret = s6e3ha2_power_on(ctx);
+	if (ret < 0)
+		return ret;
+
+	s6e3ha2_panel_init(ctx);
+
+	ret = s6e3ha2_clear_error(ctx);
+	if (ret < 0) {
+		s6e3ha2_power_off(ctx);
+		return ret;
+	}
+
+	ctx->bl_dev->props.power = FB_BLANK_NORMAL;
+
+	return 0;
+}
+
+static int s6e3ha2_enable(struct drm_panel *panel)
+{
+	struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
+	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+
+	/* common setting */
+	mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
+
+	s6e3ha2_test_key_on_f0(ctx);
+	s6e3ha2_test_key_on_fc(ctx);
+	s6e3ha2_touch_hsync_on1(ctx);
+	s6e3ha2_pentile_control(ctx);
+	s6e3ha2_poc_global(ctx);
+	s6e3ha2_poc_setting(ctx);
+	s6e3ha2_test_key_off_fc(ctx);
+
+	/* pcd setting off for TB */
+	s6e3ha2_pcd_set_off(ctx);
+	s6e3ha2_err_fg_set(ctx);
+	s6e3ha2_te_start_setting(ctx);
+
+	/* brightness setting */
+	s6e3ha2_set_brightness(ctx->bl_dev);
+	s6e3ha2_aor_control(ctx);
+	s6e3ha2_caps_elvss_set(ctx);
+	s6e3ha2_gamma_update(ctx);
+	s6e3ha2_acl_off(ctx);
+	s6e3ha2_acl_off_opr(ctx);
+	s6e3ha2_hbm_off(ctx);
+
+	/* elvss temp compensation */
+	s6e3ha2_test_global(ctx);
+	s6e3ha2_test(ctx);
+	s6e3ha2_test_key_off_f0(ctx);
+
+	mipi_dsi_dcs_set_display_on(dsi);
+	if (ctx->error != 0)
+		return ctx->error;
+
+	ctx->bl_dev->props.power = FB_BLANK_UNBLANK;
+
+	return 0;
+}
+
+static int s6e3ha2_get_modes(struct drm_panel *panel)
+{
+	struct drm_connector *connector = panel->connector;
+	struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel);
+	struct drm_display_mode *mode;
+
+	mode = drm_mode_create(connector->dev);
+	if (!mode) {
+		DRM_ERROR("failed to create a new display mode\n");
+		return 0;
+	}
+
+	drm_display_mode_from_videomode(&ctx->vm, mode);
+	mode->vrefresh = 60;
+	mode->width_mm = 71;
+	mode->height_mm = 125;
+	connector->display_info.width_mm = mode->width_mm;
+	connector->display_info.height_mm = mode->height_mm;
+
+	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+	drm_mode_probed_add(connector, mode);
+
+	return 1;
+}
+
+static const struct drm_panel_funcs s6e3ha2_drm_funcs = {
+	.disable = s6e3ha2_disable,
+	.unprepare = s6e3ha2_unprepare,
+	.prepare = s6e3ha2_prepare,
+	.enable = s6e3ha2_enable,
+	.get_modes = s6e3ha2_get_modes,
+};
+
+static int s6e3ha2_parse_dt(struct s6e3ha2 *ctx)
+{
+	struct device *dev = ctx->dev;
+	struct device_node *np = dev->of_node;
+	int ret;
+
+	ret = of_get_videomode(dev->of_node, &ctx->vm, 0);
+	if (ret < 0)
+		return ret;
+
+	of_property_read_u32(np, "power-on-delay", &ctx->power_on_delay);
+	of_property_read_u32(np, "reset-delay", &ctx->reset_delay);
+
+	return 0;
+}
+
+static int s6e3ha2_probe(struct mipi_dsi_device *dsi)
+{
+	struct device *dev = &dsi->dev;
+	struct s6e3ha2 *ctx;
+	int ret;
+
+	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	mipi_dsi_set_drvdata(dsi, ctx);
+
+	ctx->dev = dev;
+
+	dsi->lanes = 4;
+	dsi->format = MIPI_DSI_FMT_RGB888;
+	dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS;
+
+	ret = s6e3ha2_parse_dt(ctx);
+	if (ret < 0)
+		return ret;
+
+	ctx->supplies[0].supply = "vdd3";
+	ctx->supplies[1].supply = "vci";
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
+				      ctx->supplies);
+	if (ret < 0) {
+		dev_err(dev, "failed to get regulators: %d\n", ret);
+		return ret;
+	}
+
+	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(ctx->reset_gpio)) {
+		dev_err(dev, "cannot get reset-gpios %ld\n",
+			PTR_ERR(ctx->reset_gpio));
+		return PTR_ERR(ctx->reset_gpio);
+	}
+
+	ctx->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
+	if (IS_ERR(ctx->enable_gpio)) {
+		dev_err(dev, "cannot get enable-gpios %ld\n",
+			PTR_ERR(ctx->enable_gpio));
+		return PTR_ERR(ctx->enable_gpio);
+	}
+
+	ctx->bl_dev = backlight_device_register("s6e3ha2", dev, ctx,
+						&s6e3ha2_bl_ops, NULL);
+	if (IS_ERR(ctx->bl_dev)) {
+		dev_err(dev, "failed to register backlight device\n");
+		return PTR_ERR(ctx->bl_dev);
+	}
+
+	ctx->bl_dev->props.max_brightness = S6E3HA2_MAX_BRIGHTNESS;
+	ctx->bl_dev->props.brightness = S6E3HA2_DEFAULT_BRIGHTNESS;
+	ctx->bl_dev->props.power = FB_BLANK_POWERDOWN;
+
+	drm_panel_init(&ctx->panel);
+	ctx->panel.dev = dev;
+	ctx->panel.funcs = &s6e3ha2_drm_funcs;
+
+	ret = drm_panel_add(&ctx->panel);
+	if (ret < 0)
+		goto unregister_backlight;
+
+	ret = mipi_dsi_attach(dsi);
+	if (ret < 0)
+		goto remove_panel;
+
+	return ret;
+
+remove_panel:
+	drm_panel_remove(&ctx->panel);
+
+unregister_backlight:
+	backlight_device_unregister(ctx->bl_dev);
+
+	return ret;
+}
+
+static int s6e3ha2_remove(struct mipi_dsi_device *dsi)
+{
+	struct s6e3ha2 *ctx = mipi_dsi_get_drvdata(dsi);
+
+	mipi_dsi_detach(dsi);
+	drm_panel_remove(&ctx->panel);
+	backlight_device_unregister(ctx->bl_dev);
+
+	return 0;
+}
+
+static const struct of_device_id s6e3ha2_of_match[] = {
+	{ .compatible = "samsung,s6e3ha2" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, s6e3ha2_of_match);
+
+static struct mipi_dsi_driver s6e3ha2_driver = {
+	.probe = s6e3ha2_probe,
+	.remove = s6e3ha2_remove,
+	.driver = {
+		.name = "panel-samsung-s6e3ha2",
+		.of_match_table = s6e3ha2_of_match,
+	},
+};
+module_mipi_dsi_driver(s6e3ha2_driver);
+
+MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
+MODULE_AUTHOR("Hyungwon Hwang <human.hwang@samsung.com>");
+MODULE_AUTHOR("Hoegeun Kwon <hoegeun.kwon@samsung.com>");
+MODULE_DESCRIPTION("MIPI-DSI based s6e3ha2 AMOLED Panel Driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related

* [PATCH 0/2] Add support for the S6E3HA2 panel on TM2 board
From: Hoegeun Kwon @ 2016-12-14  6:04 UTC (permalink / raw)
  To: thierry.reding, kgene, krzk
  Cc: devicetree, linux-samsung-soc, linux-kernel, dri-devel,
	Hoegeun Kwon

Purpose of this patch is add support for S6E3HA2 AMOLED panel on
the TM2 board. The first patch adds support for S6E3HA2 panel
device tree document and driver, the second patch add support for
S6E3HA2 panel device tree.

Hoegeun Kwon (1):
  drm/panel: Add support for S6E3HA2 panel driver on TM2 board

Hyungwon Hwang (1):
  arm64: dts: exynos: Add support for S6E3HA2 panel device on TM2 board

 .../bindings/display/panel/samsung,s6e3ha2.txt     |  52 ++
 arch/arm64/boot/dts/exynos/exynos5433-tm2.dts      |  33 +
 drivers/gpu/drm/panel/Kconfig                      |   6 +
 drivers/gpu/drm/panel/Makefile                     |   1 +
 drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c      | 756 +++++++++++++++++++++
 5 files changed, 848 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/samsung,s6e3ha2.txt
 create mode 100644 drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c

-- 
1.9.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* Re: [PATCH v7 3/5] drm: bridge: add support for TI ths8135
From: Archit Taneja @ 2016-12-14  5:05 UTC (permalink / raw)
  To: Bartosz Golaszewski, Jyri Sarha, Tomi Valkeinen, David Airlie,
	Kevin Hilman, Michael Turquette, Sekhar Nori, Rob Herring,
	Frank Rowand, Mark Rutland, Laurent Pinchart, Peter Ujfalusi,
	Russell King, Maxime Ripard
  Cc: linux-devicetree, linux-drm, LKML, arm-soc
In-Reply-To: <1481623759-12786-4-git-send-email-bgolaszewski@baylibre.com>



On 12/13/2016 03:39 PM, Bartosz Golaszewski wrote:
> THS8135 is a configurable video DAC, but no configuration is actually
> necessary to make it work.
>
> For now use the dumb-vga-dac driver to support it.

Queued to drm-misc-next

Archit

>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  drivers/gpu/drm/bridge/dumb-vga-dac.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c
> index e570698..86e9f9c 100644
> --- a/drivers/gpu/drm/bridge/dumb-vga-dac.c
> +++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c
> @@ -237,6 +237,7 @@ static int dumb_vga_remove(struct platform_device *pdev)
>
>  static const struct of_device_id dumb_vga_match[] = {
>  	{ .compatible = "dumb-vga-dac" },
> +	{ .compatible = "ti,ths8135" },
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, dumb_vga_match);
>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* Re: [PATCH v7 2/5] drm: bridge: add DT bindings for TI ths8135
From: Archit Taneja @ 2016-12-14  5:04 UTC (permalink / raw)
  To: Bartosz Golaszewski, Jyri Sarha, Tomi Valkeinen, David Airlie,
	Kevin Hilman, Michael Turquette, Sekhar Nori, Rob Herring,
	Frank Rowand, Mark Rutland, Laurent Pinchart, Peter Ujfalusi,
	Russell King, Maxime Ripard
  Cc: linux-devicetree, linux-drm, LKML, arm-soc
In-Reply-To: <1481623759-12786-3-git-send-email-bgolaszewski@baylibre.com>

Hi,

On 12/13/2016 03:39 PM, Bartosz Golaszewski wrote:
> THS8135 is a configurable video DAC. Add DT bindings for this chip.

Queued to drm-misc-next
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Acked-by: Rob Herring <robh@kernel.org>
> ---
>  .../bindings/display/bridge/ti,ths8135.txt         | 46 ++++++++++++++++++++++
>  1 file changed, 46 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt
>
> diff --git a/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt b/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt
> new file mode 100644
> index 0000000..6ec1a88
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/bridge/ti,ths8135.txt
> @@ -0,0 +1,46 @@
> +THS8135 Video DAC
> +-----------------
> +
> +This is the binding for Texas Instruments THS8135 Video DAC bridge.
> +
> +Required properties:
> +
> +- compatible: Must be "ti,ths8135"
> +
> +Required nodes:
> +
> +This device has two video ports. Their connections are modelled using the OF
> +graph bindings specified in Documentation/devicetree/bindings/graph.txt.
> +
> +- Video port 0 for RGB input
> +- Video port 1 for VGA output
> +
> +Example
> +-------
> +
> +vga-bridge {
> +	compatible = "ti,ths8135";
> +	#address-cells = <1>;
> +	#size-cells = <0>;
> +
> +	ports {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		port@0 {
> +			reg = <0>;
> +
> +			vga_bridge_in: endpoint {
> +				remote-endpoint = <&lcdc_out_vga>;
> +			};
> +		};
> +
> +		port@1 {
> +			reg = <1>;
> +
> +			vga_bridge_out: endpoint {
> +				remote-endpoint = <&vga_con_in>;
> +			};
> +		};
> +	};
> +};
>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* [PATCH v3 2/2] drm/panel: simple: Add support BOE nv101wxmn51
From: Caesar Wang @ 2016-12-14  3:19 UTC (permalink / raw)
  To: thierry.reding
  Cc: devicetree, linux-kernel, dri-devel, dianders, robh+dt,
	Caesar Wang
In-Reply-To: <1481685596-15608-1-git-send-email-wxt@rock-chips.com>

10.1WXGA is a color active matrix TFT LCD module using amorphous silicon
TFT's as an active switching devices. It can be supported by the
simple-panel driver.

Read the panel default edid information:

EDID MODE DETAILS
                name = <NULL>
                pixel_clock = 71900
                lvds_dual_channel = 0
                refresh = 0
                ha = 1280
                hbl = 160
                hso = 48
                hspw = 32
                hborder = 0
                va = 800
                vbl = 32
                vso = 3
                vspw = 5
                vborder = 0
                phsync = +
                pvsync = -
                x_mm = 0
                y_mm = 0
drm_display_mode
                .hdisplay = 1280
                .hsync_start = 1328
                .hsync_end = 1360
                .htotal = 1440
                .vdisplay = 800
                .vsync_start = 803
                .vsync_end = 808
                .vtotal = 832

There are two modes in the edid:
Detailed mode1: Clock 71.900 MHz, 216 mm x 135 mm
               1280 1328 1360 1440 hborder 0
                800  803  808  832 vborder 0
               +hsync -vsync
Detailed mode2: Clock 57.500 MHz, 216 mm x 135 mm
               1280 1328 1360 1440 hborder 0
                800  803  808  832 vborder 0
               +hsync -vsync

Add the both edid to support more modes for BOE nv101wxmn51.

Signed-off-by: Caesar Wang <wxt@rock-chips.com>
---

Changes in v3:
- As Stéphane commented on https://patchwork.kernel.org/patch/9465911,
  add downclock mode for edid.

Changes in v2:
- fix the vsync_start and vsync_end from the edid.
- change the commit.

 drivers/gpu/drm/panel/panel-simple.c | 45 ++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index 06aaf79..1ce25b5 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -668,6 +668,48 @@ static const struct panel_desc avic_tm070ddh03 = {
 	},
 };
 
+static const struct drm_display_mode boe_nv101wxmn51_modes[] = {
+	{
+		.clock = 71900,
+		.hdisplay = 1280,
+		.hsync_start = 1280 + 48,
+		.hsync_end = 1280 + 48 + 32,
+		.htotal = 1280 + 48 + 32 + 80,
+		.vdisplay = 800,
+		.vsync_start = 800 + 3,
+		.vsync_end = 800 + 3 + 5,
+		.vtotal = 800 + 3 + 5 + 24,
+		.vrefresh = 60,
+	},
+	{
+		.clock = 57500,
+		.hdisplay = 1280,
+		.hsync_start = 1280 + 48,
+		.hsync_end = 1280 + 48 + 32,
+		.htotal = 1280 + 48 + 32 + 80,
+		.vdisplay = 800,
+		.vsync_start = 800 + 3,
+		.vsync_end = 800 + 3 + 5,
+		.vtotal = 800 + 3 + 5 + 24,
+		.vrefresh = 48,
+	},
+};
+
+static const struct panel_desc boe_nv101wxmn51 = {
+	.modes = boe_nv101wxmn51_modes,
+	.num_modes = ARRAY_SIZE(boe_nv101wxmn51_modes),
+	.bpc = 8,
+	.size = {
+		.width = 217,
+		.height = 136,
+	},
+	.delay = {
+		.prepare = 210,
+		.enable = 50,
+		.unprepare = 160,
+	},
+};
+
 static const struct drm_display_mode chunghwa_claa070wp03xg_mode = {
 	.clock = 66770,
 	.hdisplay = 800,
@@ -1748,6 +1790,9 @@ static const struct of_device_id platform_of_match[] = {
 		.compatible = "avic,tm070ddh03",
 		.data = &avic_tm070ddh03,
 	}, {
+		.compatible = "boe,nv101wxmn51",
+		.data = &boe_nv101wxmn51,
+	}, {
 		.compatible = "chunghwa,claa070wp03xg",
 		.data = &chunghwa_claa070wp03xg,
 	}, {
-- 
2.7.4

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related

* [PATCH v3 1/2] dt-bindings: display: Add BOE nv101wxmn51 panel binding
From: Caesar Wang @ 2016-12-14  3:19 UTC (permalink / raw)
  To: thierry.reding
  Cc: devicetree, linux-kernel, dri-devel, dianders, robh+dt,
	Caesar Wang

The BOE 10.1" NV101WXMN51 panel is an WXGA TFT LCD panel.

Signed-off-by: Caesar Wang <wxt@rock-chips.com>
---

Changes in v3: None
Changes in v2: None

 .../devicetree/bindings/display/panel/boe,nv101wxmn51.txt          | 7 +++++++
 1 file changed, 7 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/boe,nv101wxmn51.txt

diff --git a/Documentation/devicetree/bindings/display/panel/boe,nv101wxmn51.txt b/Documentation/devicetree/bindings/display/panel/boe,nv101wxmn51.txt
new file mode 100644
index 0000000..b258d6a
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/boe,nv101wxmn51.txt
@@ -0,0 +1,7 @@
+BOE OPTOELECTRONICS TECHNOLOGY 10.1" WXGA TFT LCD panel
+
+Required properties:
+- compatible: should be "boe,nv101wxmn51"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
-- 
2.7.4

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related

* (unknown), 
From: Mr Friedrich Mayrhofer @ 2016-12-14  2:45 UTC (permalink / raw)



Good Day,

This is the second time i am sending you this mail.

I, Friedrich Mayrhofer Donate $ 1,000,000.00 to You, Email Me
personally for more details.

Regards.
Friedrich Mayrhofer






--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v5 2/2] mmc: sdhci-cadence: add Cadence SD4HC support
From: Masahiro Yamada @ 2016-12-14  2:27 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Rob Herring, linux-mmc, Adrian Hunter, Douglas Anderson,
	devicetree@vger.kernel.org, Al Cooper, Linux Kernel Mailing List,
	Stefan Wahren, Andrei Pistirica, Wolfram Sang, Mark Rutland,
	Simon Horman
In-Reply-To: <CAPDyKFrejOSGVWb=gsuCixxj_OXfLfo22VwLDC_Y4scw+Se8FQ@mail.gmail.com>

Hi Ulf,

2016-12-13 16:52 GMT+09:00 Ulf Hansson <ulf.hansson@linaro.org>:
> [...]
>
>>>> +
>>>> +Optional properties:
>>>> +For eMMC configuration, supported speed modes are not indicated by the SDHCI
>>>> +Capabilities Register.  Instead, the following properties should be specified
>>>> +if supported.  See mmc.txt for details.
>>>> +- mmc-ddr-1_8v
>>>> +- mmc-ddr-1_2v
>>>> +- mmc-hs200-1_8v
>>>> +- mmc-hs200-1_2v
>>>> +- mmc-hs400-1_8v
>>>> +- mmc-hs400-1_2v
>>>
>>> There's now a property to override SDHCI capabilities register. Maybe
>>> you should use that instead? I'll defer to Ulf.
>>>
>>
>> I did not know this new property.
>>
>> So, now we have two ways to specify MMC speed mode capabilities
>> by only touching DT.
>
> Let me clarify a bit.
>
> The point with the new bindings is to be able to override *broken*
> SDHCI caps bits. So, not only related to the speed modes.

Right.

So my approach ([1] Add MMC mode flags directly)
basically sounds OK.



>>
>> [1] Add MMC mode flags directly, like I did.
>> [2] Use "sdhci-caps-mask" and "sdhci-caps"
>>
>>
>> The problem for [2] is that eMMC capabilities
>> do not perfectly correspond to the SDHCI capabilities register.
>>
>>
>>>> +- mmc-hs400-1_8v
>>>> +- mmc-hs400-1_2v
>>
>> If the driver sets SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400,
>> we can use the bit63 of caps for specifying HS400.
>>
>> But, this is not defined in the SDHCI standard.
>> #define  SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */
>>
>>
>>
>>>> +- mmc-ddr-1_8v
>>
>> For High Speed DDR, perhaps we can imply MMC_CAP_1_8V_DDR
>> from MMC_CAP_UHS_DDR50  (bit34 of caps)
>>
>> This is not supported in the current code, but
>> if this is a good idea, I can send a patch.
>>
>>
>>>> +- mmc-ddr-1_2v
>>
>> This does not have the corresponding bit, but
>> 1.2V is not commonly used, so this is not a fatal problem.
>>
>>
>>
>> What I can do at most now, is to delete the
>> Optional properties section entirely
>> so users can choose [1] or [2] as they like.
>>
>
> I think a better approach is to use the new sdhci-caps* bindings to
> mask those caps that can't be trusted. And then use the generic mmc
> bindings for speed modes instead.
>
> That should be a safer approach, right!?

Right.

But, if I know the caps register bits 63-32 are all zero,
I need not explicitly specify sdhci-caps-mask, right?



-- 
Best Regards
Masahiro Yamada

^ permalink raw reply

* Re: [PATCH] mmc: sdhci-cadence: add SoC specific compatible string
From: Masahiro Yamada @ 2016-12-14  2:12 UTC (permalink / raw)
  To: linux-mmc
  Cc: Rob Herring, Adrian Hunter, Ulf Hansson, Masahiro Yamada,
	devicetree, Linux Kernel Mailing List, Rob Herring, Mark Rutland
In-Reply-To: <1481680795-15697-1-git-send-email-yamada.masahiro@socionext.com>

2016-12-14 10:59 GMT+09:00 Masahiro Yamada <yamada.masahiro@socionext.com>:
> Add a Socionext SoC specific compatible (suggested by Rob Herring).
>
> No SoC specific data are associated with the compatible strings for
> now, but other SoC vendors may use this IP and want to differentiate
> IP variants in the future.
>
> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

I thought adding SoC family name ("uniphier") would be better.

I've just sent v2.




-- 
Best Regards
Masahiro Yamada

^ permalink raw reply

* [PATCH v2] mmc: sdhci-cadence: add Socionext UniPhier specific compatible string
From: Masahiro Yamada @ 2016-12-14  2:10 UTC (permalink / raw)
  To: linux-mmc
  Cc: Rob Herring, Adrian Hunter, Ulf Hansson, Masahiro Yamada,
	devicetree, linux-kernel, Rob Herring, Mark Rutland

Add a Socionext SoC specific compatible (suggested by Rob Herring).

No SoC specific data are associated with the compatible strings for
now, but other SoC vendors may use this IP and want to differentiate
IP variants in the future.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

Changes in v2:
  - Add "uniphier" to the compatible to make it more SoC-specific

 Documentation/devicetree/bindings/mmc/sdhci-cadence.txt | 6 ++++--
 drivers/mmc/host/sdhci-cadence.c                        | 1 +
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/sdhci-cadence.txt b/Documentation/devicetree/bindings/mmc/sdhci-cadence.txt
index 750374f..c0f37cb 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-cadence.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-cadence.txt
@@ -1,7 +1,9 @@
 * Cadence SD/SDIO/eMMC Host Controller
 
 Required properties:
-- compatible: should be "cdns,sd4hc".
+- compatible: should be one of the following:
+    "cdns,sd4hc"               - default of the IP
+    "socionext,uniphier-sd4hc" - for Socionext UniPhier SoCs
 - reg: offset and length of the register set for the device.
 - interrupts: a single interrupt specifier.
 - clocks: phandle to the input clock.
@@ -19,7 +21,7 @@ if supported.  See mmc.txt for details.
 
 Example:
 	emmc: sdhci@5a000000 {
-		compatible = "cdns,sd4hc";
+		compatible = "socionext,uniphier-sd4hc", "cdns,sd4hc";
 		reg = <0x5a000000 0x400>;
 		interrupts = <0 78 4>;
 		clocks = <&clk 4>;
diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c
index 1501cfd..4b0ecb9 100644
--- a/drivers/mmc/host/sdhci-cadence.c
+++ b/drivers/mmc/host/sdhci-cadence.c
@@ -262,6 +262,7 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
 }
 
 static const struct of_device_id sdhci_cdns_match[] = {
+	{ .compatible = "socionext,uniphier-sd4hc" },
 	{ .compatible = "cdns,sd4hc" },
 	{ /* sentinel */ }
 };
-- 
2.7.4


^ permalink raw reply related

* [PATCH] mmc: sdhci-cadence: add SoC specific compatible string
From: Masahiro Yamada @ 2016-12-14  1:59 UTC (permalink / raw)
  To: linux-mmc
  Cc: Rob Herring, Adrian Hunter, Ulf Hansson, Masahiro Yamada,
	devicetree, linux-kernel, Rob Herring, Mark Rutland

Add a Socionext SoC specific compatible (suggested by Rob Herring).

No SoC specific data are associated with the compatible strings for
now, but other SoC vendors may use this IP and want to differentiate
IP variants in the future.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

 Documentation/devicetree/bindings/mmc/sdhci-cadence.txt | 6 ++++--
 drivers/mmc/host/sdhci-cadence.c                        | 1 +
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/mmc/sdhci-cadence.txt b/Documentation/devicetree/bindings/mmc/sdhci-cadence.txt
index 750374f..de66ac0 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-cadence.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-cadence.txt
@@ -1,7 +1,9 @@
 * Cadence SD/SDIO/eMMC Host Controller
 
 Required properties:
-- compatible: should be "cdns,sd4hc".
+- compatible: should be one of the following:
+    "cdns,sd4hc"
+    "socionext,sd4hc"
 - reg: offset and length of the register set for the device.
 - interrupts: a single interrupt specifier.
 - clocks: phandle to the input clock.
@@ -19,7 +21,7 @@ if supported.  See mmc.txt for details.
 
 Example:
 	emmc: sdhci@5a000000 {
-		compatible = "cdns,sd4hc";
+		compatible = "socionext,sd4hc", "cdns,sd4hc";
 		reg = <0x5a000000 0x400>;
 		interrupts = <0 78 4>;
 		clocks = <&clk 4>;
diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c
index 1501cfd..66b99f7 100644
--- a/drivers/mmc/host/sdhci-cadence.c
+++ b/drivers/mmc/host/sdhci-cadence.c
@@ -262,6 +262,7 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
 }
 
 static const struct of_device_id sdhci_cdns_match[] = {
+	{ .compatible = "socionext,sd4hc" },
 	{ .compatible = "cdns,sd4hc" },
 	{ /* sentinel */ }
 };
-- 
2.7.4


^ permalink raw reply related

* Re: [PATCH v4 3/4] powernv: Pass PSSCR value and mask to power9_idle_stop
From: Balbir Singh @ 2016-12-14  0:16 UTC (permalink / raw)
  To: Gautham R. Shenoy, Michael Ellerman, Benjamin Herrenschmidt,
	Paul Mackerras, Rafael J. Wysocki, Daniel Lezcano,
	Michael Neuling, Vaidyanathan Srinivasan, Shreyas B. Prabhu,
	Shilpasri G Bhat, Stewart Smith, Oliver O'Halloran
  Cc: linuxppc-dev, linux-kernel, linux-pm, devicetree, Rob Herring,
	Mark Rutland
In-Reply-To: <31b1024af69726cdf3cfb25413fc3dff28fa3547.1481288905.git.ego@linux.vnet.ibm.com>



On 10/12/16 00:32, Gautham R. Shenoy wrote:
> From: "Gautham R. Shenoy" <ego@linux.vnet.ibm.com>
> 
> The power9_idle_stop method currently takes only the requested stop
> level as a parameter and picks up the rest of the PSSCR bits from a
> hand-coded macro. This is not a very flexible design, especially when
> the firmware has the capability to communicate the psscr value and the
> mask associated with a particular stop state via device tree.
> 
> This patch modifies the power9_idle_stop API to take as parameters the
> PSSCR value and the PSSCR mask corresponding to the stop state that
> needs to be set. These PSSCR value and mask are respectively obtained
> by parsing the "ibm,cpu-idle-state-psscr" and
> "ibm,cpu-idle-state-psscr-mask" fields from the device tree.
> 
> In addition to this, the patch adds support for handling stop states
> for which ESL and EC bits in the PSSCR are zero. As per the
> architecture, a wakeup from these stop states resumes execution from
> the subsequent instruction as opposed to waking up at the System
> Vector.
> 
> The older firmware sets only the Requested Level (RL) field in the
> psscr and psscr-mask exposed in the device tree. For older firmware
> where psscr-mask=0xf, this patch will set the default sane values that
> the set for for remaining PSSCR fields (i.e PSLL, MTL, ESL, EC, and
> TR).
> 
> This skiboot patch that exports fully populated PSSCR values and the
> mask for all the stop states can be found here:
> https://lists.ozlabs.org/pipermail/skiboot/2016-September/004869.html
> 
> Signed-off-by: Gautham R. Shenoy <ego@linux.vnet.ibm.com>
> ---
>  arch/powerpc/include/asm/cpuidle.h       | 41 ++++++++++++++++
>  arch/powerpc/include/asm/processor.h     |  3 +-
>  arch/powerpc/kernel/idle_book3s.S        | 31 +++++++-----
>  arch/powerpc/platforms/powernv/idle.c    | 81 ++++++++++++++++++++++++++------
>  arch/powerpc/platforms/powernv/powernv.h |  3 +-
>  arch/powerpc/platforms/powernv/smp.c     | 14 +++---
>  drivers/cpuidle/cpuidle-powernv.c        | 40 +++++++++++-----
>  7 files changed, 169 insertions(+), 44 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/cpuidle.h b/arch/powerpc/include/asm/cpuidle.h
> index 0a3255b..fa0b6c0 100644
> --- a/arch/powerpc/include/asm/cpuidle.h
> +++ b/arch/powerpc/include/asm/cpuidle.h
> @@ -10,11 +10,52 @@
>  #define PNV_CORE_IDLE_LOCK_BIT          0x100
>  #define PNV_CORE_IDLE_THREAD_BITS       0x0FF
>  
> +/*
> + * ============================ NOTE =================================
> + * The older firmware populates only the RL field in the psscr_val and
> + * sets the psscr_mask to 0xf. On such a firmware, the kernel sets the
> + * remaining PSSCR fields to default values as follows:
> + *
> + * - ESL and EC bits are to 1. So wakeup from any stop state will be
> + *   at vector 0x100.
> + *
> + * - MTL and PSLL are set to the maximum allowed value as per the ISA,
> + *    i.e. 15.
> + *
> + * - The Transition Rate, TR is set to the Maximum value 3.
> + */
> +#define PSSCR_HV_DEFAULT_VAL    (PSSCR_ESL | PSSCR_EC |		    \
> +				PSSCR_PSLL_MASK | PSSCR_TR_MASK |   \
> +				PSSCR_MTL_MASK)
> +
> +#define PSSCR_HV_DEFAULT_MASK   (PSSCR_ESL | PSSCR_EC |		    \
> +				PSSCR_PSLL_MASK | PSSCR_TR_MASK |   \
> +				PSSCR_MTL_MASK | PSSCR_RL_MASK)
> +
>  #ifndef __ASSEMBLY__
>  extern u32 pnv_fastsleep_workaround_at_entry[];
>  extern u32 pnv_fastsleep_workaround_at_exit[];
>  
>  extern u64 pnv_first_deep_stop_state;
> +
> +static inline u64 compute_psscr_val(u64 psscr_val, u64 psscr_mask)
> +{
> +	/*
> +	 * psscr_mask == 0xf indicates an older firmware.
> +	 * Set remaining fields of psscr to the default values.
> +	 * See NOTE above definition of PSSCR_HV_DEFAULT_VAL
> +	 */
> +	if (psscr_mask == 0xf)
> +		return psscr_val | PSSCR_HV_DEFAULT_VAL;
> +	return psscr_val;
> +}
> +
> +static inline u64 compute_psscr_mask(u64 psscr_mask)
> +{
> +	if (psscr_mask == 0xf)
> +		return PSSCR_HV_DEFAULT_MASK;
> +	return psscr_mask;
> +}
>  #endif
>  
>  #endif
> diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
> index c07c31b..422becd 100644
> --- a/arch/powerpc/include/asm/processor.h
> +++ b/arch/powerpc/include/asm/processor.h
> @@ -458,7 +458,8 @@ static inline unsigned long get_clean_sp(unsigned long sp, int is_32)
>  extern unsigned long power7_nap(int check_irq);
>  extern unsigned long power7_sleep(void);
>  extern unsigned long power7_winkle(void);
> -extern unsigned long power9_idle_stop(unsigned long stop_level);
> +extern unsigned long power9_idle_stop(unsigned long stop_psscr_val,
> +				      unsigned long stop_psscr_mask);
>  
>  extern void flush_instruction_cache(void);
>  extern void hard_reset_now(void);
> diff --git a/arch/powerpc/kernel/idle_book3s.S b/arch/powerpc/kernel/idle_book3s.S
> index be90e2f..37ee533 100644
> --- a/arch/powerpc/kernel/idle_book3s.S
> +++ b/arch/powerpc/kernel/idle_book3s.S
> @@ -40,9 +40,7 @@
>  #define _WORC	GPR11
>  #define _PTCR	GPR12
>  
> -#define PSSCR_HV_TEMPLATE	PSSCR_ESL | PSSCR_EC | \
> -				PSSCR_PSLL_MASK | PSSCR_TR_MASK | \
> -				PSSCR_MTL_MASK
> +#define PSSCR_EC_ESL_MASK_SHIFTED          (PSSCR_EC | PSSCR_ESL) >> 16
>  
>  	.text
>  
> @@ -264,7 +262,7 @@ enter_winkle:
>  	IDLE_STATE_ENTER_SEQ_NORET(PPC_WINKLE)
>  
>  /*
> - * r3 - requested stop state
> + * r3 - PSSCR value corresponding to the requested stop state.
>   */
>  power_enter_stop:
>  #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
> @@ -274,9 +272,19 @@ power_enter_stop:
>  	stb	r4,HSTATE_HWTHREAD_STATE(r13)
>  #endif
>  /*
> + * Check if we are executing the lite variant with ESL=EC=0
> + */
> +	andis.   r4, r3, PSSCR_EC_ESL_MASK_SHIFTED

r4 = psscr & (PSSCR_EC | PSSCR_ESL)

> +	andi.    r3, r3, PSSCR_RL_MASK   /* r3 = requested stop state */

r3 = psscr & RL_MASK (requested mask). 

Why do we do and andis. followed by andi. and a compdi below?

> +	cmpdi	 r4, 0

r4 == 0 implies we either both PSSCR_EC|ESL are cleared.
I am not sure if our checks for EC are well defined/implemented.
Should we worry about EC at all at this point?

> +	bne	 1f
> +	IDLE_STATE_ENTER_SEQ(PPC_STOP)
> +	li	r3,0  /* Since we didn't lose state, return 0 */
> +	b 	pnv_wakeup_noloss
> +/*
>   * Check if the requested state is a deep idle state.
>   */
> -	LOAD_REG_ADDRBASE(r5,pnv_first_deep_stop_state)
> +1:	LOAD_REG_ADDRBASE(r5,pnv_first_deep_stop_state)
>  	ld	r4,ADDROFF(pnv_first_deep_stop_state)(r5)
>  	cmpd	r3,r4
>  	bge	2f
> @@ -353,16 +361,17 @@ ALT_FTR_SECTION_END_NESTED_IFSET(CPU_FTR_ARCH_207S, 66);		\
>  	ld	r3,ORIG_GPR3(r1);	/* Restore original r3 */	\
>  20:	nop;
>  
> -

Spurious change?

>  /*
> - * r3 - requested stop state
> + * r3 - The PSSCR value corresponding to the stop state.
> + * r4 - The PSSCR mask corrresonding to the stop state.
>   */
>  _GLOBAL(power9_idle_stop)
> -	LOAD_REG_IMMEDIATE(r4, PSSCR_HV_TEMPLATE)
> -	or	r4,r4,r3
> -	mtspr	SPRN_PSSCR, r4
> -	li	r4, 1
> +	mfspr   r5, SPRN_PSSCR
> +	andc    r5, r5, r4
> +	or      r3, r3, r5
> +	mtspr 	SPRN_PSSCR, r3
>  	LOAD_REG_ADDR(r5,power_enter_stop)
> +	li	r4, 1
>  	b	pnv_powersave_common
>  	/* No return */
>  /*
> diff --git a/arch/powerpc/platforms/powernv/idle.c b/arch/powerpc/platforms/powernv/idle.c
> index 479c256..663c6ef 100644
> --- a/arch/powerpc/platforms/powernv/idle.c
> +++ b/arch/powerpc/platforms/powernv/idle.c
> @@ -237,15 +237,21 @@ static DEVICE_ATTR(fastsleep_workaround_applyonce, 0600,
>  			show_fastsleep_workaround_applyonce,
>  			store_fastsleep_workaround_applyonce);
>  
> +/*
> + * The default stop state that will be used by ppc_md.power_save
> + * function on platforms that support stop instruction.
> + */
> +u64 pnv_default_stop_val;
> +u64 pnv_default_stop_mask;
>  
>  /*
>   * Used for ppc_md.power_save which needs a function with no parameters
>   */
>  static void power9_idle(void)
>  {
> -	/* Requesting stop state 0 */
> -	power9_idle_stop(0);
> +	power9_idle_stop(pnv_default_stop_val, pnv_default_stop_mask);
>  }
> +
>  /*
>   * First deep stop state. Used to figure out when to save/restore
>   * hypervisor context.
> @@ -253,9 +259,11 @@ static void power9_idle(void)
>  u64 pnv_first_deep_stop_state = MAX_STOP_STATE;
>  
>  /*
> - * Deepest stop idle state. Used when a cpu is offlined
> + * psscr value and mask of the deepest stop idle state.
> + * Used when a cpu is offlined.
>   */
> -u64 pnv_deepest_stop_state;
> +u64 pnv_deepest_stop_psscr_val;
> +u64 pnv_deepest_stop_psscr_mask;
>  
>  /*
>   * Power ISA 3.0 idle initialization.
> @@ -302,28 +310,58 @@ static int __init pnv_arch300_idle_init(struct device_node *np, u32 *flags,
>  					int dt_idle_states)

In some cases we say power9 and arch300 in others, not related to this patchset, but just a generic comment

>  {
>  	u64 *psscr_val = NULL;
> +	u64 *psscr_mask = NULL;
> +	u32 *residency_ns = NULL;
> +	u64 max_residency_ns = 0;
>  	int rc = 0, i;
> +	bool default_stop_found = false;
>  
> -	psscr_val = kcalloc(dt_idle_states, sizeof(*psscr_val),
> -				GFP_KERNEL);
> -	if (!psscr_val) {
> +	psscr_val = kcalloc(dt_idle_states, sizeof(*psscr_val), GFP_KERNEL);
> +	psscr_mask = kcalloc(dt_idle_states, sizeof(*psscr_mask), GFP_KERNEL);
> +	residency_ns = kcalloc(dt_idle_states, sizeof(*residency_ns),
> +			       GFP_KERNEL);
> +
> +	if (!psscr_val || !psscr_mask || !residency_ns) {
>  		rc = -1;
>  		goto out;
>  	}
> +
>  	if (of_property_read_u64_array(np,
>  		"ibm,cpu-idle-state-psscr",
>  		psscr_val, dt_idle_states)) {
> -		pr_warn("cpuidle-powernv: missing ibm,cpu-idle-states-psscr in DT\n");
> +		pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-psscr in DT\n");
> +		rc = -1;
> +		goto out;
> +	}
> +
> +	if (of_property_read_u64_array(np,
> +				       "ibm,cpu-idle-state-psscr-mask",
> +				       psscr_mask, dt_idle_states)) {
> +		pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-psscr-mask in DT\n");
> +		rc = -1;
> +		goto out;
> +	}
> +
> +	if (of_property_read_u32_array(np,
> +				       "ibm,cpu-idle-state-residency-ns",
> +					residency_ns, dt_idle_states)) {
> +		pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-residency-ns in DT\n");
>  		rc = -1;
>  		goto out;
>  	}
>  
>  	/*
> -	 * Set pnv_first_deep_stop_state and pnv_deepest_stop_state.
> +	 * Set pnv_first_deep_stop_state, pnv_deepest_stop_psscr_{val,mask},
> +	 * and the pnv_default_stop_{val,mask}.
> +	 *
>  	 * pnv_first_deep_stop_state should be set to the first stop
>  	 * level to cause hypervisor state loss.
> -	 * pnv_deepest_stop_state should be set to the deepest stop
> -	 * stop state.
> +	 *
> +	 * pnv_deepest_stop_{val,mask} should be set to values corresponding to
> +	 * the deepest stop state.
> +	 *
> +	 * pnv_default_stop_{val,mask} should be set to values corresponding to
> +	 * the shallowest (OPAL_PM_STOP_INST_FAST) loss-less stop state.
>  	 */
>  	pnv_first_deep_stop_state = MAX_STOP_STATE;
>  	for (i = 0; i < dt_idle_states; i++) {
> @@ -333,12 +371,27 @@ static int __init pnv_arch300_idle_init(struct device_node *np, u32 *flags,
>  		     (pnv_first_deep_stop_state > psscr_rl))
>  			pnv_first_deep_stop_state = psscr_rl;
>  
> -		if (pnv_deepest_stop_state < psscr_rl)
> -			pnv_deepest_stop_state = psscr_rl;
> -	}
> +		if (max_residency_ns < residency_ns[i]) {
> +			max_residency_ns = residency_ns[i];
> +			pnv_deepest_stop_psscr_val =
> +				compute_psscr_val(psscr_val[i], psscr_mask[i]);
> +			pnv_deepest_stop_psscr_mask =
> +				compute_psscr_mask(psscr_mask[i]);
> +		}
>  

Does it make sense to have them sorted and then use the last value from the array?


Balbir Singh

^ permalink raw reply

* [PATCH v2 3/3] power: supply: bq24735-charger: allow chargers to share the ac-detect gpio
From: Peter Rosin @ 2016-12-13 23:56 UTC (permalink / raw)
  To: linux-kernel
  Cc: Peter Rosin, Sebastian Reichel, Rob Herring, Mark Rutland,
	linux-pm, devicetree
In-Reply-To: <1481673405-4547-1-git-send-email-peda@axentia.se>

If several parallel bq24735 chargers have their ac-detect gpios wired
together (or if only one of the parallel bq24735 chargers have its
ac-detect pin wired to a gpio, and the others are assumed to react the
same), then all driver instances need to check the same gpio. But the
gpio subsystem does not allow sharing gpios, so handle that locally.

However, only do this for the polling case, sharing is not supported if
the ac detection is handled with interrupts.

Signed-off-by: Peter Rosin <peda@axentia.se>
---
 drivers/power/supply/bq24735-charger.c | 111 +++++++++++++++++++++++++++++----
 1 file changed, 100 insertions(+), 11 deletions(-)

diff --git a/drivers/power/supply/bq24735-charger.c b/drivers/power/supply/bq24735-charger.c
index f45876927676..c2403c4d5ece 100644
--- a/drivers/power/supply/bq24735-charger.c
+++ b/drivers/power/supply/bq24735-charger.c
@@ -25,6 +25,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/power_supply.h>
 #include <linux/slab.h>
@@ -43,12 +44,24 @@
 #define BQ24735_MANUFACTURER_ID		0xfe
 #define BQ24735_DEVICE_ID		0xff
 
+struct bq24735;
+
+struct bq24735_shared {
+	struct list_head		list;
+	struct bq24735			*owner;
+	struct gpio_desc		*status_gpio;
+};
+
+static DEFINE_MUTEX(shared_lock);
+static LIST_HEAD(shared_list);
+
 struct bq24735 {
 	struct power_supply		*charger;
 	struct power_supply_desc	charger_desc;
 	struct i2c_client		*client;
 	struct bq24735_platform		*pdata;
 	struct mutex			lock;
+	struct bq24735_shared		*shared;
 	struct gpio_desc		*status_gpio;
 	struct delayed_work		poll;
 	u32				poll_interval;
@@ -346,6 +359,75 @@ static struct bq24735_platform *bq24735_parse_dt_data(struct i2c_client *client)
 	return pdata;
 }
 
+static struct gpio_desc *bq24735_get_status_gpio(struct bq24735 *charger)
+{
+	struct device *dev = &charger->client->dev;
+	struct bq24735_shared *shared;
+	int gpio;
+	enum of_gpio_flags flags;
+	int active_low;
+	struct list_head *pos;
+
+	if (of_property_read_bool(dev->of_node, "ti,ac-detect-gpios"))
+		gpio = of_get_named_gpio_flags(dev->of_node,
+					       "ti,ac-detect-gpios", 0, &flags);
+	else if (of_property_read_bool(dev->of_node, "ti,ac-detect-gpio"))
+		gpio = of_get_named_gpio_flags(dev->of_node,
+					       "ti,ac-detect-gpio", 0, &flags);
+	else
+		return NULL;
+
+	if (!gpio_is_valid(gpio))
+		return ERR_PTR(gpio);
+	active_low = flags & OF_GPIO_ACTIVE_LOW;
+
+	mutex_lock(&shared_lock);
+	list_for_each(pos, &shared_list) {
+		shared = list_entry(pos, struct bq24735_shared, list);
+		if (gpio != desc_to_gpio(shared->status_gpio))
+			continue;
+		if (!active_low ^ !gpiod_is_active_low(shared->status_gpio))
+			continue;
+
+		get_device(&shared->owner->client->dev);
+		dev_dbg(dev, "sharing gpio with %s\n",
+			shared->owner->pdata->name);
+		charger->shared = shared;
+		mutex_unlock(&shared_lock);
+		return shared->status_gpio;
+	}
+
+	shared = devm_kzalloc(dev, sizeof(*shared), GFP_KERNEL);
+	if (!shared) {
+		mutex_unlock(&shared_lock);
+		return ERR_PTR(-ENOMEM);
+	}
+	shared->owner = charger;
+	shared->status_gpio = gpiod_get(dev, "ti,ac-detect", GPIOD_IN);
+	if (!IS_ERR(shared->status_gpio)) {
+		charger->shared = shared;
+		list_add(&shared->list, &shared_list);
+	}
+	mutex_unlock(&shared_lock);
+
+	return shared->status_gpio;
+}
+
+static void bq24735_put_status_gpio(struct bq24735 *charger)
+{
+	if (!charger->shared)
+		return;
+
+	mutex_lock(&shared_lock);
+	if (charger->shared->owner != charger) {
+		put_device(&charger->shared->owner->client->dev);
+	} else {
+		list_del(&charger->shared->list);
+		gpiod_put(charger->shared->status_gpio);
+	}
+	mutex_unlock(&shared_lock);
+}
+
 static int bq24735_charger_probe(struct i2c_client *client,
 				 const struct i2c_device_id *id)
 {
@@ -402,9 +484,7 @@ static int bq24735_charger_probe(struct i2c_client *client,
 
 	i2c_set_clientdata(client, charger);
 
-	charger->status_gpio = devm_gpiod_get_optional(&client->dev,
-						       "ti,ac-detect",
-						       GPIOD_IN);
+	charger->status_gpio = bq24735_get_status_gpio(charger);
 	if (IS_ERR(charger->status_gpio)) {
 		ret = PTR_ERR(charger->status_gpio);
 		dev_err(&client->dev, "Getting gpio failed: %d\n", ret);
@@ -416,28 +496,30 @@ static int bq24735_charger_probe(struct i2c_client *client,
 		if (ret < 0) {
 			dev_err(&client->dev, "Failed to read manufacturer id : %d\n",
 				ret);
-			return ret;
+			goto out;
 		} else if (ret != 0x0040) {
 			dev_err(&client->dev,
 				"manufacturer id mismatch. 0x0040 != 0x%04x\n", ret);
-			return -ENODEV;
+			ret = -ENODEV;
+			goto out;
 		}
 
 		ret = bq24735_read_word(client, BQ24735_DEVICE_ID);
 		if (ret < 0) {
 			dev_err(&client->dev, "Failed to read device id : %d\n", ret);
-			return ret;
+			goto out;
 		} else if (ret != 0x000B) {
 			dev_err(&client->dev,
 				"device id mismatch. 0x000b != 0x%04x\n", ret);
-			return -ENODEV;
+			ret = -ENODEV;
+			goto out;
 		}
 	}
 
 	ret = bq24735_config_charger(charger);
 	if (ret < 0) {
 		dev_err(&client->dev, "failed in configuring charger");
-		return ret;
+		goto out;
 	}
 
 	/* check for AC adapter presence */
@@ -445,7 +527,7 @@ static int bq24735_charger_probe(struct i2c_client *client,
 		ret = bq24735_enable_charging(charger);
 		if (ret < 0) {
 			dev_err(&client->dev, "Failed to enable charging\n");
-			return ret;
+			goto out;
 		}
 	}
 
@@ -455,7 +537,7 @@ static int bq24735_charger_probe(struct i2c_client *client,
 		ret = PTR_ERR(charger->charger);
 		dev_err(&client->dev, "Failed to register power supply: %d\n",
 			ret);
-		return ret;
+		goto out;
 	}
 
 	if (client->irq) {
@@ -470,7 +552,7 @@ static int bq24735_charger_probe(struct i2c_client *client,
 			dev_err(&client->dev,
 				"Unable to register IRQ %d err %d\n",
 				client->irq, ret);
-			return ret;
+			goto out;
 		}
 	} else if (charger->status_gpio) {
 		ret = of_property_read_u32(client->dev.of_node,
@@ -487,6 +569,11 @@ static int bq24735_charger_probe(struct i2c_client *client,
 	}
 
 	return 0;
+
+out:
+	bq24735_put_status_gpio(charger);
+
+	return ret;
 }
 
 static int bq24735_charger_remove(struct i2c_client *client)
@@ -496,6 +583,8 @@ static int bq24735_charger_remove(struct i2c_client *client)
 	if (charger->poll_interval)
 		cancel_delayed_work_sync(&charger->poll);
 
+	bq24735_put_status_gpio(charger);
+
 	return 0;
 }
 
-- 
2.1.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox