aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/aty/aty128fb.c
diff options
context:
space:
mode:
authorMichael Hanselmann <linux-kernel@hansmi.ch>2006-06-25 08:47:08 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-25 13:00:59 -0400
commit5474c120aafe78ca54bf272f7a01107c42da2b21 (patch)
treec1b002a27703ce92c816bfb9844752186e33d403 /drivers/video/aty/aty128fb.c
parent17660bdd5c1f1a165273c1a59cb5b87670a81cc4 (diff)
[PATCH] Rewritten backlight infrastructure for portable Apple computers
This patch contains a total rewrite of the backlight infrastructure for portable Apple computers. Backward compatibility is retained. A sysfs interface allows userland to control the brightness with more steps than before. Userland is allowed to upload a brightness curve for different monitors, similar to Mac OS X. [akpm@osdl.org: add needed exports] Signed-off-by: Michael Hanselmann <linux-kernel@hansmi.ch> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Richard Purdie <rpurdie@rpsys.net> Cc: "Antonino A. Daplas" <adaplas@pol.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/video/aty/aty128fb.c')
-rw-r--r--drivers/video/aty/aty128fb.c322
1 files changed, 225 insertions, 97 deletions
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index f7bbff4ddc6a..db878fd55fb2 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -64,6 +64,7 @@
64#include <linux/pci.h> 64#include <linux/pci.h>
65#include <linux/ioport.h> 65#include <linux/ioport.h>
66#include <linux/console.h> 66#include <linux/console.h>
67#include <linux/backlight.h>
67#include <asm/io.h> 68#include <asm/io.h>
68 69
69#ifdef CONFIG_PPC_PMAC 70#ifdef CONFIG_PPC_PMAC
@@ -480,16 +481,6 @@ static struct fb_ops aty128fb_ops = {
480 .fb_imageblit = cfb_imageblit, 481 .fb_imageblit = cfb_imageblit,
481}; 482};
482 483
483#ifdef CONFIG_PMAC_BACKLIGHT
484static int aty128_set_backlight_enable(int on, int level, void* data);
485static int aty128_set_backlight_level(int level, void* data);
486
487static struct backlight_controller aty128_backlight_controller = {
488 aty128_set_backlight_enable,
489 aty128_set_backlight_level
490};
491#endif /* CONFIG_PMAC_BACKLIGHT */
492
493 /* 484 /*
494 * Functions to read from/write to the mmio registers 485 * Functions to read from/write to the mmio registers
495 * - endian conversions may possibly be avoided by 486 * - endian conversions may possibly be avoided by
@@ -1258,19 +1249,35 @@ static void aty128_set_crt_enable(struct aty128fb_par *par, int on)
1258static void aty128_set_lcd_enable(struct aty128fb_par *par, int on) 1249static void aty128_set_lcd_enable(struct aty128fb_par *par, int on)
1259{ 1250{
1260 u32 reg; 1251 u32 reg;
1252#ifdef CONFIG_FB_ATY128_BACKLIGHT
1253 struct fb_info *info = pci_get_drvdata(par->pdev);
1254#endif
1261 1255
1262 if (on) { 1256 if (on) {
1263 reg = aty_ld_le32(LVDS_GEN_CNTL); 1257 reg = aty_ld_le32(LVDS_GEN_CNTL);
1264 reg |= LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION; 1258 reg |= LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION;
1265 reg &= ~LVDS_DISPLAY_DIS; 1259 reg &= ~LVDS_DISPLAY_DIS;
1266 aty_st_le32(LVDS_GEN_CNTL, reg); 1260 aty_st_le32(LVDS_GEN_CNTL, reg);
1267#ifdef CONFIG_PMAC_BACKLIGHT 1261#ifdef CONFIG_FB_ATY128_BACKLIGHT
1268 aty128_set_backlight_enable(get_backlight_enable(), 1262 mutex_lock(&info->bl_mutex);
1269 get_backlight_level(), par); 1263 if (info->bl_dev) {
1264 down(&info->bl_dev->sem);
1265 info->bl_dev->props->update_status(info->bl_dev);
1266 up(&info->bl_dev->sem);
1267 }
1268 mutex_unlock(&info->bl_mutex);
1270#endif 1269#endif
1271 } else { 1270 } else {
1272#ifdef CONFIG_PMAC_BACKLIGHT 1271#ifdef CONFIG_FB_ATY128_BACKLIGHT
1273 aty128_set_backlight_enable(0, 0, par); 1272 mutex_lock(&info->bl_mutex);
1273 if (info->bl_dev) {
1274 down(&info->bl_dev->sem);
1275 info->bl_dev->props->brightness = 0;
1276 info->bl_dev->props->power = FB_BLANK_POWERDOWN;
1277 info->bl_dev->props->update_status(info->bl_dev);
1278 up(&info->bl_dev->sem);
1279 }
1280 mutex_unlock(&info->bl_mutex);
1274#endif 1281#endif
1275 reg = aty_ld_le32(LVDS_GEN_CNTL); 1282 reg = aty_ld_le32(LVDS_GEN_CNTL);
1276 reg |= LVDS_DISPLAY_DIS; 1283 reg |= LVDS_DISPLAY_DIS;
@@ -1691,6 +1698,184 @@ static int __init aty128fb_setup(char *options)
1691} 1698}
1692#endif /* MODULE */ 1699#endif /* MODULE */
1693 1700
1701/* Backlight */
1702#ifdef CONFIG_FB_ATY128_BACKLIGHT
1703#define MAX_LEVEL 0xFF
1704
1705static struct backlight_properties aty128_bl_data;
1706
1707static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
1708 int level)
1709{
1710 struct fb_info *info = pci_get_drvdata(par->pdev);
1711 int atylevel;
1712
1713 /* Get and convert the value */
1714 mutex_lock(&info->bl_mutex);
1715 atylevel = MAX_LEVEL -
1716 (info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL);
1717 mutex_unlock(&info->bl_mutex);
1718
1719 if (atylevel < 0)
1720 atylevel = 0;
1721 else if (atylevel > MAX_LEVEL)
1722 atylevel = MAX_LEVEL;
1723
1724 return atylevel;
1725}
1726
1727/* We turn off the LCD completely instead of just dimming the backlight.
1728 * This provides greater power saving and the display is useless without
1729 * backlight anyway
1730 */
1731#define BACKLIGHT_LVDS_OFF
1732/* That one prevents proper CRT output with LCD off */
1733#undef BACKLIGHT_DAC_OFF
1734
1735static int aty128_bl_update_status(struct backlight_device *bd)
1736{
1737 struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
1738 unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
1739 int level;
1740
1741 if (bd->props->power != FB_BLANK_UNBLANK ||
1742 bd->props->fb_blank != FB_BLANK_UNBLANK ||
1743 !par->lcd_on)
1744 level = 0;
1745 else
1746 level = bd->props->brightness;
1747
1748 reg |= LVDS_BL_MOD_EN | LVDS_BLON;
1749 if (level > 0) {
1750 reg |= LVDS_DIGION;
1751 if (!(reg & LVDS_ON)) {
1752 reg &= ~LVDS_BLON;
1753 aty_st_le32(LVDS_GEN_CNTL, reg);
1754 aty_ld_le32(LVDS_GEN_CNTL);
1755 mdelay(10);
1756 reg |= LVDS_BLON;
1757 aty_st_le32(LVDS_GEN_CNTL, reg);
1758 }
1759 reg &= ~LVDS_BL_MOD_LEVEL_MASK;
1760 reg |= (aty128_bl_get_level_brightness(par, level) << LVDS_BL_MOD_LEVEL_SHIFT);
1761#ifdef BACKLIGHT_LVDS_OFF
1762 reg |= LVDS_ON | LVDS_EN;
1763 reg &= ~LVDS_DISPLAY_DIS;
1764#endif
1765 aty_st_le32(LVDS_GEN_CNTL, reg);
1766#ifdef BACKLIGHT_DAC_OFF
1767 aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));
1768#endif
1769 } else {
1770 reg &= ~LVDS_BL_MOD_LEVEL_MASK;
1771 reg |= (aty128_bl_get_level_brightness(par, 0) << LVDS_BL_MOD_LEVEL_SHIFT);
1772#ifdef BACKLIGHT_LVDS_OFF
1773 reg |= LVDS_DISPLAY_DIS;
1774 aty_st_le32(LVDS_GEN_CNTL, reg);
1775 aty_ld_le32(LVDS_GEN_CNTL);
1776 udelay(10);
1777 reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);
1778#endif
1779 aty_st_le32(LVDS_GEN_CNTL, reg);
1780#ifdef BACKLIGHT_DAC_OFF
1781 aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);
1782#endif
1783 }
1784
1785 return 0;
1786}
1787
1788static int aty128_bl_get_brightness(struct backlight_device *bd)
1789{
1790 return bd->props->brightness;
1791}
1792
1793static struct backlight_properties aty128_bl_data = {
1794 .owner = THIS_MODULE,
1795 .get_brightness = aty128_bl_get_brightness,
1796 .update_status = aty128_bl_update_status,
1797 .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
1798};
1799
1800static void aty128_bl_init(struct aty128fb_par *par)
1801{
1802 struct fb_info *info = pci_get_drvdata(par->pdev);
1803 struct backlight_device *bd;
1804 char name[12];
1805
1806 /* Could be extended to Rage128Pro LVDS output too */
1807 if (par->chip_gen != rage_M3)
1808 return;
1809
1810#ifdef CONFIG_PMAC_BACKLIGHT
1811 if (!pmac_has_backlight_type("ati"))
1812 return;
1813#endif
1814
1815 snprintf(name, sizeof(name), "aty128bl%d", info->node);
1816
1817 bd = backlight_device_register(name, par, &aty128_bl_data);
1818 if (IS_ERR(bd)) {
1819 info->bl_dev = NULL;
1820 printk("aty128: Backlight registration failed\n");
1821 goto error;
1822 }
1823
1824 mutex_lock(&info->bl_mutex);
1825 info->bl_dev = bd;
1826 fb_bl_default_curve(info, 0,
1827 63 * FB_BACKLIGHT_MAX / MAX_LEVEL,
1828 219 * FB_BACKLIGHT_MAX / MAX_LEVEL);
1829 mutex_unlock(&info->bl_mutex);
1830
1831 up(&bd->sem);
1832 bd->props->brightness = aty128_bl_data.max_brightness;
1833 bd->props->power = FB_BLANK_UNBLANK;
1834 bd->props->update_status(bd);
1835 down(&bd->sem);
1836
1837#ifdef CONFIG_PMAC_BACKLIGHT
1838 mutex_lock(&pmac_backlight_mutex);
1839 if (!pmac_backlight)
1840 pmac_backlight = bd;
1841 mutex_unlock(&pmac_backlight_mutex);
1842#endif
1843
1844 printk("aty128: Backlight initialized (%s)\n", name);
1845
1846 return;
1847
1848error:
1849 return;
1850}
1851
1852static void aty128_bl_exit(struct aty128fb_par *par)
1853{
1854 struct fb_info *info = pci_get_drvdata(par->pdev);
1855
1856#ifdef CONFIG_PMAC_BACKLIGHT
1857 mutex_lock(&pmac_backlight_mutex);
1858#endif
1859
1860 mutex_lock(&info->bl_mutex);
1861 if (info->bl_dev) {
1862#ifdef CONFIG_PMAC_BACKLIGHT
1863 if (pmac_backlight == info->bl_dev)
1864 pmac_backlight = NULL;
1865#endif
1866
1867 backlight_device_unregister(info->bl_dev);
1868 info->bl_dev = NULL;
1869
1870 printk("aty128: Backlight unloaded\n");
1871 }
1872 mutex_unlock(&info->bl_mutex);
1873
1874#ifdef CONFIG_PMAC_BACKLIGHT
1875 mutex_unlock(&pmac_backlight_mutex);
1876#endif
1877}
1878#endif /* CONFIG_FB_ATY128_BACKLIGHT */
1694 1879
1695/* 1880/*
1696 * Initialisation 1881 * Initialisation
@@ -1835,17 +2020,15 @@ static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *
1835 if (register_framebuffer(info) < 0) 2020 if (register_framebuffer(info) < 0)
1836 return 0; 2021 return 0;
1837 2022
1838#ifdef CONFIG_PMAC_BACKLIGHT
1839 /* Could be extended to Rage128Pro LVDS output too */
1840 if (par->chip_gen == rage_M3)
1841 register_backlight_controller(&aty128_backlight_controller, par, "ati");
1842#endif /* CONFIG_PMAC_BACKLIGHT */
1843
1844 par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM); 2023 par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
1845 par->pdev = pdev; 2024 par->pdev = pdev;
1846 par->asleep = 0; 2025 par->asleep = 0;
1847 par->lock_blank = 0; 2026 par->lock_blank = 0;
1848 2027
2028#ifdef CONFIG_FB_ATY128_BACKLIGHT
2029 aty128_bl_init(par);
2030#endif
2031
1849 printk(KERN_INFO "fb%d: %s frame buffer device on %s\n", 2032 printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",
1850 info->node, info->fix.id, video_card); 2033 info->node, info->fix.id, video_card);
1851 2034
@@ -1981,6 +2164,10 @@ static void __devexit aty128_remove(struct pci_dev *pdev)
1981 2164
1982 par = info->par; 2165 par = info->par;
1983 2166
2167#ifdef CONFIG_FB_ATY128_BACKLIGHT
2168 aty128_bl_exit(par);
2169#endif
2170
1984 unregister_framebuffer(info); 2171 unregister_framebuffer(info);
1985#ifdef CONFIG_MTRR 2172#ifdef CONFIG_MTRR
1986 if (par->mtrr.vram_valid) 2173 if (par->mtrr.vram_valid)
@@ -2011,10 +2198,14 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
2011 if (par->lock_blank || par->asleep) 2198 if (par->lock_blank || par->asleep)
2012 return 0; 2199 return 0;
2013 2200
2014#ifdef CONFIG_PMAC_BACKLIGHT 2201#ifdef CONFIG_FB_ATY128_BACKLIGHT
2015 if (machine_is(powermac) && blank) 2202 if (machine_is(powermac) && blank) {
2016 set_backlight_enable(0); 2203 down(&fb->bl_dev->sem);
2017#endif /* CONFIG_PMAC_BACKLIGHT */ 2204 fb->bl_dev->props->power = FB_BLANK_POWERDOWN;
2205 fb->bl_dev->props->update_status(fb->bl_dev);
2206 up(&fb->bl_dev->sem);
2207 }
2208#endif
2018 2209
2019 if (blank & FB_BLANK_VSYNC_SUSPEND) 2210 if (blank & FB_BLANK_VSYNC_SUSPEND)
2020 state |= 2; 2211 state |= 2;
@@ -2029,10 +2220,14 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
2029 aty128_set_crt_enable(par, par->crt_on && !blank); 2220 aty128_set_crt_enable(par, par->crt_on && !blank);
2030 aty128_set_lcd_enable(par, par->lcd_on && !blank); 2221 aty128_set_lcd_enable(par, par->lcd_on && !blank);
2031 } 2222 }
2032#ifdef CONFIG_PMAC_BACKLIGHT 2223#ifdef CONFIG_FB_ATY128_BACKLIGHT
2033 if (machine_is(powermac) && !blank) 2224 if (machine_is(powermac) && !blank) {
2034 set_backlight_enable(1); 2225 down(&fb->bl_dev->sem);
2035#endif /* CONFIG_PMAC_BACKLIGHT */ 2226 fb->bl_dev->props->power = FB_BLANK_UNBLANK;
2227 fb->bl_dev->props->update_status(fb->bl_dev);
2228 up(&fb->bl_dev->sem);
2229 }
2230#endif
2036 return 0; 2231 return 0;
2037} 2232}
2038 2233
@@ -2138,73 +2333,6 @@ static int aty128fb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
2138 return -EINVAL; 2333 return -EINVAL;
2139} 2334}
2140 2335
2141#ifdef CONFIG_PMAC_BACKLIGHT
2142static int backlight_conv[] = {
2143 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
2144 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
2145};
2146
2147/* We turn off the LCD completely instead of just dimming the backlight.
2148 * This provides greater power saving and the display is useless without
2149 * backlight anyway
2150 */
2151#define BACKLIGHT_LVDS_OFF
2152/* That one prevents proper CRT output with LCD off */
2153#undef BACKLIGHT_DAC_OFF
2154
2155static int aty128_set_backlight_enable(int on, int level, void *data)
2156{
2157 struct aty128fb_par *par = data;
2158 unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
2159
2160 if (!par->lcd_on)
2161 on = 0;
2162 reg |= LVDS_BL_MOD_EN | LVDS_BLON;
2163 if (on && level > BACKLIGHT_OFF) {
2164 reg |= LVDS_DIGION;
2165 if (!(reg & LVDS_ON)) {
2166 reg &= ~LVDS_BLON;
2167 aty_st_le32(LVDS_GEN_CNTL, reg);
2168 (void)aty_ld_le32(LVDS_GEN_CNTL);
2169 mdelay(10);
2170 reg |= LVDS_BLON;
2171 aty_st_le32(LVDS_GEN_CNTL, reg);
2172 }
2173 reg &= ~LVDS_BL_MOD_LEVEL_MASK;
2174 reg |= (backlight_conv[level] << LVDS_BL_MOD_LEVEL_SHIFT);
2175#ifdef BACKLIGHT_LVDS_OFF
2176 reg |= LVDS_ON | LVDS_EN;
2177 reg &= ~LVDS_DISPLAY_DIS;
2178#endif
2179 aty_st_le32(LVDS_GEN_CNTL, reg);
2180#ifdef BACKLIGHT_DAC_OFF
2181 aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));
2182#endif
2183 } else {
2184 reg &= ~LVDS_BL_MOD_LEVEL_MASK;
2185 reg |= (backlight_conv[0] << LVDS_BL_MOD_LEVEL_SHIFT);
2186#ifdef BACKLIGHT_LVDS_OFF
2187 reg |= LVDS_DISPLAY_DIS;
2188 aty_st_le32(LVDS_GEN_CNTL, reg);
2189 (void)aty_ld_le32(LVDS_GEN_CNTL);
2190 udelay(10);
2191 reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);
2192#endif
2193 aty_st_le32(LVDS_GEN_CNTL, reg);
2194#ifdef BACKLIGHT_DAC_OFF
2195 aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);
2196#endif
2197 }
2198
2199 return 0;
2200}
2201
2202static int aty128_set_backlight_level(int level, void* data)
2203{
2204 return aty128_set_backlight_enable(1, level, data);
2205}
2206#endif /* CONFIG_PMAC_BACKLIGHT */
2207
2208#if 0 2336#if 0
2209 /* 2337 /*
2210 * Accelerated functions 2338 * Accelerated functions