All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
To: Lee Jones <lee.jones@linaro.org>
Cc: Linus Walleij <linus.walleij@linaro.org>,
	Alexandre Courbot <gnurou@gmail.com>,
	Rob Herring <robh+dt@kernel.org>,
	Mark Rutland <mark.rutland@arm.com>,
	Frank Rowand <frowand.list@gmail.com>,
	Wolfram Sang <wsa@the-dreams.de>,
	Richard Purdie <rpurdie@rpsys.net>,
	Jacek Anaszewski <j.anaszewski@samsung.com>,
	Jean Delvare <jdelvare@suse.com>, Peter Rosin <peda@axentia.se>,
	Avirup Banerjee <abanerjee@juniper.net>,
	Georgi Vlaev <gvlaev@juniper.net>,
	Guenter Roeck <linux@roeck-us.net>,
	JawaharBalaji Thirumalaisamy <jawaharb@juniper.net>,
	Pantelis Antoniou <pantelis.antoniou@konsulko.com>,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-gpio@vger.kernel.org, linux-i2c@vger.kernel.org,
	linux-leds@vger.kernel.org, linux-hwmon@vger.kernel.org
Subject: [PATCH 07/10] leds: i2cs: Add I2CS FPGA leds driver
Date: Fri,  7 Oct 2016 18:21:06 +0300	[thread overview]
Message-ID: <1475853669-22480-8-git-send-email-pantelis.antoniou@konsulko.com> (raw)
In-Reply-To: <1475853669-22480-1-git-send-email-pantelis.antoniou@konsulko.com>

From: Georgi Vlaev <gvlaev@juniper.net>

Add support for the FRU faceplate status LEDs (OK, FAIL,
ACTIVE, STANDBY) controlled by the Juniper I2CS FPGA. This
driver is a jnx-i2cs-core client.

Signed-off-by: Georgi Vlaev <gvlaev@juniper.net>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
---
 drivers/leds/Kconfig         |   9 ++
 drivers/leds/Makefile        |   1 +
 drivers/leds/leds-jnx-i2cs.c | 219 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 229 insertions(+)
 create mode 100644 drivers/leds/leds-jnx-i2cs.c

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 7a628c6..45c6612 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -659,6 +659,15 @@ config LEDS_MLXCPLD
 	  This option enabled support for the LEDs on the Mellanox
 	  boards. Say Y to enabled these.
 
+config LEDS_JNX_I2CS
+	tristate "LED support for the Juniper Networks I2CS FPGA"
+	depends on LEDS_CLASS && I2C
+	select REGMAP_I2C
+	help
+	  This option enables support for the FRU faceplate status
+	  LEDs (OK, FAIL, ACTIVE, STANDBY) controlled by the Juniper
+	  I2CS FPGA.
+
 comment "LED Triggers"
 source "drivers/leds/trigger/Kconfig"
 
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 3965070..1ce2d0b 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_LEDS_IS31FL319X)		+= leds-is31fl319x.o
 obj-$(CONFIG_LEDS_IS31FL32XX)		+= leds-is31fl32xx.o
 obj-$(CONFIG_LEDS_PM8058)		+= leds-pm8058.o
 obj-$(CONFIG_LEDS_MLXCPLD)		+= leds-mlxcpld.o
