Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d7ca6f8c authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus' of git://git.o-hand.com/linux-rpurdie-backlight

* 'for-linus' of git://git.o-hand.com/linux-rpurdie-backlight:
  backlight: Adds HP Jornada 700 series backlight driver
  backlight: Add HP Jornada 700 series LCD driver
  backlight: fix pwm_bl.c when multiple PWM backlights exist
  backlight: mbp_nvidia_bl - Add a debug switch
  backlight: Add support for MacBook 5, MacBook Air 2, and MacBook Pro 5
parents 3cd69271 13a7b5dc
Loading
Loading
Loading
Loading
+18 −0
Original line number Original line Diff line number Diff line
@@ -84,6 +84,15 @@ config LCD_TOSA
	  If you have an Sharp SL-6000 Zaurus say Y to enable a driver
	  If you have an Sharp SL-6000 Zaurus say Y to enable a driver
	  for its LCD.
	  for its LCD.


config LCD_HP700
	tristate "HP Jornada 700 series LCD Driver"
	depends on LCD_CLASS_DEVICE
	depends on SA1100_JORNADA720_SSP && !PREEMPT
	default y
	help
	  If you have an HP Jornada 700 series handheld (710/720/728)
	  say Y to enable LCD control driver.

#
#
# Backlight
# Backlight
#
#
@@ -157,6 +166,15 @@ config BACKLIGHT_HP680
	  If you have a HP Jornada 680, say y to enable the
	  If you have a HP Jornada 680, say y to enable the
	  backlight driver.
	  backlight driver.


config BACKLIGHT_HP700
	tristate "HP Jornada 700 series Backlight Driver"
	depends on BACKLIGHT_CLASS_DEVICE
	depends on SA1100_JORNADA720_SSP && !PREEMPT
	default y
	help
	  If you have an HP Jornada 700 series,
	  say Y to include backlight control driver.

config BACKLIGHT_PROGEAR
config BACKLIGHT_PROGEAR
	tristate "Frontpath ProGear Backlight Driver"
	tristate "Frontpath ProGear Backlight Driver"
	depends on BACKLIGHT_CLASS_DEVICE && PCI && X86
	depends on BACKLIGHT_CLASS_DEVICE && PCI && X86
+2 −0
Original line number Original line Diff line number Diff line
@@ -2,6 +2,7 @@


obj-$(CONFIG_LCD_CLASS_DEVICE)     += lcd.o
obj-$(CONFIG_LCD_CLASS_DEVICE)     += lcd.o
obj-$(CONFIG_LCD_CORGI)		   += corgi_lcd.o
obj-$(CONFIG_LCD_CORGI)		   += corgi_lcd.o
obj-$(CONFIG_LCD_HP700)		   += jornada720_lcd.o
obj-$(CONFIG_LCD_LTV350QV)	   += ltv350qv.o
obj-$(CONFIG_LCD_LTV350QV)	   += ltv350qv.o
obj-$(CONFIG_LCD_ILI9320)	   += ili9320.o
obj-$(CONFIG_LCD_ILI9320)	   += ili9320.o
obj-$(CONFIG_LCD_PLATFORM)	   += platform_lcd.o
obj-$(CONFIG_LCD_PLATFORM)	   += platform_lcd.o
@@ -12,6 +13,7 @@ obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o
obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
obj-$(CONFIG_BACKLIGHT_ATMEL_PWM)    += atmel-pwm-bl.o
obj-$(CONFIG_BACKLIGHT_ATMEL_PWM)    += atmel-pwm-bl.o
obj-$(CONFIG_BACKLIGHT_GENERIC)	+= generic_bl.o
obj-$(CONFIG_BACKLIGHT_GENERIC)	+= generic_bl.o
obj-$(CONFIG_BACKLIGHT_HP700)	+= jornada720_bl.o
obj-$(CONFIG_BACKLIGHT_HP680)	+= hp680_bl.o
obj-$(CONFIG_BACKLIGHT_HP680)	+= hp680_bl.o
obj-$(CONFIG_BACKLIGHT_LOCOMO)	+= locomolcd.o
obj-$(CONFIG_BACKLIGHT_LOCOMO)	+= locomolcd.o
obj-$(CONFIG_BACKLIGHT_OMAP1)	+= omap1_bl.o
obj-$(CONFIG_BACKLIGHT_OMAP1)	+= omap1_bl.o
+161 −0
Original line number Original line Diff line number Diff line
/*
 *
 * Backlight driver for HP Jornada 700 series (710/720/728)
 * Copyright (C) 2006-2009 Kristoffer Ericson <kristoffer.ericson@gmail.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 or any later version as published by the Free Software Foundation.
 *
 */

