aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Phillips <david@yeah.nah.nz>2021-05-09 20:26:47 +1200
committerDavid Phillips <david@yeah.nah.nz>2021-05-09 20:27:23 +1200
commit690ba570a2108987bbdf4aa4d73242300e55cd2d (patch)
treebb1f16e7efea7e8e0f9814ebe91f121866f5ecaf
parent270c973f4b752e6bf9e977556d37aa61b73135b7 (diff)
downloadcds9k-690ba570a2108987bbdf4aa4d73242300e55cd2d.tar.xz
Add driver for PWM LED block
-rw-r--r--Makefile1
-rw-r--r--cds9k-led.c99
2 files changed, 100 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 8e49ff6..dd7ef7c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,6 @@
obj-m := cds9k-mfd-spi.o
obj-m += cds9k-gpio.o
+obj-m += cds9k-led.o
SRC := $(shell pwd)
diff --git a/cds9k-led.c b/cds9k-led.c
new file mode 100644
index 0000000..e00429e
--- /dev/null
+++ b/cds9k-led.c
@@ -0,0 +1,99 @@
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/leds.h>
+
+#define LED_REG_VALUE 0x0
+#define LED_REG_RATE 0x1
+
+struct cds9k_led {
+ struct led_classdev cdev;
+ struct regmap *regmap;
+ u32 base;
+};
+
+void cds9k_led_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness)
+{
+ struct cds9k_led *led = container_of(led_cdev, struct cds9k_led, cdev);
+
+ regmap_write(led->regmap, led->base + LED_REG_VALUE, brightness);
+}
+
+enum led_brightness cds9k_led_brightness_get(struct led_classdev *led_cdev)
+{
+ int ret;
+ unsigned int brightness;
+ struct cds9k_led *led = container_of(led_cdev, struct cds9k_led, cdev);
+
+ ret = regmap_read(led->regmap, led->base + LED_REG_VALUE, &brightness);
+ /* FIXME log something */
+ if (!ret)
+ return LED_OFF;
+
+ if (brightness > LED_FULL)
+ brightness = LED_FULL;
+
+ return brightness;
+}
+
+static int cds9k_led_probe(struct platform_device *pdev)
+{
+ int ret;
+ u32 base;
+ struct cds9k_led *led;
+ struct device_node *np = pdev->dev.of_node;
+ struct led_init_data init_data = {};
+ struct fwnode_handle *fwnode;
+
+ led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
+
+ ret = device_property_read_u32(&pdev->dev, "reg", &led->base);
+ if (ret)
+ return -EINVAL;
+
+ if (!pdev->dev.parent)
+ return -ENODEV;
+
+ led->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!led->regmap)
+ return -ENODEV;
+
+ led->cdev.name = of_get_property(np, "label", NULL) ? : np->name;
+ led->cdev.default_trigger = of_get_property(np, "linux,default-trigger", NULL);
+ led->cdev.brightness_set = cds9k_led_brightness_set;
+ led->cdev.brightness_get = cds9k_led_brightness_get;
+ led->cdev.max_brightness = 0xFF;
+ /* FIXME default state keep/on etc */
+
+ init_data.fwnode = of_fwnode_handle(np);
+ init_data.devicename = "cds9k_led";
+
+ ret = devm_led_classdev_register_ext(&pdev->dev, &led->cdev, &init_data);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct of_device_id cds9k_led_of_match[] = {
+ { .compatible = "david,cds9k-led" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, cds9k_led_of_match);
+
+static struct platform_driver cds9k_led = {
+ .driver = {
+ .name = "cds9k-led",
+ .of_match_table = cds9k_led_of_match,
+ },
+ .probe = cds9k_led_probe,
+ //.shutdown = cds9k_led_shutdown,
+};
+module_platform_driver(cds9k_led);
+
+MODULE_AUTHOR("David Phillips <david@yeah.nah.nz>");
+MODULE_DESCRIPTION("LED driver for the CDS9K board controller");
+MODULE_LICENSE("GPL v2");