Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | /*
* Copyright (C) 2012 Bachmann electronic GmbH
* Christian Gmeiner <christian.gmeiner@gmail.com>
*
* Backlight driver for ot200 visualisation device from
* Bachmann electronic GmbH.
*
* 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 <linux/module.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/cs5535.h>
static struct cs5535_mfgpt_timer *pwm_timer;
/* this array defines the mapping of brightness in % to pwm frequency */
static const u8 dim_table[101] = {0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9,
10, 10, 11, 11, 12, 12, 13, 14, 15, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28,
30, 31, 33, 35, 37, 39, 41, 43, 45, 47, 50,
53, 55, 58, 61, 65, 68, 72, 75, 79, 84, 88,
93, 97, 103, 108, 114, 120, 126, 133, 140,
147, 155, 163};
struct ot200_backlight_data {
int current_brightness;
};
#define GPIO_DIMM 27
#define SCALE 1
#define CMP1MODE 0x2 /* compare on GE; output high on compare
* greater than or equal */
#define PWM_SETUP (SCALE | CMP1MODE << 6 | MFGPT_SETUP_CNTEN)
#define MAX_COMP2 163
static int ot200_backlight_update_status(struct backlight_device *bl)
{
struct ot200_backlight_data *data = bl_get_data(bl);
int brightness = bl->props.brightness;
if (bl->props.state & BL_CORE_FBBLANK)
brightness = 0;
/* enable or disable PWM timer */
if (brightness == 0)
cs5535_mfgpt_write(pwm_timer, MFGPT_REG_SETUP, 0);
else if (data->current_brightness == 0) {
cs5535_mfgpt_write(pwm_timer, MFGPT_REG_COUNTER, 0);
cs5535_mfgpt_write(pwm_timer, MFGPT_REG_SETUP,
MFGPT_SETUP_CNTEN);
}
/* apply new brightness value */
cs5535_mfgpt_write(pwm_timer, MFGPT_REG_CMP1,
MAX_COMP2 - dim_table[brightness]);
data->current_brightness = brightness;
return 0;
}
static int ot200_backlight_get_brightness(struct backlight_device *bl)
{
struct ot200_backlight_data *data = bl_get_data(bl);
return data->current_brightness;
}
static const struct backlight_ops ot200_backlight_ops = {
.update_status = ot200_backlight_update_status,
.get_brightness = ot200_backlight_get_brightness,
};
static int ot200_backlight_probe(struct platform_device *pdev)
{
struct backlight_device *bl;
struct ot200_backlight_data *data;
struct backlight_properties props;
int retval = 0;
/* request gpio */
if (devm_gpio_request(&pdev->dev, GPIO_DIMM,
"ot200 backlight dimmer") < 0) {
dev_err(&pdev->dev, "failed to request GPIO %d\n", GPIO_DIMM);
return -ENODEV;
}
/* request timer */
pwm_timer = cs5535_mfgpt_alloc_timer(7, MFGPT_DOMAIN_ANY);
if (!pwm_timer) {
dev_err(&pdev->dev, "MFGPT 7 not available\n");
return -ENODEV;
}
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data) {
retval = -ENOMEM;
goto error_devm_kzalloc;
}
/* setup gpio */
cs5535_gpio_set(GPIO_DIMM, GPIO_OUTPUT_ENABLE);
cs5535_gpio_set(GPIO_DIMM, GPIO_OUTPUT_AUX1);
/* setup timer */
cs5535_mfgpt_write(pwm_timer, MFGPT_REG_CMP1, 0);
cs5535_mfgpt_write(pwm_timer, MFGPT_REG_CMP2, MAX_COMP2);
cs5535_mfgpt_write(pwm_timer, MFGPT_REG_SETUP, PWM_SETUP);
data->current_brightness = 100;
props.max_brightness = 100;
props.brightness = 100;
props.type = BACKLIGHT_RAW;
bl = devm_backlight_device_register(&pdev->dev, dev_name(&pdev->dev),
&pdev->dev, data, &ot200_backlight_ops,
&props);
if (IS_ERR(bl)) {
dev_err(&pdev->dev, "failed to register backlight\n");
retval = PTR_ERR(bl);
goto error_devm_kzalloc;
}
platform_set_drvdata(pdev, bl);
return 0;
error_devm_kzalloc:
cs5535_mfgpt_free_timer(pwm_timer);
return retval;
}
static int ot200_backlight_remove(struct platform_device *pdev)
{
/* on module unload set brightness to 100% */
cs5535_mfgpt_write(pwm_timer, MFGPT_REG_COUNTER, 0);
cs5535_mfgpt_write(pwm_timer, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN);
cs5535_mfgpt_write(pwm_timer, MFGPT_REG_CMP1,
MAX_COMP2 - dim_table[100]);
cs5535_mfgpt_free_timer(pwm_timer);
return 0;
}
static struct platform_driver ot200_backlight_driver = {
.driver = {
.name = "ot200-backlight",
},
.probe = ot200_backlight_probe,
.remove = ot200_backlight_remove,
};
module_platform_driver(ot200_backlight_driver);
MODULE_DESCRIPTION("backlight driver for ot200 visualisation device");
MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:ot200-backlight");
|