#include <linux/backlight.h>
#include <linux/device.h>
#include <linux/fb.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>

#include <mach/jornada720.h>
#include <mach/hardware.h>

#include <video/s1d13xxxfb.h>

#define BL_MAX_BRIGHT	255
#define BL_DEF_BRIGHT	25

static int jornada_bl_get_brightness(struct backlight_device *bd)
{
	int ret;

	/* check if backlight is on */
	if (!(PPSR & PPC_LDD1))
		return 0;

	jornada_ssp_start();

	/* cmd should return txdummy */
	ret = jornada_ssp_byte(GETBRIGHTNESS);

	if (jornada_ssp_byte(GETBRIGHTNESS) != TXDUMMY) {
		printk(KERN_ERR "bl : get brightness timeout\n");
		jornada_ssp_end();
		return -ETIMEDOUT;
	} else /* exchange txdummy for value */
		ret = jornada_ssp_byte(TXDUMMY);

	jornada_ssp_end();

	return (BL_MAX_BRIGHT - ret);
}

static int jornada_bl_update_status(struct backlight_device *bd)
{
	int ret = 0;

	jornada_ssp_start();

	/* If backlight is off then really turn it off */
	if ((bd->props.power != FB_BLANK_UNBLANK) || (bd->props.fb_blank != FB_BLANK_UNBLANK)) {
		ret = jornada_ssp_byte(BRIGHTNESSOFF);
		if (ret != TXDUMMY) {
			printk(KERN_INFO "bl : brightness off timeout\n");
			/* turn off backlight */
			PPSR &= ~PPC_LDD1;
			PPDR |= PPC_LDD1;
			ret = -ETIMEDOUT;
		}
	} else  /* turn on backlight */
		PPSR |= PPC_LDD1;

		/* send command to our mcu */
		if (jornada_ssp_byte(SETBRIGHTNESS) != TXDUMMY) {
			printk(KERN_INFO "bl : failed to set brightness\n");
			ret = -ETIMEDOUT;
			goto out
		}

		/* at this point we expect that the mcu has accepted
		   our command and is waiting for our new value
		   please note that maximum brightness is 255,
		   but due to physical layout it is equal to 0, so we simply
		   invert the value (MAX VALUE - NEW VALUE). */
		if (jornada_ssp_byte(BL_MAX_BRIGHT - bd->props.brightness) != TXDUMMY) {
			printk(KERN_ERR "bl : set brightness failed\n");
			ret = -ETIMEDOUT;
		}

		/* If infact we get an TXDUMMY as output we are happy and dont
		   make any further comments about it */
out:
	jornada_ssp_end();

	return ret;
}

static struct backlight_ops jornada_bl_ops = {
	.get_brightness = jornada_bl_get_brightness,
	.update_status = jornada_bl_update_status,
	.options = BL_CORE_SUSPENDRESUME,
};

static int jornada_bl_probe(struct platform_device *pdev)
{
	int ret;
	struct backlight_device *bd;

	bd = backlight_device_register(S1D_DEVICENAME, &pdev->dev, NULL, &jornada_bl_ops);

	if (IS_ERR(bd)) {
		ret = PTR_ERR(bd);
		printk(KERN_ERR "bl : failed to register device, err=%x\n", ret);
		return ret;
	}

	bd->props.power = FB_BLANK_UNBLANK;
	bd->props.brightness = BL_DEF_BRIGHT;
	/* note. make sure max brightness is set otherwise
	   you will get seemingly non-related errors when
	   trying to change brightness */
	bd->props.max_brightness = BL_MAX_BRIGHT;
	jornada_bl_update_status(bd);

	platform_set_drvdata(pdev, bd);
	printk(KERN_INFO "HP Jornada 700 series backlight driver\n");

	return 0;
}

