1 /*
2  *  Backlight Driver for Frontpath ProGear HX1050+
3  *
4  *  Copyright (c) 2006 Marcin Juszkiewicz
5  *
6  *  Based on Progear LCD driver by M Schacht
7  *  <mschacht at alumni dot washington dot edu>
8  *
9  *  Based on Sharp's Corgi Backlight Driver
10  *  Based on Backlight Driver for HP Jornada 680
11  *
12  *  This program is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License version 2 as
14  *  published by the Free Software Foundation.
15  *
16  */
17 
18 #include <linux/module.h>
19 #include <linux/kernel.h>
20 #include <linux/init.h>
21 #include <linux/platform_device.h>
22 #include <linux/mutex.h>
23 #include <linux/fb.h>
24 #include <linux/backlight.h>
25 #include <linux/pci.h>
26 
27 #define PMU_LPCR               0xB0
28 #define SB_MPS1                0x61
29 #define HW_LEVEL_MAX           0x77
30 #define HW_LEVEL_MIN           0x4f
31 
32 static struct pci_dev *pmu_dev = NULL;
33 static struct pci_dev *sb_dev = NULL;
34 
progearbl_set_intensity(struct backlight_device * bd)35 static int progearbl_set_intensity(struct backlight_device *bd)
36 {
37 	int intensity = bd->props.brightness;
38 
39 	if (bd->props.power != FB_BLANK_UNBLANK)
40 		intensity = 0;
41 	if (bd->props.fb_blank != FB_BLANK_UNBLANK)
42 		intensity = 0;
43 
44 	pci_write_config_byte(pmu_dev, PMU_LPCR, intensity + HW_LEVEL_MIN);
45 
46 	return 0;
47 }
48 
progearbl_get_intensity(struct backlight_device * bd)49 static int progearbl_get_intensity(struct backlight_device *bd)
50 {
51 	u8 intensity;
52 	pci_read_config_byte(pmu_dev, PMU_LPCR, &intensity);
53 
54 	return intensity - HW_LEVEL_MIN;
55 }
56 
57 static const struct backlight_ops progearbl_ops = {
58 	.get_brightness = progearbl_get_intensity,
59 	.update_status = progearbl_set_intensity,
60 };
61 
progearbl_probe(struct platform_device * pdev)62 static int progearbl_probe(struct platform_device *pdev)
63 {
64 	struct backlight_properties props;
65 	u8 temp;
66 	struct backlight_device *progear_backlight_device;
67 	int ret;
68 
69 	pmu_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, NULL);
70 	if (!pmu_dev) {
71 		printk("ALI M7101 PMU not found.\n");
72 		return -ENODEV;
73 	}
74 
75 	sb_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
76 	if (!sb_dev) {
77 		printk("ALI 1533 SB not found.\n");
78 		ret = -ENODEV;
79 		goto put_pmu;
80 	}
81 
82 	/*     Set SB_MPS1 to enable brightness control. */
83 	pci_read_config_byte(sb_dev, SB_MPS1, &temp);
84 	pci_write_config_byte(sb_dev, SB_MPS1, temp | 0x20);
85 
86 	memset(&props, 0, sizeof(struct backlight_properties));
87 	props.type = BACKLIGHT_RAW;
88 	props.max_brightness = HW_LEVEL_MAX - HW_LEVEL_MIN;
89 	progear_backlight_device = backlight_device_register("progear-bl",
90 							     &pdev->dev, NULL,
91 							     &progearbl_ops,
92 							     &props);
93 	if (IS_ERR(progear_backlight_device)) {
94 		ret = PTR_ERR(progear_backlight_device);
95 		goto put_sb;
96 	}
97 
98 	platform_set_drvdata(pdev, progear_backlight_device);
99 
100 	progear_backlight_device->props.power = FB_BLANK_UNBLANK;
101 	progear_backlight_device->props.brightness = HW_LEVEL_MAX - HW_LEVEL_MIN;
102 	progearbl_set_intensity(progear_backlight_device);
103 
104 	return 0;
105 put_sb:
106 	pci_dev_put(sb_dev);
107 put_pmu:
108 	pci_dev_put(pmu_dev);
109 	return ret;
110 }
111 
progearbl_remove(struct platform_device * pdev)112 static int progearbl_remove(struct platform_device *pdev)
113 {
114 	struct backlight_device *bd = platform_get_drvdata(pdev);
115 	backlight_device_unregister(bd);
116 
117 	return 0;
118 }
119 
120 static struct platform_driver progearbl_driver = {
121 	.probe = progearbl_probe,
122 	.remove = progearbl_remove,
123 	.driver = {
124 		   .name = "progear-bl",
125 		   },
126 };
127 
128 static struct platform_device *progearbl_device;
129 
progearbl_init(void)130 static int __init progearbl_init(void)
131 {
132 	int ret = platform_driver_register(&progearbl_driver);
133 
134 	if (ret)
135 		return ret;
136 	progearbl_device = platform_device_register_simple("progear-bl", -1,
137 								NULL, 0);
138 	if (IS_ERR(progearbl_device)) {
139 		platform_driver_unregister(&progearbl_driver);
140 		return PTR_ERR(progearbl_device);
141 	}
142 
143 	return 0;
144 }
145 
progearbl_exit(void)146 static void __exit progearbl_exit(void)
147 {
148 	pci_dev_put(pmu_dev);
149 	pci_dev_put(sb_dev);
150 
151 	platform_device_unregister(progearbl_device);
152 	platform_driver_unregister(&progearbl_driver);
153 }
154 
155 module_init(progearbl_init);
156 module_exit(progearbl_exit);
157 
158 MODULE_AUTHOR("Marcin Juszkiewicz <linux@hrw.one.pl>");
159 MODULE_DESCRIPTION("ProGear Backlight Driver");
160 MODULE_LICENSE("GPL");
161