diff options
Diffstat (limited to 'cds9k-led.c')
-rw-r--r-- | cds9k-led.c | 99 |
1 files changed, 99 insertions, 0 deletions
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"); |