static int jornada_bl_remove(struct platform_device *pdev)
{
	struct backlight_device *bd = platform_get_drvdata(pdev);

	backlight_device_unregister(bd);

	return 0;
}

static struct platform_driver jornada_bl_driver = {
	.probe		= jornada_bl_probe,
	.remove		= jornada_bl_remove,
	.driver	= {
		.name	= "jornada_bl",
	},
};

int __init jornada_bl_init(void)
{
	return platform_driver_register(&jornada_bl_driver);
}

void __exit jornada_bl_exit(void)
{
	platform_driver_unregister(&jornada_bl_driver);
}

MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson>");
MODULE_DESCRIPTION("HP Jornada 710/720/728 Backlight driver");
MODULE_LICENSE("GPL");

module_init(jornada_bl_init);
module_exit(jornada_bl_exit);
+153 −0
Original line number Original line Diff line number Diff line
/*
 *
 * LCD driver for HP Jornada 700 series (710/720/728)
 * Copyright (C) 2006-2009 Kristoffer Ericson <kristoffer.ericson@gmail.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 or any later version as published by the Free Software Foundation.
 *
 */

#include <linux/device.h>
#include <linux/fb.h>
#include <linux/kernel.h>
#include <linux/lcd.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/delay.h>

#include <mach/jornada720.h>
#include <mach/hardware.h>

#include <video/s1d13xxxfb.h>

#define LCD_MAX_CONTRAST	0xff
#define LCD_DEF_CONTRAST	0x80

static int jornada_lcd_get_power(struct lcd_device *dev)
{
	/* LDD2 in PPC = LCD POWER */
	if (PPSR & PPC_LDD2)
		return FB_BLANK_UNBLANK;	/* PW ON */
	else
		return FB_BLANK_POWERDOWN;	/* PW OFF */
}

static int jornada_lcd_get_contrast(struct lcd_device *dev)
{
	int ret;

	if (jornada_lcd_get_power(dev) != FB_BLANK_UNBLANK)
		return 0;

	jornada_ssp_start();

	if (jornada_ssp_byte(GETCONTRAST) != TXDUMMY) {
		printk(KERN_ERR "lcd: get contrast failed\n");
		jornada_ssp_end();
		return -ETIMEDOUT;
	} else {
		ret = jornada_ssp_byte(TXDUMMY);
		jornada_ssp_end();
		return ret;
	}
}

static int jornada_lcd_set_contrast(struct lcd_device *dev, int value)
{
	int ret;

	jornada_ssp_start();

	/* start by sending our set contrast cmd to mcu */
	ret = jornada_ssp_byte(SETCONTRAST);

	/* push the new value */
	if (jornada_ssp_byte(value) != TXDUMMY) {
		printk(KERN_ERR "lcd : set contrast failed\n");
		jornada_ssp_end();
		return -ETIMEDOUT;
	}

	/* if we get here we can assume everything went well */
	jornada_ssp_end();

	return 0;
}

static int jornada_lcd_set_power(struct lcd_device *dev, int power)
{
	if (power != FB_BLANK_UNBLANK) {
		PPSR &= ~PPC_LDD2;
		PPDR |= PPC_LDD2;
	} else
		PPSR |= PPC_LDD2;

	return 0;
}

static struct lcd_ops jornada_lcd_props = {
	.get_contrast = jornada_lcd_get_contrast,
	.set_contrast = jornada_lcd_set_contrast,
	.get_power = jornada_lcd_get_power,
	.set_power = jornada_lcd_set_power,
};

static int jornada_lcd_probe(struct platform_device *pdev)
{
	struct lcd_device *lcd_device;
	int ret;

	lcd_device = lcd_device_register(S1D_DEVICENAME, &pdev->dev, NULL, &jornada_lcd_props);

	if (IS_ERR(lcd_device)) {
		ret = PTR_ERR(lcd_device);
		printk(KERN_ERR "lcd : failed to register device\n");
		return ret;
	}

	platform_set_drvdata(pdev, lcd_device);

	/* lets set our default values */
	jornada_lcd_set_contrast(lcd_device, LCD_DEF_CONTRAST);
	jornada_lcd_set_power(lcd_device, FB_BLANK_UNBLANK);
	/* give it some time to startup */
	msleep(100);

	return 0;
}

