#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/gpio.h>
#include <linux/fb.h>
#include <linux/lcd.h>
#include <linux/spi/spi.h>
struct lcd_device *lcd_dev;
struct backlight_device *bl_dev;
+ int limit_mask;
int intensity;
int power;
int mode;
char buf[2];
- void (*notify)(int intensity);
+ int gpio_backlight_on;
+ int gpio_backlight_cont;
+ int gpio_backlight_cont_inverted;
+
void (*kick_battery)(void);
};
static int corgi_ssp_lcdtg_send(struct corgi_lcd *lcd, int reg, uint8_t val);
+static struct corgi_lcd *the_corgi_lcd;
+static unsigned long corgibl_flags;
+#define CORGIBL_SUSPENDED 0x01
+#define CORGIBL_BATTLOW 0x02
+
/*
* This is only a psuedo I2C interface. We can't use the standard kernel
* routines as the interface is write only. We just assume the data is acked...
static int corgi_bl_set_intensity(struct corgi_lcd *lcd, int intensity)
{
+ int cont;
+
if (intensity > 0x10)
intensity += 0x10;
corgi_ssp_lcdtg_send(lcd, DUTYCTRL_ADRS, intensity);
- lcd->intensity = intensity;
- if (lcd->notify)
- lcd->notify(intensity);
+ /* Bit 5 via GPIO_BACKLIGHT_CONT */
+ cont = !!(intensity & 0x20) ^ lcd->gpio_backlight_cont_inverted;
+
+ if (gpio_is_valid(lcd->gpio_backlight_cont))
+ gpio_set_value(lcd->gpio_backlight_cont, cont);
+
+ if (gpio_is_valid(lcd->gpio_backlight_on))
+ gpio_set_value(lcd->gpio_backlight_on, intensity);
if (lcd->kick_battery)
lcd->kick_battery();
+ lcd->intensity = intensity;
return 0;
}
if (bd->props.fb_blank != FB_BLANK_UNBLANK)
intensity = 0;
+ if (corgibl_flags & CORGIBL_SUSPENDED)
+ intensity = 0;
+ if (corgibl_flags & CORGIBL_BATTLOW)
+ intensity &= lcd->limit_mask;
+
return corgi_bl_set_intensity(lcd, intensity);
}
+void corgibl_limit_intensity(int limit)
+{
+ if (limit)
+ corgibl_flags |= CORGIBL_BATTLOW;
+ else
+ corgibl_flags &= ~CORGIBL_BATTLOW;
+
+ backlight_update_status(the_corgi_lcd->bl_dev);
+}
+EXPORT_SYMBOL(corgibl_limit_intensity);
+
static struct backlight_ops corgi_bl_ops = {
.get_brightness = corgi_bl_get_intensity,
.update_status = corgi_bl_update_status,
{
struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev);
+ corgibl_flags |= CORGIBL_SUSPENDED;
corgi_bl_set_intensity(lcd, 0);
corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN);
return 0;
{
struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev);
+ corgibl_flags &= ~CORGIBL_SUSPENDED;
corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK);
backlight_update_status(lcd->bl_dev);
return 0;
#define corgi_lcd_resume NULL
#endif
+static int setup_gpio_backlight(struct corgi_lcd *lcd,
+ struct corgi_lcd_platform_data *pdata)
+{
+ struct spi_device *spi = lcd->spi_dev;
+ int err;
+
+ lcd->gpio_backlight_on = -1;
+ lcd->gpio_backlight_cont = -1;
+
+ if (gpio_is_valid(pdata->gpio_backlight_on)) {
+ err = gpio_request(pdata->gpio_backlight_on, "BL_ON");
+ if (err) {
+ dev_err(&spi->dev, "failed to request GPIO%d for "
+ "backlight_on\n", pdata->gpio_backlight_on);
+ return err;
+ }
+
+ lcd->gpio_backlight_on = pdata->gpio_backlight_on;
+ gpio_direction_output(lcd->gpio_backlight_on, 0);
+ }
+
+ if (gpio_is_valid(pdata->gpio_backlight_cont)) {
+ err = gpio_request(pdata->gpio_backlight_cont, "BL_CONT");
+ if (err) {
+ dev_err(&spi->dev, "failed to request GPIO%d for "
+ "backlight_cont\n", pdata->gpio_backlight_cont);
+ goto err_free_backlight_on;
+ }
+
+ lcd->gpio_backlight_cont = pdata->gpio_backlight_cont;
+
+ /* spitz and akita use both GPIOs for backlight, and
+ * have inverted polarity of GPIO_BACKLIGHT_CONT
+ */
+ if (gpio_is_valid(lcd->gpio_backlight_on)) {
+ lcd->gpio_backlight_cont_inverted = 1;
+ gpio_direction_output(lcd->gpio_backlight_cont, 1);
+ } else {
+ lcd->gpio_backlight_cont_inverted = 0;
+ gpio_direction_output(lcd->gpio_backlight_cont, 0);
+ }
+ }
+ return 0;
+
+err_free_backlight_on:
+ if (gpio_is_valid(lcd->gpio_backlight_on))
+ gpio_free(lcd->gpio_backlight_on);
+ return err;
+}
+
static int __devinit corgi_lcd_probe(struct spi_device *spi)
{
struct corgi_lcd_platform_data *pdata = spi->dev.platform_data;
lcd->bl_dev->props.brightness = pdata->default_intensity;
lcd->bl_dev->props.power = FB_BLANK_UNBLANK;
- lcd->notify = pdata->notify;
+ ret = setup_gpio_backlight(lcd, pdata);
+ if (ret)
+ goto err_unregister_bl;
+
lcd->kick_battery = pdata->kick_battery;
dev_set_drvdata(&spi->dev, lcd);
corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK);
backlight_update_status(lcd->bl_dev);
+
+ lcd->limit_mask = pdata->limit_mask;
+ the_corgi_lcd = lcd;
return 0;
+err_unregister_bl:
+ backlight_device_unregister(lcd->bl_dev);
err_unregister_lcd:
lcd_device_unregister(lcd->lcd_dev);
err_free_lcd:
backlight_update_status(lcd->bl_dev);
backlight_device_unregister(lcd->bl_dev);
+ if (gpio_is_valid(lcd->gpio_backlight_on))
+ gpio_free(lcd->gpio_backlight_on);
+
+ if (gpio_is_valid(lcd->gpio_backlight_cont))
+ gpio_free(lcd->gpio_backlight_cont);
+
corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN);
lcd_device_unregister(lcd->lcd_dev);
kfree(lcd);