+obj-$(CONFIG_LEDS_JNX_I2CS)		+= leds-jnx-i2cs.o
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
diff --git a/drivers/leds/leds-jnx-i2cs.c b/drivers/leds/leds-jnx-i2cs.c
new file mode 100644
index 0000000..c2d7274
--- /dev/null
+++ b/drivers/leds/leds-jnx-i2cs.c
@@ -0,0 +1,219 @@
+/*
+ * Juniper Networks I2CS FPGA LEDs driver
+ *
+ * Copyright (C) 2016 Juniper Networks
+ * Author: Georgi Vlaev <gvlaev@juniper.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+#include <linux/leds.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/jnx-i2cs-core.h>
+
+#define FRU_LEDS	4 /* Total LEDs (active, fail, ok, standby) */
+#define HW_BLINK_LEDS	3 /* LEDs with hw blink cap (standby not supported) */
+
+/*
+ * I2CS fru_led [0x12]
+ *
+ * bit 6   | bit 5    | bit 4   |...                        | bit 0
+ * blink_ok|blink_fail|blink_act|led_standby|led_ok|led_fail|led_act
+ */
+
+/* TODO: Use the regmap from the parent MFD */
+static struct regmap_config i2cs_leds_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = I2CS_SPARE_OE,
+};
+
+struct i2cs_led {
+	struct led_classdev lc;
+	struct regmap *regmap;
+	struct work_struct work;
+	int blink;
+	int on;
+	int bit;
+};
+
+struct i2cs_led_data {
+	int num_leds;
+	struct i2cs_led *leds;
+};
+
+static void jnx_i2cs_leds_work(struct work_struct *work)
+{
+	struct i2cs_led *led = container_of(work, struct i2cs_led, work);
+
+	int mask = (BIT(led->bit) << 4) | BIT(led->bit);
+	int value = ((led->blink << led->bit) << 4) | (led->on << led->bit);
+
+	regmap_update_bits(led->regmap, I2CS_FRU_LED, mask, value & 0x7f);
+}
+
+static void jnx_i2cs_leds_brightness_set(struct led_classdev *lc,
+				 enum led_brightness brightness)
+{
+	struct i2cs_led *led = container_of(lc, struct i2cs_led, lc);
+
+	led->on = (brightness != LED_OFF);
+	led->blink = 0; /* always turn off hw blink on brightness_set() */
+	schedule_work(&led->work);
+}
+
+static int jnx_i2cs_leds_blink_set(struct led_classdev *lc,
+				   unsigned long *delay_on,
+				   unsigned long *delay_off)
+{
+	struct i2cs_led *led = container_of(lc, struct i2cs_led, lc);
+
+	led->blink = (*delay_on > 0);
+	led->on = led->blink; /* 'on' bit should be set if blinking */
+	schedule_work(&led->work);
+
+	return 0;
+}
+
+static int jnx_i2cs_leds_init_one(struct device *dev, struct device_node *np,
+				  struct i2cs_led_data *ild,
+				  struct regmap *regmap, int num)
+{
+	struct i2cs_led *led;
+	const char *string;
+	bool hw_blink;
+	int ret;
+	u32 reg;
+
+	ret = of_property_read_u32(np, "reg", &reg);
+	if (ret || reg >= FRU_LEDS)
+		return -ENODEV;
+
+	led = &ild->leds[num];
+	led->bit = reg;
+	led->regmap = regmap;
+
+	if (!of_property_read_string(np, "label", &string))
+		led->lc.name = string;
+	else
+		led->lc.name = np->name;
+
+	if (!of_property_read_string(np, "linux,default-trigger", &string))
+		led->lc.default_trigger = string;
+
+	led->lc.brightness = LED_OFF;
+	led->lc.brightness_set = jnx_i2cs_leds_brightness_set;
+	if (led->bit <= HW_BLINK_LEDS) {
+		hw_blink = of_property_read_bool(np, "hw-blink");
+		if (hw_blink)
+			led->lc.blink_set = jnx_i2cs_leds_blink_set;
+	}
+
+	ret = devm_led_classdev_register(dev, &led->lc);
+	if (ret)
+		return ret;
+
+	INIT_WORK(&led->work, jnx_i2cs_leds_work);
+
+	return 0;
+}
+
+static int jnx_i2cs_leds_of_init(struct device *dev, struct i2cs_led_data *ild)
+{
+	struct device_node *child, *np = dev->of_node;
+	struct regmap *regmap;
+	struct i2c_client *client;
+	int ret, num_leds, i = 0;
+
+	if (!dev->parent)
+		return -ENODEV;
+
+	client = i2c_verify_client(dev->parent);
+	if (!client)
+		return -ENODEV;
+
+	regmap = devm_regmap_init_i2c(client, &i2cs_leds_regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(dev, "Failed to allocate register map\n");
+		return PTR_ERR(regmap);
+	}
+
+	num_leds = of_get_child_count(np);
+	if (!num_leds || num_leds > FRU_LEDS)
+		return -ENODEV;
+
+	ild->num_leds = num_leds;
+	ild->leds = devm_kzalloc(dev, sizeof(struct i2cs_led) * num_leds,
+				 GFP_KERNEL);
+	if (!ild->leds)
+		return -ENOMEM;
+
+	for_each_child_of_node(np, child) {
+		ret = jnx_i2cs_leds_init_one(dev, child, ild, regmap, i++);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int jnx_i2cs_leds_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct i2cs_led_data *ild;
+	int ret;
+
+	ild = devm_kzalloc(dev, sizeof(*ild), GFP_KERNEL);
+	if (!ild)
+		return -ENOMEM;
+
+	ret = jnx_i2cs_leds_of_init(dev, ild);
+	if (ret < 0)
+		return ret;
+
+	platform_set_drvdata(pdev, ild);
+
+	return 0;
+}
+
+static int jnx_i2cs_leds_remove(struct platform_device *pdev)
+{
+	struct i2cs_led_data *ild = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < ild->num_leds; i++) {
+		devm_led_classdev_unregister(&pdev->dev, &ild->leds[i].lc);
+		cancel_work_sync(&ild->leds[i].work);
+	}
+
+	return 0;
+}
+
+static const struct of_device_id jnx_i2cs_leds_match[] = {
+	{ .compatible = "jnx,leds-i2cs", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, jnx_i2cs_leds_match);
+
+static struct platform_driver jnx_i2cs_leds_driver = {
+	.driver = {
+		.name  = "leds-i2cs",
+		.of_match_table = jnx_i2cs_leds_match,
+	},
+	.probe = jnx_i2cs_leds_probe,
+	.remove = jnx_i2cs_leds_remove,
+};
+
+module_platform_driver(jnx_i2cs_leds_driver);
+
+MODULE_DESCRIPTION("Juniper Networks I2CS leds driver");
+MODULE_AUTHOR("Georgi Vlaev <gvlaev@juniper.net>");
+MODULE_LICENSE("GPL");
-- 
1.9.1

  parent reply	other threads:[~2016-10-07 15:21 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-10-07 15:20 [PATCH 00/10] Introduce Juniper I2CS FPGA driver Pantelis Antoniou
2016-10-07 15:21 ` [PATCH 01/10] mfd: Add Juniper I2CS MFD driver Pantelis Antoniou
2016-10-07 15:21   ` Pantelis Antoniou
2016-10-07 15:21 ` [PATCH 02/10] mfd: dt-bindings: Add bindings for the Juniper I2CS MFD Pantelis Antoniou
2016-10-10 20:23   ` Rob Herring
2016-10-17 19:10     ` Pantelis Antoniou
2016-10-07 15:21 ` [PATCH 03/10] i2c/muxes: Juniper I2CS RE mux Pantelis Antoniou
2016-10-07 15:21   ` Pantelis Antoniou
2016-10-10 15:29   ` Peter Rosin
2016-10-10 15:29     ` Peter Rosin
2016-10-07 15:21 ` [PATCH 04/10] i2c: i2c-mux-i2cs: Add device tree bindings Pantelis Antoniou
2016-10-10 15:48   ` Peter Rosin
2016-10-10 15:48     ` Peter Rosin
2016-10-17 19:11     ` Pantelis Antoniou
2016-10-10 20:25   ` Rob Herring
2016-10-07 15:21 ` [PATCH 05/10] gpio: i2cs: Juniper I2CS to GPIO pin mapping driver Pantelis Antoniou
2016-10-21  8:41   ` Linus Walleij
2016-10-21  8:41     ` Linus Walleij
2016-10-07 15:21 ` [PATCH 06/10] gpio: gpio-i2cs: Document bindings of I2CS FPGA GPIO block Pantelis Antoniou
2016-10-21  8:59   ` Linus Walleij
2016-10-21  8:59     ` Linus Walleij
2016-10-07 15:21 ` Pantelis Antoniou [this message]
2016-10-10  9:41   ` [PATCH 07/10] leds: i2cs: Add I2CS FPGA leds driver Jacek Anaszewski
2016-10-07 15:21 ` [PATCH 08/10] leds: Add binding for Juniper's I2CS FPGA Pantelis Antoniou
2016-10-07 15:21   ` Pantelis Antoniou
2016-10-10  9:41   ` Jacek Anaszewski
2016-10-07 15:21 ` [PATCH 09/10] hwmon: Add driver for Fan Tray on Juniper I2CS FGPA Pantelis Antoniou
2016-10-07 15:21 ` [PATCH 10/10] hwmon: i2cs-fan: Add hwmon dts binding documentation Pantelis Antoniou
2016-10-10 20:29   ` Rob Herring
2016-10-17 19:12     ` Pantelis Antoniou

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1475853669-22480-8-git-send-email-pantelis.antoniou@konsulko.com \
    --to=pantelis.antoniou@konsulko.com \
    --cc=abanerjee@juniper.net \
    --cc=devicetree@vger.kernel.org \
    --cc=frowand.list@gmail.com \
    --cc=gnurou@gmail.com \
    --cc=gvlaev@juniper.net \
    --cc=j.anaszewski@samsung.com \
    --cc=jawaharb@juniper.net \
    --cc=jdelvare@suse.com \
    --cc=lee.jones@linaro.org \
    --cc=linus.walleij@linaro.org \
    --cc=linux-gpio@vger.kernel.org \
    --cc=linux-hwmon@vger.kernel.org \
    --cc=linux-i2c@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-leds@vger.kernel.org \
    --cc=linux@roeck-us.net \
    --cc=mark.rutland@arm.com \
    --cc=peda@axentia.se \
    --cc=robh+dt@kernel.org \
    --cc=rpurdie@rpsys.net \
    --cc=wsa@the-dreams.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.