static int jornada_lcd_remove(struct platform_device *pdev)
{
	struct lcd_device *lcd_device = platform_get_drvdata(pdev);

	lcd_device_unregister(lcd_device);

	return 0;
}

static struct platform_driver jornada_lcd_driver = {
	.probe	= jornada_lcd_probe,
	.remove	= jornada_lcd_remove,
	.driver	= {
		.name	= "jornada_lcd",
	},
};

int __init jornada_lcd_init(void)
{
	return platform_driver_register(&jornada_lcd_driver);
}

void __exit jornada_lcd_exit(void)
{
	platform_driver_unregister(&jornada_lcd_driver);
}

MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
MODULE_DESCRIPTION("HP Jornada 710/720/728 LCD driver");
MODULE_LICENSE("GPL");

module_init(jornada_lcd_init);
module_exit(jornada_lcd_exit);
+155 −36
Original line number Original line Diff line number Diff line
@@ -27,52 +27,171 @@


static struct backlight_device *mbp_backlight_device;
static struct backlight_device *mbp_backlight_device;


static struct dmi_system_id __initdata mbp_device_table[] = {
/* Structure to be passed to the DMI_MATCH function. */
struct dmi_match_data {
	/* I/O resource to allocate. */
	unsigned long iostart;
	unsigned long iolen;
	/* Backlight operations structure. */
	struct backlight_ops backlight_ops;
};

/* Module parameters. */
static int debug;
module_param_named(debug, debug, int, 0644);
MODULE_PARM_DESC(debug, "Set to one to enable debugging messages.");

/*
 * Implementation for MacBooks with Intel chipset.
 */
static int intel_chipset_send_intensity(struct backlight_device *bd)
{
	int intensity = bd->props.brightness;

	if (debug)
		printk(KERN_DEBUG "mbp_nvidia_bl: setting brightness to %d\n",
		       intensity);

	outb(0x04 | (intensity << 4), 0xb3);
	outb(0xbf, 0xb2);
	return 0;
}

static int intel_chipset_get_intensity(struct backlight_device *bd)
{
	int intensity;

	outb(0x03, 0xb3);
	outb(0xbf, 0xb2);
	intensity = inb(0xb3) >> 4;

	if (debug)
		printk(KERN_DEBUG "mbp_nvidia_bl: read brightness of %d\n",
		       intensity);

	return intensity;
}

static const struct dmi_match_data intel_chipset_data = {
	.iostart = 0xb2,
	.iolen = 2,
	.backlight_ops	= {
		.options	= BL_CORE_SUSPENDRESUME,
		.get_brightness	= intel_chipset_get_intensity,
		.update_status	= intel_chipset_send_intensity,
	}
};

/*
 * Implementation for MacBooks with Nvidia chipset.
 */
static int nvidia_chipset_send_intensity(struct backlight_device *bd)
{
	int intensity = bd->props.brightness;

	if (debug)
		printk(KERN_DEBUG "mbp_nvidia_bl: setting brightness to %d\n",
		       intensity);

	outb(0x04 | (intensity << 4), 0x52f);
	outb(0xbf, 0x52e);
	return 0;
}

static int nvidia_chipset_get_intensity(struct backlight_device *bd)
{
	int intensity;

	outb(0x03, 0x52f);
	outb(0xbf, 0x52e);
	intensity = inb(0x52f) >> 4;

	if (debug)
		printk(KERN_DEBUG "mbp_nvidia_bl: read brightness of %d\n",
		       intensity);

	return intensity;
}

static const struct dmi_match_data nvidia_chipset_data = {
	.iostart = 0x52e,
	.iolen = 2,
	.backlight_ops		= {
		.options	= BL_CORE_SUSPENDRESUME,
		.get_brightness	= nvidia_chipset_get_intensity,
		.update_status	= nvidia_chipset_send_intensity
	}
};

/*
 * DMI matching.
 */
static /* const */ struct dmi_match_data *driver_data;

static int mbp_dmi_match(const struct dmi_system_id *id)
{
	driver_data = id->driver_data;

	printk(KERN_INFO "mbp_nvidia_bl: %s detected\n", id->ident);
	return 1;
}

static const struct dmi_system_id __initdata mbp_device_table[] = {
	{
	{
		.ident = "3,1",
		.callback	= mbp_dmi_match,
		.ident		= "MacBookPro 3,1",
		.matches	= {
		.matches	= {
			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
		},
		},
		.driver_data	= (void *)&intel_chipset_data,
	},
	},
	{
	{
		.ident = "3,2",
		.callback	= mbp_dmi_match,
		.ident		= "MacBookPro 3,2",
		.matches	= {
		.matches	= {
			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,2"),
			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,2"),
		},
		},
		.driver_data	= (void *)&intel_chipset_data,
	},
	},
	{
	{
		.ident = "4,1",
		.callback	= mbp_dmi_match,
		.ident		= "MacBookPro 4,1",
		.matches	= {
		.matches	= {
			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4,1"),
			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4,1"),
		},
		},
		.driver_data	= (void *)&intel_chipset_data,
	},
	},
	{ }
};

static int mbp_send_intensity(struct backlight_device *bd)
	{
	{
	int intensity = bd->props.brightness;
		.callback	= mbp_dmi_match,

		.ident		= "MacBook 5,1",
	outb(0x04 | (intensity << 4), 0xb3);
		.matches	= {
	outb(0xbf, 0xb2);
			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),

			DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5,1"),
	return 0;
		},
}
		.driver_data	= (void *)&nvidia_chipset_data,

	},
