^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Driver for the Cirrus EP93xx lcd backlight
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2010 H Hartley Sweeten <hsweeten@visionengravers.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * This driver controls the pulse width modulated brightness control output,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * BRIGHT, on the Cirrus EP9307, EP9312, and EP9315 processors.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/backlight.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define EP93XX_MAX_COUNT 255
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define EP93XX_MAX_BRIGHT 255
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define EP93XX_DEF_BRIGHT 128
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) struct ep93xxbl {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) void __iomem *mmio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) int brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static int ep93xxbl_set(struct backlight_device *bl, int brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct ep93xxbl *ep93xxbl = bl_get_data(bl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) writel((brightness << 8) | EP93XX_MAX_COUNT, ep93xxbl->mmio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) ep93xxbl->brightness = brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static int ep93xxbl_update_status(struct backlight_device *bl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return ep93xxbl_set(bl, backlight_get_brightness(bl));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static int ep93xxbl_get_brightness(struct backlight_device *bl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct ep93xxbl *ep93xxbl = bl_get_data(bl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) return ep93xxbl->brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static const struct backlight_ops ep93xxbl_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) .update_status = ep93xxbl_update_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) .get_brightness = ep93xxbl_get_brightness,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static int ep93xxbl_probe(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct ep93xxbl *ep93xxbl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct backlight_device *bl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) struct backlight_properties props;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) ep93xxbl = devm_kzalloc(&dev->dev, sizeof(*ep93xxbl), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (!ep93xxbl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) res = platform_get_resource(dev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (!res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * FIXME - We don't do a request_mem_region here because we are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * sharing the register space with the framebuffer driver (see
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * drivers/video/ep93xx-fb.c) and doing so will cause the second
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * loaded driver to return -EBUSY.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * NOTE: No locking is required; the framebuffer does not touch
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * this register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) ep93xxbl->mmio = devm_ioremap(&dev->dev, res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) resource_size(res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (!ep93xxbl->mmio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) memset(&props, 0, sizeof(struct backlight_properties));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) props.type = BACKLIGHT_RAW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) props.max_brightness = EP93XX_MAX_BRIGHT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) bl = devm_backlight_device_register(&dev->dev, dev->name, &dev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) ep93xxbl, &ep93xxbl_ops, &props);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (IS_ERR(bl))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) return PTR_ERR(bl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) bl->props.brightness = EP93XX_DEF_BRIGHT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) platform_set_drvdata(dev, bl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) ep93xxbl_update_status(bl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) static int ep93xxbl_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct backlight_device *bl = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return ep93xxbl_set(bl, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static int ep93xxbl_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct backlight_device *bl = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) backlight_update_status(bl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static SIMPLE_DEV_PM_OPS(ep93xxbl_pm_ops, ep93xxbl_suspend, ep93xxbl_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static struct platform_driver ep93xxbl_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) .name = "ep93xx-bl",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) .pm = &ep93xxbl_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) .probe = ep93xxbl_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) module_platform_driver(ep93xxbl_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) MODULE_DESCRIPTION("EP93xx Backlight Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) MODULE_ALIAS("platform:ep93xx-bl");