blacklight: remove redundant spi driver bus initialization
[deliverable/linux.git] / drivers / video / backlight / apple_bl.c
CommitLineData
7be35c72 1/*
39b3dee7 2 * Backlight Driver for Intel-based Apples
7be35c72
MG
3 *
4 * Copyright (c) Red Hat <mjg@redhat.com>
5 * Based on code from Pommed:
6 * Copyright (C) 2006 Nicolas Boichat <nicolas @boichat.ch>
7 * Copyright (C) 2006 Felipe Alfaro Solana <felipe_alfaro @linuxmail.org>
8 * Copyright (C) 2007 Julien BLACHE <jb@jblache.org>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * This driver triggers SMIs which cause the firmware to change the
15 * backlight brightness. This is icky in many ways, but it's impractical to
16 * get at the firmware code in order to figure out what it's actually doing.
17 */
18
19#include <linux/module.h>
20#include <linux/kernel.h>
21#include <linux/init.h>
7be35c72
MG
22#include <linux/backlight.h>
23#include <linux/err.h>
7be35c72 24#include <linux/io.h>
23a9847f
MG
25#include <linux/pci.h>
26#include <linux/acpi.h>
83e72dd9 27#include <linux/atomic.h>
7be35c72 28
39b3dee7 29static struct backlight_device *apple_backlight_device;
7be35c72 30
23a9847f 31struct hw_data {
c78a6288
MS
32 /* I/O resource to allocate. */
33 unsigned long iostart;
34 unsigned long iolen;
35 /* Backlight operations structure. */
9905a43b 36 const struct backlight_ops backlight_ops;
23a9847f 37 void (*set_brightness)(int);
7be35c72
MG
38};
39
23a9847f
MG
40static const struct hw_data *hw_data;
41
39b3dee7 42#define DRIVER "apple_backlight: "
23a9847f 43
1a468ba1
MS
44/* Module parameters. */
45static int debug;
46module_param_named(debug, debug, int, 0644);
47MODULE_PARM_DESC(debug, "Set to one to enable debugging messages.");
48
c78a6288 49/*
39b3dee7 50 * Implementation for machines with Intel chipset.
c78a6288 51 */
23a9847f
MG
52static void intel_chipset_set_brightness(int intensity)
53{
54 outb(0x04 | (intensity << 4), 0xb3);
55 outb(0xbf, 0xb2);
56}
57
c78a6288 58static int intel_chipset_send_intensity(struct backlight_device *bd)
7be35c72
MG
59{
60 int intensity = bd->props.brightness;
61
1a468ba1 62 if (debug)
23a9847f 63 printk(KERN_DEBUG DRIVER "setting brightness to %d\n",
1a468ba1
MS
64 intensity);
65
23a9847f 66 intel_chipset_set_brightness(intensity);
7be35c72
MG
67 return 0;
68}
69
c78a6288 70static int intel_chipset_get_intensity(struct backlight_device *bd)
7be35c72 71{
1a468ba1
MS
72 int intensity;
73
7be35c72
MG
74 outb(0x03, 0xb3);
75 outb(0xbf, 0xb2);
1a468ba1
MS
76 intensity = inb(0xb3) >> 4;
77
78 if (debug)
23a9847f 79 printk(KERN_DEBUG DRIVER "read brightness of %d\n",
1a468ba1
MS
80 intensity);
81
82 return intensity;
7be35c72
MG
83}
84
23a9847f 85static const struct hw_data intel_chipset_data = {
c78a6288
MS
86 .iostart = 0xb2,
87 .iolen = 2,
88 .backlight_ops = {
89 .options = BL_CORE_SUSPENDRESUME,
90 .get_brightness = intel_chipset_get_intensity,
91 .update_status = intel_chipset_send_intensity,
23a9847f
MG
92 },
93 .set_brightness = intel_chipset_set_brightness,
c78a6288
MS
94};
95
96/*
39b3dee7 97 * Implementation for machines with Nvidia chipset.
c78a6288 98 */
23a9847f
MG
99static void nvidia_chipset_set_brightness(int intensity)
100{
101 outb(0x04 | (intensity << 4), 0x52f);
102 outb(0xbf, 0x52e);
103}
104
c78a6288
MS
105static int nvidia_chipset_send_intensity(struct backlight_device *bd)
106{
107 int intensity = bd->props.brightness;
108
1a468ba1 109 if (debug)
23a9847f 110 printk(KERN_DEBUG DRIVER "setting brightness to %d\n",
1a468ba1
MS
111 intensity);
112
23a9847f 113 nvidia_chipset_set_brightness(intensity);
c78a6288
MS
114 return 0;
115}
116
117static int nvidia_chipset_get_intensity(struct backlight_device *bd)
118{
1a468ba1
MS
119 int intensity;
120
c78a6288
MS
121 outb(0x03, 0x52f);
122 outb(0xbf, 0x52e);
1a468ba1
MS
123 intensity = inb(0x52f) >> 4;
124
125 if (debug)
23a9847f 126 printk(KERN_DEBUG DRIVER "read brightness of %d\n",
1a468ba1
MS
127 intensity);
128
129 return intensity;
c78a6288
MS
130}
131
23a9847f 132static const struct hw_data nvidia_chipset_data = {
c78a6288
MS
133 .iostart = 0x52e,
134 .iolen = 2,
135 .backlight_ops = {
136 .options = BL_CORE_SUSPENDRESUME,
137 .get_brightness = nvidia_chipset_get_intensity,
138 .update_status = nvidia_chipset_send_intensity
23a9847f
MG
139 },
140 .set_brightness = nvidia_chipset_set_brightness,
c78a6288
MS
141};
142
39b3dee7 143static int __devinit apple_bl_add(struct acpi_device *dev)
c78a6288 144{
23a9847f
MG
145 struct backlight_properties props;
146 struct pci_dev *host;
99fd28e1 147 int intensity;
c78a6288 148
23a9847f 149 host = pci_get_bus_and_slot(0, 0);
c78a6288 150
23a9847f
MG
151 if (!host) {
152 printk(KERN_ERR DRIVER "unable to find PCI host\n");
153 return -ENODEV;
154 }
7be35c72 155
23a9847f
MG
156 if (host->vendor == PCI_VENDOR_ID_INTEL)
157 hw_data = &intel_chipset_data;
158 else if (host->vendor == PCI_VENDOR_ID_NVIDIA)
159 hw_data = &nvidia_chipset_data;
160
161 pci_dev_put(host);
162
163 if (!hw_data) {
164 printk(KERN_ERR DRIVER "unknown hardware\n");
7be35c72 165 return -ENODEV;
23a9847f 166 }
7be35c72 167
99fd28e1
MG
168 /* Check that the hardware responds - this may not work under EFI */
169
170 intensity = hw_data->backlight_ops.get_brightness(NULL);
171
172 if (!intensity) {
173 hw_data->set_brightness(1);
174 if (!hw_data->backlight_ops.get_brightness(NULL))
175 return -ENODEV;
176
177 hw_data->set_brightness(0);
178 }
179
23a9847f 180 if (!request_region(hw_data->iostart, hw_data->iolen,
39b3dee7 181 "Apple backlight"))
7be35c72
MG
182 return -ENXIO;
183
a19a6ee6 184 memset(&props, 0, sizeof(struct backlight_properties));
bb7ca747 185 props.type = BACKLIGHT_PLATFORM;
a19a6ee6 186 props.max_brightness = 15;
39b3dee7
MG
187 apple_backlight_device = backlight_device_register("apple_backlight",
188 NULL, NULL, &hw_data->backlight_ops, &props);
23a9847f 189
39b3dee7 190 if (IS_ERR(apple_backlight_device)) {
23a9847f 191 release_region(hw_data->iostart, hw_data->iolen);
39b3dee7 192 return PTR_ERR(apple_backlight_device);
7be35c72
MG
193 }
194
39b3dee7
MG
195 apple_backlight_device->props.brightness =
196 hw_data->backlight_ops.get_brightness(apple_backlight_device);
197 backlight_update_status(apple_backlight_device);
7be35c72
MG
198
199 return 0;
200}
201
39b3dee7 202static int __devexit apple_bl_remove(struct acpi_device *dev, int type)
7be35c72 203{
39b3dee7 204 backlight_device_unregister(apple_backlight_device);
7be35c72 205
23a9847f
MG
206 release_region(hw_data->iostart, hw_data->iolen);
207 hw_data = NULL;
208 return 0;
209}
210
39b3dee7 211static const struct acpi_device_id apple_bl_ids[] = {
23a9847f
MG
212 {"APP0002", 0},
213 {"", 0},
214};
215
39b3dee7
MG
216static struct acpi_driver apple_bl_driver = {
217 .name = "Apple backlight",
218 .ids = apple_bl_ids,
23a9847f 219 .ops = {
39b3dee7
MG
220 .add = apple_bl_add,
221 .remove = apple_bl_remove,
23a9847f
MG
222 },
223};
224
83e72dd9
SF
225static atomic_t apple_bl_registered = ATOMIC_INIT(0);
226
227int apple_bl_register(void)
228{
229 if (atomic_xchg(&apple_bl_registered, 1) == 0)
230 return acpi_bus_register_driver(&apple_bl_driver);
231
232 return 0;
233}
234EXPORT_SYMBOL_GPL(apple_bl_register);
235
236void apple_bl_unregister(void)
237{
238 if (atomic_xchg(&apple_bl_registered, 0) == 1)
239 acpi_bus_unregister_driver(&apple_bl_driver);
240}
241EXPORT_SYMBOL_GPL(apple_bl_unregister);
242
39b3dee7 243static int __init apple_bl_init(void)
23a9847f 244{
83e72dd9 245 return apple_bl_register();
23a9847f
MG
246}
247
39b3dee7 248static void __exit apple_bl_exit(void)
23a9847f 249{
83e72dd9 250 apple_bl_unregister();
7be35c72
MG
251}
252
39b3dee7
MG
253module_init(apple_bl_init);
254module_exit(apple_bl_exit);
7be35c72
MG
255
256MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
39b3dee7 257MODULE_DESCRIPTION("Apple Backlight Driver");
7be35c72 258MODULE_LICENSE("GPL");
39b3dee7
MG
259MODULE_DEVICE_TABLE(acpi, apple_bl_ids);
260MODULE_ALIAS("mbp_nvidia_bl");
This page took 0.300629 seconds and 5 git commands to generate.