static int mbp_get_intensity(struct backlight_device *bd)
	{
	{
	outb(0x03, 0xb3);
		.callback	= mbp_dmi_match,
	outb(0xbf, 0xb2);
		.ident		= "MacBookAir 2,1",
	return inb(0xb3) >> 4;
		.matches	= {
}
			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),

			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2,1"),
static struct backlight_ops mbp_ops = {
		},
	.options = BL_CORE_SUSPENDRESUME,
		.driver_data	= (void *)&nvidia_chipset_data,
	.get_brightness = mbp_get_intensity,
	},
	.update_status  = mbp_send_intensity,
	{
		.callback	= mbp_dmi_match,
		.ident		= "MacBookPro 5,1",
		.matches	= {
			DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
			DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,1"),
		},
		.driver_data	= (void *)&nvidia_chipset_data,
	},
	{ }
};
};


static int __init mbp_init(void)
static int __init mbp_init(void)
@@ -80,20 +199,20 @@ static int __init mbp_init(void)
	if (!dmi_check_system(mbp_device_table))
	if (!dmi_check_system(mbp_device_table))
		return -ENODEV;
		return -ENODEV;


	if (!request_region(0xb2, 2, "Macbook Pro backlight"))
	if (!request_region(driver_data->iostart, driver_data->iolen, 
						"Macbook Pro backlight"))
		return -ENXIO;
		return -ENXIO;


	mbp_backlight_device = backlight_device_register("mbp_backlight",
	mbp_backlight_device = backlight_device_register("mbp_backlight",
							 NULL, NULL,
					NULL, NULL, &driver_data->backlight_ops);
							 &mbp_ops);
	if (IS_ERR(mbp_backlight_device)) {
	if (IS_ERR(mbp_backlight_device)) {
		release_region(0xb2, 2);
		release_region(driver_data->iostart, driver_data->iolen);
		return PTR_ERR(mbp_backlight_device);
		return PTR_ERR(mbp_backlight_device);
	}
	}


	mbp_backlight_device->props.max_brightness = 15;
	mbp_backlight_device->props.max_brightness = 15;
	mbp_backlight_device->props.brightness =
	mbp_backlight_device->props.brightness =
		mbp_get_intensity(mbp_backlight_device);
		driver_data->backlight_ops.get_brightness(mbp_backlight_device);
	backlight_update_status(mbp_backlight_device);
	backlight_update_status(mbp_backlight_device);


	return 0;
	return 0;
@@ -103,7 +222,7 @@ static void __exit mbp_exit(void)
{
{
	backlight_device_unregister(mbp_backlight_device);
	backlight_device_unregister(mbp_backlight_device);


	release_region(0xb2, 2);
	release_region(driver_data->iostart, driver_data->iolen);
}
}


module_init(mbp_init);
module_init(mbp_init);
Loading