~ubuntu-branches/ubuntu/trusty/linux-linaro-omap/trusty

« back to all changes in this revision

Viewing changes to drivers/video/backlight/adp8870_bl.c

  • Committer: Package Import Robot
  • Author(s): John Rigby, John Rigby
  • Date: 2011-09-26 10:44:23 UTC
  • Revision ID: package-import@ubuntu.com-20110926104423-57i0gl3v99b3lkfg
Tags: 3.0.0-1007.9
[ John Rigby ]

Enable crypto modules and remove crypto-modules from
exclude-module files
LP: #826021

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Backlight driver for Analog Devices ADP8870 Backlight Devices
 
3
 *
 
4
 * Copyright 2009-2011 Analog Devices Inc.
 
5
 *
 
6
 * Licensed under the GPL-2 or later.
 
7
 */
 
8
 
 
9
#include <linux/module.h>
 
10
#include <linux/version.h>
 
11
#include <linux/init.h>
 
12
#include <linux/errno.h>
 
13
#include <linux/pm.h>
 
14
#include <linux/platform_device.h>
 
15
#include <linux/i2c.h>
 
16
#include <linux/fb.h>
 
17
#include <linux/backlight.h>
 
18
#include <linux/leds.h>
 
19
#include <linux/workqueue.h>
 
20
#include <linux/slab.h>
 
21
 
 
22
#include <linux/i2c/adp8870.h>
 
23
#define ADP8870_EXT_FEATURES
 
24
#define ADP8870_USE_LEDS
 
25
 
 
26
 
 
27
#define ADP8870_MFDVID  0x00  /* Manufacturer and device ID */
 
28
#define ADP8870_MDCR    0x01  /* Device mode and status */
 
29
#define ADP8870_INT_STAT 0x02  /* Interrupts status */
 
30
#define ADP8870_INT_EN  0x03  /* Interrupts enable */
 
31
#define ADP8870_CFGR    0x04  /* Configuration register */
 
32
#define ADP8870_BLSEL   0x05  /* Sink enable backlight or independent */
 
33
#define ADP8870_PWMLED  0x06  /* PWM Enable Selection Register */
 
34
#define ADP8870_BLOFF   0x07  /* Backlight off timeout */
 
35
#define ADP8870_BLDIM   0x08  /* Backlight dim timeout */
 
36
#define ADP8870_BLFR    0x09  /* Backlight fade in and out rates */
 
37
#define ADP8870_BLMX1   0x0A  /* Backlight (Brightness Level 1-daylight) maximum current */
 
38
#define ADP8870_BLDM1   0x0B  /* Backlight (Brightness Level 1-daylight) dim current */
 
39
#define ADP8870_BLMX2   0x0C  /* Backlight (Brightness Level 2-bright) maximum current */
 
40
#define ADP8870_BLDM2   0x0D  /* Backlight (Brightness Level 2-bright) dim current */
 
41
#define ADP8870_BLMX3   0x0E  /* Backlight (Brightness Level 3-office) maximum current */
 
42
#define ADP8870_BLDM3   0x0F  /* Backlight (Brightness Level 3-office) dim current */
 
43
#define ADP8870_BLMX4   0x10  /* Backlight (Brightness Level 4-indoor) maximum current */
 
44
#define ADP8870_BLDM4   0x11  /* Backlight (Brightness Level 4-indoor) dim current */
 
45
#define ADP8870_BLMX5   0x12  /* Backlight (Brightness Level 5-dark) maximum current */
 
46
#define ADP8870_BLDM5   0x13  /* Backlight (Brightness Level 5-dark) dim current */
 
47
#define ADP8870_ISCLAW  0x1A  /* Independent sink current fade law register */
 
48
#define ADP8870_ISCC    0x1B  /* Independent sink current control register */
 
49
#define ADP8870_ISCT1   0x1C  /* Independent Sink Current Timer Register LED[7:5] */
 
50
#define ADP8870_ISCT2   0x1D  /* Independent Sink Current Timer Register LED[4:1] */
 
51
#define ADP8870_ISCF    0x1E  /* Independent sink current fade register */
 
52
#define ADP8870_ISC1    0x1F  /* Independent Sink Current LED1 */
 
53
#define ADP8870_ISC2    0x20  /* Independent Sink Current LED2 */
 
54
#define ADP8870_ISC3    0x21  /* Independent Sink Current LED3 */
 
55
#define ADP8870_ISC4    0x22  /* Independent Sink Current LED4 */
 
56
#define ADP8870_ISC5    0x23  /* Independent Sink Current LED5 */
 
57
#define ADP8870_ISC6    0x24  /* Independent Sink Current LED6 */
 
58
#define ADP8870_ISC7    0x25  /* Independent Sink Current LED7 (Brightness Level 1-daylight) */
 
59
#define ADP8870_ISC7_L2 0x26  /* Independent Sink Current LED7 (Brightness Level 2-bright) */
 
60
#define ADP8870_ISC7_L3 0x27  /* Independent Sink Current LED7 (Brightness Level 3-office) */
 
61
#define ADP8870_ISC7_L4 0x28  /* Independent Sink Current LED7 (Brightness Level 4-indoor) */
 
62
#define ADP8870_ISC7_L5 0x29  /* Independent Sink Current LED7 (Brightness Level 5-dark) */
 
63
#define ADP8870_CMP_CTL 0x2D  /* ALS Comparator Control Register */
 
64
#define ADP8870_ALS1_EN 0x2E  /* Main ALS comparator level enable */
 
65
#define ADP8870_ALS2_EN 0x2F  /* Second ALS comparator level enable */
 
66
#define ADP8870_ALS1_STAT 0x30  /* Main ALS Comparator Status Register */
 
67
#define ADP8870_ALS2_STAT 0x31  /* Second ALS Comparator Status Register */
 
68
#define ADP8870_L2TRP   0x32  /* L2 comparator reference */
 
69
#define ADP8870_L2HYS   0x33  /* L2 hysteresis */
 
70
#define ADP8870_L3TRP   0x34  /* L3 comparator reference */
 
71
#define ADP8870_L3HYS   0x35  /* L3 hysteresis */
 
72
#define ADP8870_L4TRP   0x36  /* L4 comparator reference */
 
73
#define ADP8870_L4HYS   0x37  /* L4 hysteresis */
 
74
#define ADP8870_L5TRP   0x38  /* L5 comparator reference */
 
75
#define ADP8870_L5HYS   0x39  /* L5 hysteresis */
 
76
#define ADP8870_PH1LEVL 0x40  /* First phototransistor ambient light level-low byte register */
 
77
#define ADP8870_PH1LEVH 0x41  /* First phototransistor ambient light level-high byte register */
 
78
#define ADP8870_PH2LEVL 0x42  /* Second phototransistor ambient light level-low byte register */
 
79
#define ADP8870_PH2LEVH 0x43  /* Second phototransistor ambient light level-high byte register */
 
80
 
 
81
#define ADP8870_MANUFID         0x3  /* Analog Devices AD8870 Manufacturer and device ID */
 
82
#define ADP8870_DEVID(x)        ((x) & 0xF)
 
83
#define ADP8870_MANID(x)        ((x) >> 4)
 
84
 
 
85
/* MDCR Device mode and status */
 
86
#define D7ALSEN                 (1 << 7)
 
87
#define INT_CFG                 (1 << 6)
 
88
#define NSTBY                   (1 << 5)
 
89
#define DIM_EN                  (1 << 4)
 
90
#define GDWN_DIS                (1 << 3)
 
91
#define SIS_EN                  (1 << 2)
 
92
#define CMP_AUTOEN              (1 << 1)
 
93
#define BLEN                    (1 << 0)
 
94
 
 
95
/* ADP8870_ALS1_EN Main ALS comparator level enable */
 
96
#define L5_EN                   (1 << 3)
 
97
#define L4_EN                   (1 << 2)
 
98
#define L3_EN                   (1 << 1)
 
99
#define L2_EN                   (1 << 0)
 
100
 
 
101
#define CFGR_BLV_SHIFT          3
 
102
#define CFGR_BLV_MASK           0x7
 
103
#define ADP8870_FLAG_LED_MASK   0xFF
 
104
 
 
105
#define FADE_VAL(in, out)       ((0xF & (in)) | ((0xF & (out)) << 4))
 
106
#define BL_CFGR_VAL(law, blv)   ((((blv) & CFGR_BLV_MASK) << CFGR_BLV_SHIFT) | ((0x3 & (law)) << 1))
 
107
#define ALS_CMPR_CFG_VAL(filt)  ((0x7 & (filt)) << 1)
 
108
 
 
109
struct adp8870_bl {
 
110
        struct i2c_client *client;
 
111
        struct backlight_device *bl;
 
112
        struct adp8870_led *led;
 
113
        struct adp8870_backlight_platform_data *pdata;
 
114
        struct mutex lock;
 
115
        unsigned long cached_daylight_max;
 
116
        int id;
 
117
        int revid;
 
118
        int current_brightness;
 
119
};
 
120
 
 
121
struct adp8870_led {
 
122
        struct led_classdev     cdev;
 
123
        struct work_struct      work;
 
124
        struct i2c_client       *client;
 
125
        enum led_brightness     new_brightness;
 
126
        int                     id;
 
127
        int                     flags;
 
128
};
 
129
 
 
130
static int adp8870_read(struct i2c_client *client, int reg, uint8_t *val)
 
131
{
 
132
        int ret;
 
133
 
 
134
        ret = i2c_smbus_read_byte_data(client, reg);
 
135
        if (ret < 0) {
 
136
                dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
 
137
                return ret;
 
138
        }
 
139
 
 
140
        *val = ret;
 
141
        return 0;
 
142
}
 
143
 
 
144
 
 
145
static int adp8870_write(struct i2c_client *client, u8 reg, u8 val)
 
146
{
 
147
        int ret = i2c_smbus_write_byte_data(client, reg, val);
 
148
        if (ret)
 
149
                dev_err(&client->dev, "failed to write\n");
 
150
 
 
151
        return ret;
 
152
}
 
153
 
 
154
static int adp8870_set_bits(struct i2c_client *client, int reg, uint8_t bit_mask)
 
155
{
 
156
        struct adp8870_bl *data = i2c_get_clientdata(client);
 
157
        uint8_t reg_val;
 
158
        int ret;
 
159
 
 
160
        mutex_lock(&data->lock);
 
161
 
 
162
        ret = adp8870_read(client, reg, &reg_val);
 
163
 
 
164
        if (!ret && ((reg_val & bit_mask) == 0)) {
 
165
                reg_val |= bit_mask;
 
166
                ret = adp8870_write(client, reg, reg_val);
 
167
        }
 
168
 
 
169
        mutex_unlock(&data->lock);
 
170
        return ret;
 
171
}
 
172
 
 
173
static int adp8870_clr_bits(struct i2c_client *client, int reg, uint8_t bit_mask)
 
174
{
 
175
        struct adp8870_bl *data = i2c_get_clientdata(client);
 
176
        uint8_t reg_val;
 
177
        int ret;
 
178
 
 
179
        mutex_lock(&data->lock);
 
180
 
 
181
        ret = adp8870_read(client, reg, &reg_val);
 
182
 
 
183
        if (!ret && (reg_val & bit_mask)) {
 
184
                reg_val &= ~bit_mask;
 
185
                ret = adp8870_write(client, reg, reg_val);
 
186
        }
 
187
 
 
188
        mutex_unlock(&data->lock);
 
189
        return ret;
 
190
}
 
191
 
 
192
/*
 
193
 * Independent sink / LED
 
194
 */
 
195
#if defined(ADP8870_USE_LEDS)
 
196
static void adp8870_led_work(struct work_struct *work)
 
197
{
 
198
        struct adp8870_led *led = container_of(work, struct adp8870_led, work);
 
199
        adp8870_write(led->client, ADP8870_ISC1 + led->id - 1,
 
200
                         led->new_brightness >> 1);
 
201
}
 
202
 
 
203
static void adp8870_led_set(struct led_classdev *led_cdev,
 
204
                           enum led_brightness value)
 
205
{
 
206
        struct adp8870_led *led;
 
207
 
 
208
        led = container_of(led_cdev, struct adp8870_led, cdev);
 
209
        led->new_brightness = value;
 
210
        /*
 
211
         * Use workqueue for IO since I2C operations can sleep.
 
212
         */
 
213
        schedule_work(&led->work);
 
214
}
 
215
 
 
216
static int adp8870_led_setup(struct adp8870_led *led)
 
217
{
 
218
        struct i2c_client *client = led->client;
 
219
        int ret = 0;
 
220
 
 
221
        ret = adp8870_write(client, ADP8870_ISC1 + led->id - 1, 0);
 
222
        if (ret)
 
223
                return ret;
 
224
 
 
225
        ret = adp8870_set_bits(client, ADP8870_ISCC, 1 << (led->id - 1));
 
226
        if (ret)
 
227
                return ret;
 
228
 
 
229
        if (led->id > 4)
 
230
                ret = adp8870_set_bits(client, ADP8870_ISCT1,
 
231
                                (led->flags & 0x3) << ((led->id - 5) * 2));
 
232
        else
 
233
                ret = adp8870_set_bits(client, ADP8870_ISCT2,
 
234
                                (led->flags & 0x3) << ((led->id - 1) * 2));
 
235
 
 
236
        return ret;
 
237
}
 
238
 
 
239
static int __devinit adp8870_led_probe(struct i2c_client *client)
 
240
{
 
241
        struct adp8870_backlight_platform_data *pdata =
 
242
                client->dev.platform_data;
 
243
        struct adp8870_bl *data = i2c_get_clientdata(client);
 
244
        struct adp8870_led *led, *led_dat;
 
245
        struct led_info *cur_led;
 
246
        int ret, i;
 
247
 
 
248
 
 
249
        led = kcalloc(pdata->num_leds, sizeof(*led), GFP_KERNEL);
 
250
        if (led == NULL) {
 
251
                dev_err(&client->dev, "failed to alloc memory\n");
 
252
                return -ENOMEM;
 
253
        }
 
254
 
 
255
        ret = adp8870_write(client, ADP8870_ISCLAW, pdata->led_fade_law);
 
256
        if (ret)
 
257
                goto err_free;
 
258
 
 
259
        ret = adp8870_write(client, ADP8870_ISCT1,
 
260
                        (pdata->led_on_time & 0x3) << 6);
 
261
        if (ret)
 
262
                goto err_free;
 
263
 
 
264
        ret = adp8870_write(client, ADP8870_ISCF,
 
265
                        FADE_VAL(pdata->led_fade_in, pdata->led_fade_out));
 
266
        if (ret)
 
267
                goto err_free;
 
268
 
 
269
        for (i = 0; i < pdata->num_leds; ++i) {
 
270
                cur_led = &pdata->leds[i];
 
271
                led_dat = &led[i];
 
272
 
 
273
                led_dat->id = cur_led->flags & ADP8870_FLAG_LED_MASK;
 
274
 
 
275
                if (led_dat->id > 7 || led_dat->id < 1) {
 
276
                        dev_err(&client->dev, "Invalid LED ID %d\n",
 
277
                                led_dat->id);
 
278
                        goto err;
 
279
                }
 
280
 
 
281
                if (pdata->bl_led_assign & (1 << (led_dat->id - 1))) {
 
282
                        dev_err(&client->dev, "LED %d used by Backlight\n",
 
283
                                led_dat->id);
 
284
                        goto err;
 
285
                }
 
286
 
 
287
                led_dat->cdev.name = cur_led->name;
 
288
                led_dat->cdev.default_trigger = cur_led->default_trigger;
 
289
                led_dat->cdev.brightness_set = adp8870_led_set;
 
290
                led_dat->cdev.brightness = LED_OFF;
 
291
                led_dat->flags = cur_led->flags >> FLAG_OFFT_SHIFT;
 
292
                led_dat->client = client;
 
293
                led_dat->new_brightness = LED_OFF;
 
294
                INIT_WORK(&led_dat->work, adp8870_led_work);
 
295
 
 
296
                ret = led_classdev_register(&client->dev, &led_dat->cdev);
 
297
                if (ret) {
 
298
                        dev_err(&client->dev, "failed to register LED %d\n",
 
299
                                led_dat->id);
 
300
                        goto err;
 
301
                }
 
302
 
 
303
                ret = adp8870_led_setup(led_dat);
 
304
                if (ret) {
 
305
                        dev_err(&client->dev, "failed to write\n");
 
306
                        i++;
 
307
                        goto err;
 
308
                }
 
309
        }
 
310
 
 
311
        data->led = led;
 
312
 
 
313
        return 0;
 
314
 
 
315
 err:
 
316
        for (i = i - 1; i >= 0; --i) {
 
317
                led_classdev_unregister(&led[i].cdev);
 
318
                cancel_work_sync(&led[i].work);
 
319
        }
 
320
 
 
321
 err_free:
 
322
        kfree(led);
 
323
 
 
324
        return ret;
 
325
}
 
326
 
 
327
static int __devexit adp8870_led_remove(struct i2c_client *client)
 
328
{
 
329
        struct adp8870_backlight_platform_data *pdata =
 
330
                client->dev.platform_data;
 
331
        struct adp8870_bl *data = i2c_get_clientdata(client);
 
332
        int i;
 
333
 
 
334
        for (i = 0; i < pdata->num_leds; i++) {
 
335
                led_classdev_unregister(&data->led[i].cdev);
 
336
                cancel_work_sync(&data->led[i].work);
 
337
        }
 
338
 
 
339
        kfree(data->led);
 
340
        return 0;
 
341
}
 
342
#else
 
343
static int __devinit adp8870_led_probe(struct i2c_client *client)
 
344
{
 
345
        return 0;
 
346
}
 
347
 
 
348
static int __devexit adp8870_led_remove(struct i2c_client *client)
 
349
{
 
350
        return 0;
 
351
}
 
352
#endif
 
353
 
 
354
static int adp8870_bl_set(struct backlight_device *bl, int brightness)
 
355
{
 
356
        struct adp8870_bl *data = bl_get_data(bl);
 
357
        struct i2c_client *client = data->client;
 
358
        int ret = 0;
 
359
 
 
360
        if (data->pdata->en_ambl_sens) {
 
361
                if ((brightness > 0) && (brightness < ADP8870_MAX_BRIGHTNESS)) {
 
362
                        /* Disable Ambient Light auto adjust */
 
363
                        ret = adp8870_clr_bits(client, ADP8870_MDCR,
 
364
                                        CMP_AUTOEN);
 
365
                        if (ret)
 
366
                                return ret;
 
367
                        ret = adp8870_write(client, ADP8870_BLMX1, brightness);
 
368
                        if (ret)
 
369
                                return ret;
 
370
                } else {
 
371
                        /*
 
372
                         * MAX_BRIGHTNESS -> Enable Ambient Light auto adjust
 
373
                         * restore daylight l1 sysfs brightness
 
374
                         */
 
375
                        ret = adp8870_write(client, ADP8870_BLMX1,
 
376
                                         data->cached_daylight_max);
 
377
                        if (ret)
 
378
                                return ret;
 
379
 
 
380
                        ret = adp8870_set_bits(client, ADP8870_MDCR,
 
381
                                         CMP_AUTOEN);
 
382
                        if (ret)
 
383
                                return ret;
 
384
                }
 
385
        } else {
 
386
                ret = adp8870_write(client, ADP8870_BLMX1, brightness);
 
387
                if (ret)
 
388
                        return ret;
 
389
        }
 
390
 
 
391
        if (data->current_brightness && brightness == 0)
 
392
                ret = adp8870_set_bits(client,
 
393
                                ADP8870_MDCR, DIM_EN);
 
394
        else if (data->current_brightness == 0 && brightness)
 
395
                ret = adp8870_clr_bits(client,
 
396
                                ADP8870_MDCR, DIM_EN);
 
397
 
 
398
        if (!ret)
 
399
                data->current_brightness = brightness;
 
400
 
 
401
        return ret;
 
402
}
 
403
 
 
404
static int adp8870_bl_update_status(struct backlight_device *bl)
 
405
{
 
406
        int brightness = bl->props.brightness;
 
407
        if (bl->props.power != FB_BLANK_UNBLANK)
 
408
                brightness = 0;
 
409
 
 
410
        if (bl->props.fb_blank != FB_BLANK_UNBLANK)
 
411
                brightness = 0;
 
412
 
 
413
        return adp8870_bl_set(bl, brightness);
 
414
}
 
415
 
 
416
static int adp8870_bl_get_brightness(struct backlight_device *bl)
 
417
{
 
418
        struct adp8870_bl *data = bl_get_data(bl);
 
419
 
 
420
        return data->current_brightness;
 
421
}
 
422
 
 
423
static const struct backlight_ops adp8870_bl_ops = {
 
424
        .update_status  = adp8870_bl_update_status,
 
425
        .get_brightness = adp8870_bl_get_brightness,
 
426
};
 
427
 
 
428
static int adp8870_bl_setup(struct backlight_device *bl)
 
429
{
 
430
        struct adp8870_bl *data = bl_get_data(bl);
 
431
        struct i2c_client *client = data->client;
 
432
        struct adp8870_backlight_platform_data *pdata = data->pdata;
 
433
        int ret = 0;
 
434
 
 
435
        ret = adp8870_write(client, ADP8870_BLSEL, ~pdata->bl_led_assign);
 
436
        if (ret)
 
437
                return ret;
 
438
 
 
439
        ret = adp8870_write(client, ADP8870_PWMLED, pdata->pwm_assign);
 
440
        if (ret)
 
441
                return ret;
 
442
 
 
443
        ret = adp8870_write(client, ADP8870_BLMX1, pdata->l1_daylight_max);
 
444
        if (ret)
 
445
                return ret;
 
446
 
 
447
        ret = adp8870_write(client, ADP8870_BLDM1, pdata->l1_daylight_dim);
 
448
        if (ret)
 
449
                return ret;
 
450
 
 
451
        if (pdata->en_ambl_sens) {
 
452
                data->cached_daylight_max = pdata->l1_daylight_max;
 
453
                ret = adp8870_write(client, ADP8870_BLMX2,
 
454
                                                pdata->l2_bright_max);
 
455
                if (ret)
 
456
                        return ret;
 
457
                ret = adp8870_write(client, ADP8870_BLDM2,
 
458
                                                pdata->l2_bright_dim);
 
459
                if (ret)
 
460
                        return ret;
 
461
 
 
462
                ret = adp8870_write(client, ADP8870_BLMX3,
 
463
                                                pdata->l3_office_max);
 
464
                if (ret)
 
465
                        return ret;
 
466
                ret = adp8870_write(client, ADP8870_BLDM3,
 
467
                                                pdata->l3_office_dim);
 
468
                if (ret)
 
469
                        return ret;
 
470
 
 
471
                ret = adp8870_write(client, ADP8870_BLMX4,
 
472
                                                pdata->l4_indoor_max);
 
473
                if (ret)
 
474
                        return ret;
 
475
 
 
476
                ret = adp8870_write(client, ADP8870_BLDM4,
 
477
                                                pdata->l4_indor_dim);
 
478
                if (ret)
 
479
                        return ret;
 
480
 
 
481
                ret = adp8870_write(client, ADP8870_BLMX5,
 
482
                                                pdata->l5_dark_max);
 
483
                if (ret)
 
484
                        return ret;
 
485
 
 
486
                ret = adp8870_write(client, ADP8870_BLDM5,
 
487
                                                pdata->l5_dark_dim);
 
488
                if (ret)
 
489
                        return ret;
 
490
 
 
491
                ret = adp8870_write(client, ADP8870_L2TRP, pdata->l2_trip);
 
492
                if (ret)
 
493
                        return ret;
 
494
 
 
495
                ret = adp8870_write(client, ADP8870_L2HYS, pdata->l2_hyst);
 
496
                if (ret)
 
497
                        return ret;
 
498
 
 
499
                ret = adp8870_write(client, ADP8870_L3TRP, pdata->l3_trip);
 
500
                if (ret)
 
501
                        return ret;
 
502
 
 
503
                ret = adp8870_write(client, ADP8870_L3HYS, pdata->l3_hyst);
 
504
                if (ret)
 
505
                        return ret;
 
506
 
 
507
                ret = adp8870_write(client, ADP8870_L4TRP, pdata->l4_trip);
 
508
                if (ret)
 
509
                        return ret;
 
510
 
 
511
                ret = adp8870_write(client, ADP8870_L4HYS, pdata->l4_hyst);
 
512
                if (ret)
 
513
                        return ret;
 
514
 
 
515
                ret = adp8870_write(client, ADP8870_L5TRP, pdata->l5_trip);
 
516
                if (ret)
 
517
                        return ret;
 
518
 
 
519
                ret = adp8870_write(client, ADP8870_L5HYS, pdata->l5_hyst);
 
520
                if (ret)
 
521
                        return ret;
 
522
 
 
523
                ret = adp8870_write(client, ADP8870_ALS1_EN, L5_EN | L4_EN |
 
524
                                                L3_EN | L2_EN);
 
525
                if (ret)
 
526
                        return ret;
 
527
 
 
528
                ret = adp8870_write(client, ADP8870_CMP_CTL,
 
529
                        ALS_CMPR_CFG_VAL(pdata->abml_filt));
 
530
                if (ret)
 
531
                        return ret;
 
532
        }
 
533
 
 
534
        ret = adp8870_write(client, ADP8870_CFGR,
 
535
                        BL_CFGR_VAL(pdata->bl_fade_law, 0));
 
536
        if (ret)
 
537
                return ret;
 
538
 
 
539
        ret = adp8870_write(client, ADP8870_BLFR, FADE_VAL(pdata->bl_fade_in,
 
540
                        pdata->bl_fade_out));
 
541
        if (ret)
 
542
                return ret;
 
543
        /*
 
544
         * ADP8870 Rev0 requires GDWN_DIS bit set
 
545
         */
 
546
 
 
547
        ret = adp8870_set_bits(client, ADP8870_MDCR, BLEN | DIM_EN | NSTBY |
 
548
                        (data->revid == 0 ? GDWN_DIS : 0));
 
549
 
 
550
        return ret;
 
551
}
 
552
 
 
553
static ssize_t adp8870_show(struct device *dev, char *buf, int reg)
 
554
{
 
555
        struct adp8870_bl *data = dev_get_drvdata(dev);
 
556
        int error;
 
557
        uint8_t reg_val;
 
558
 
 
559
        mutex_lock(&data->lock);
 
560
        error = adp8870_read(data->client, reg, &reg_val);
 
561
        mutex_unlock(&data->lock);
 
562
 
 
563
        if (error < 0)
 
564
                return error;
 
565
 
 
566
        return sprintf(buf, "%u\n", reg_val);
 
567
}
 
568
 
 
569
static ssize_t adp8870_store(struct device *dev, const char *buf,
 
570
                         size_t count, int reg)
 
571
{
 
572
        struct adp8870_bl *data = dev_get_drvdata(dev);
 
573
        unsigned long val;
 
574
        int ret;
 
575
 
 
576
        ret = strict_strtoul(buf, 10, &val);
 
577
        if (ret)
 
578
                return ret;
 
579
 
 
580
        mutex_lock(&data->lock);
 
581
        adp8870_write(data->client, reg, val);
 
582
        mutex_unlock(&data->lock);
 
583
 
 
584
        return count;
 
585
}
 
586
 
 
587
static ssize_t adp8870_bl_l5_dark_max_show(struct device *dev,
 
588
                struct device_attribute *attr, char *buf)
 
589
{
 
590
        return adp8870_show(dev, buf, ADP8870_BLMX5);
 
591
}
 
592
 
 
593
static ssize_t adp8870_bl_l5_dark_max_store(struct device *dev,
 
594
                struct device_attribute *attr, const char *buf, size_t count)
 
595
{
 
596
        return adp8870_store(dev, buf, count, ADP8870_BLMX5);
 
597
}
 
598
static DEVICE_ATTR(l5_dark_max, 0664, adp8870_bl_l5_dark_max_show,
 
599
                        adp8870_bl_l5_dark_max_store);
 
600
 
 
601
 
 
602
static ssize_t adp8870_bl_l4_indoor_max_show(struct device *dev,
 
603
                struct device_attribute *attr, char *buf)
 
604
{
 
605
        return adp8870_show(dev, buf, ADP8870_BLMX4);
 
606
}
 
607
 
 
608
static ssize_t adp8870_bl_l4_indoor_max_store(struct device *dev,
 
609
                struct device_attribute *attr, const char *buf, size_t count)
 
610
{
 
611
        return adp8870_store(dev, buf, count, ADP8870_BLMX4);
 
612
}
 
613
static DEVICE_ATTR(l4_indoor_max, 0664, adp8870_bl_l4_indoor_max_show,
 
614
                        adp8870_bl_l4_indoor_max_store);
 
615
 
 
616
 
 
617
static ssize_t adp8870_bl_l3_office_max_show(struct device *dev,
 
618
                                     struct device_attribute *attr, char *buf)
 
619
{
 
620
        return adp8870_show(dev, buf, ADP8870_BLMX3);
 
621
}
 
622
 
 
623
static ssize_t adp8870_bl_l3_office_max_store(struct device *dev,
 
624
                struct device_attribute *attr, const char *buf, size_t count)
 
625
{
 
626
        return adp8870_store(dev, buf, count, ADP8870_BLMX3);
 
627
}
 
628
 
 
629
static DEVICE_ATTR(l3_office_max, 0664, adp8870_bl_l3_office_max_show,
 
630
                        adp8870_bl_l3_office_max_store);
 
631
 
 
632
static ssize_t adp8870_bl_l2_bright_max_show(struct device *dev,
 
633
                struct device_attribute *attr, char *buf)
 
634
{
 
635
        return adp8870_show(dev, buf, ADP8870_BLMX2);
 
636
}
 
637
 
 
638
static ssize_t adp8870_bl_l2_bright_max_store(struct device *dev,
 
639
                struct device_attribute *attr, const char *buf, size_t count)
 
640
{
 
641
        return adp8870_store(dev, buf, count, ADP8870_BLMX2);
 
642
}
 
643
static DEVICE_ATTR(l2_bright_max, 0664, adp8870_bl_l2_bright_max_show,
 
644
                        adp8870_bl_l2_bright_max_store);
 
645
 
 
646
static ssize_t adp8870_bl_l1_daylight_max_show(struct device *dev,
 
647
                        struct device_attribute *attr, char *buf)
 
648
{
 
649
        return adp8870_show(dev, buf, ADP8870_BLMX1);
 
650
}
 
651
 
 
652
static ssize_t adp8870_bl_l1_daylight_max_store(struct device *dev,
 
653
                struct device_attribute *attr, const char *buf, size_t count)
 
654
{
 
655
        struct adp8870_bl *data = dev_get_drvdata(dev);
 
656
        int ret = strict_strtoul(buf, 10, &data->cached_daylight_max);
 
657
        if (ret)
 
658
                return ret;
 
659
 
 
660
        return adp8870_store(dev, buf, count, ADP8870_BLMX1);
 
661
}
 
662
static DEVICE_ATTR(l1_daylight_max, 0664, adp8870_bl_l1_daylight_max_show,
 
663
                        adp8870_bl_l1_daylight_max_store);
 
664
 
 
665
static ssize_t adp8870_bl_l5_dark_dim_show(struct device *dev,
 
666
                        struct device_attribute *attr, char *buf)
 
667
{
 
668
        return adp8870_show(dev, buf, ADP8870_BLDM5);
 
669
}
 
670
 
 
671
static ssize_t adp8870_bl_l5_dark_dim_store(struct device *dev,
 
672
                                     struct device_attribute *attr,
 
673
                                     const char *buf, size_t count)
 
674
{
 
675
        return adp8870_store(dev, buf, count, ADP8870_BLDM5);
 
676
}
 
677
static DEVICE_ATTR(l5_dark_dim, 0664, adp8870_bl_l5_dark_dim_show,
 
678
                        adp8870_bl_l5_dark_dim_store);
 
679
 
 
680
static ssize_t adp8870_bl_l4_indoor_dim_show(struct device *dev,
 
681
                        struct device_attribute *attr, char *buf)
 
682
{
 
683
        return adp8870_show(dev, buf, ADP8870_BLDM4);
 
684
}
 
685
 
 
686
static ssize_t adp8870_bl_l4_indoor_dim_store(struct device *dev,
 
687
                                     struct device_attribute *attr,
 
688
                                     const char *buf, size_t count)
 
689
{
 
690
        return adp8870_store(dev, buf, count, ADP8870_BLDM4);
 
691
}
 
692
static DEVICE_ATTR(l4_indoor_dim, 0664, adp8870_bl_l4_indoor_dim_show,
 
693
                        adp8870_bl_l4_indoor_dim_store);
 
694
 
 
695
 
 
696
static ssize_t adp8870_bl_l3_office_dim_show(struct device *dev,
 
697
                        struct device_attribute *attr, char *buf)
 
698
{
 
699
        return adp8870_show(dev, buf, ADP8870_BLDM3);
 
700
}
 
701
 
 
702
static ssize_t adp8870_bl_l3_office_dim_store(struct device *dev,
 
703
                                     struct device_attribute *attr,
 
704
                                     const char *buf, size_t count)
 
705
{
 
706
        return adp8870_store(dev, buf, count, ADP8870_BLDM3);
 
707
}
 
708
static DEVICE_ATTR(l3_office_dim, 0664, adp8870_bl_l3_office_dim_show,
 
709
                        adp8870_bl_l3_office_dim_store);
 
710
 
 
711
static ssize_t adp8870_bl_l2_bright_dim_show(struct device *dev,
 
712
                        struct device_attribute *attr, char *buf)
 
713
{
 
714
        return adp8870_show(dev, buf, ADP8870_BLDM2);
 
715
}
 
716
 
 
717
static ssize_t adp8870_bl_l2_bright_dim_store(struct device *dev,
 
718
                                     struct device_attribute *attr,
 
719
                                     const char *buf, size_t count)
 
720
{
 
721
        return adp8870_store(dev, buf, count, ADP8870_BLDM2);
 
722
}
 
723
static DEVICE_ATTR(l2_bright_dim, 0664, adp8870_bl_l2_bright_dim_show,
 
724
                        adp8870_bl_l2_bright_dim_store);
 
725
 
 
726
static ssize_t adp8870_bl_l1_daylight_dim_show(struct device *dev,
 
727
                                     struct device_attribute *attr, char *buf)
 
728
{
 
729
        return adp8870_show(dev, buf, ADP8870_BLDM1);
 
730
}
 
731
 
 
732
static ssize_t adp8870_bl_l1_daylight_dim_store(struct device *dev,
 
733
                                     struct device_attribute *attr,
 
734
                                     const char *buf, size_t count)
 
735
{
 
736
        return adp8870_store(dev, buf, count, ADP8870_BLDM1);
 
737
}
 
738
static DEVICE_ATTR(l1_daylight_dim, 0664, adp8870_bl_l1_daylight_dim_show,
 
739
                        adp8870_bl_l1_daylight_dim_store);
 
740
 
 
741
#ifdef ADP8870_EXT_FEATURES
 
742
static ssize_t adp8870_bl_ambient_light_level_show(struct device *dev,
 
743
                                     struct device_attribute *attr, char *buf)
 
744
{
 
745
        struct adp8870_bl *data = dev_get_drvdata(dev);
 
746
        int error;
 
747
        uint8_t reg_val;
 
748
        uint16_t ret_val;
 
749
 
 
750
        mutex_lock(&data->lock);
 
751
        error = adp8870_read(data->client, ADP8870_PH1LEVL, &reg_val);
 
752
        if (error < 0) {
 
753
                mutex_unlock(&data->lock);
 
754
                return error;
 
755
        }
 
756
        ret_val = reg_val;
 
757
        error = adp8870_read(data->client, ADP8870_PH1LEVH, &reg_val);
 
758
        mutex_unlock(&data->lock);
 
759
 
 
760
        if (error < 0)
 
761
                return error;
 
762
 
 
763
        /* Return 13-bit conversion value for the first light sensor */
 
764
        ret_val += (reg_val & 0x1F) << 8;
 
765
 
 
766
        return sprintf(buf, "%u\n", ret_val);
 
767
}
 
768
static DEVICE_ATTR(ambient_light_level, 0444,
 
769
                adp8870_bl_ambient_light_level_show, NULL);
 
770
 
 
771
static ssize_t adp8870_bl_ambient_light_zone_show(struct device *dev,
 
772
                                     struct device_attribute *attr, char *buf)
 
773
{
 
774
        struct adp8870_bl *data = dev_get_drvdata(dev);
 
775
        int error;
 
776
        uint8_t reg_val;
 
777
 
 
778
        mutex_lock(&data->lock);
 
779
        error = adp8870_read(data->client, ADP8870_CFGR, &reg_val);
 
780
        mutex_unlock(&data->lock);
 
781
 
 
782
        if (error < 0)
 
783
                return error;
 
784
 
 
785
        return sprintf(buf, "%u\n",
 
786
                ((reg_val >> CFGR_BLV_SHIFT) & CFGR_BLV_MASK) + 1);
 
787
}
 
788
 
 
789
static ssize_t adp8870_bl_ambient_light_zone_store(struct device *dev,
 
790
                                     struct device_attribute *attr,
 
791
                                     const char *buf, size_t count)
 
792
{
 
793
        struct adp8870_bl *data = dev_get_drvdata(dev);
 
794
        unsigned long val;
 
795
        uint8_t reg_val;
 
796
        int ret;
 
797
 
 
798
        ret = strict_strtoul(buf, 10, &val);
 
799
        if (ret)
 
800
                return ret;
 
801
 
 
802
        if (val == 0) {
 
803
                /* Enable automatic ambient light sensing */
 
804
                adp8870_set_bits(data->client, ADP8870_MDCR, CMP_AUTOEN);
 
805
        } else if ((val > 0) && (val < 6)) {
 
806
                /* Disable automatic ambient light sensing */
 
807
                adp8870_clr_bits(data->client, ADP8870_MDCR, CMP_AUTOEN);
 
808
 
 
809
                /* Set user supplied ambient light zone */
 
810
                mutex_lock(&data->lock);
 
811
                adp8870_read(data->client, ADP8870_CFGR, &reg_val);
 
812
                reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT);
 
813
                reg_val |= (val - 1) << CFGR_BLV_SHIFT;
 
814
                adp8870_write(data->client, ADP8870_CFGR, reg_val);
 
815
                mutex_unlock(&data->lock);
 
816
        }
 
817
 
 
818
        return count;
 
819
}
 
820
static DEVICE_ATTR(ambient_light_zone, 0664,
 
821
                adp8870_bl_ambient_light_zone_show,
 
822
                adp8870_bl_ambient_light_zone_store);
 
823
#endif
 
824
 
 
825
static struct attribute *adp8870_bl_attributes[] = {
 
826
        &dev_attr_l5_dark_max.attr,
 
827
        &dev_attr_l5_dark_dim.attr,
 
828
        &dev_attr_l4_indoor_max.attr,
 
829
        &dev_attr_l4_indoor_dim.attr,
 
830
        &dev_attr_l3_office_max.attr,
 
831
        &dev_attr_l3_office_dim.attr,
 
832
        &dev_attr_l2_bright_max.attr,
 
833
        &dev_attr_l2_bright_dim.attr,
 
834
        &dev_attr_l1_daylight_max.attr,
 
835
        &dev_attr_l1_daylight_dim.attr,
 
836
#ifdef ADP8870_EXT_FEATURES
 
837
        &dev_attr_ambient_light_level.attr,
 
838
        &dev_attr_ambient_light_zone.attr,
 
839
#endif
 
840
        NULL
 
841
};
 
842
 
 
843
static const struct attribute_group adp8870_bl_attr_group = {
 
844
        .attrs = adp8870_bl_attributes,
 
845
};
 
846
 
 
847
static int __devinit adp8870_probe(struct i2c_client *client,
 
848
                                        const struct i2c_device_id *id)
 
849
{
 
850
        struct backlight_properties props;
 
851
        struct backlight_device *bl;
 
852
        struct adp8870_bl *data;
 
853
        struct adp8870_backlight_platform_data *pdata =
 
854
                client->dev.platform_data;
 
855
        uint8_t reg_val;
 
856
        int ret;
 
857
 
 
858
        if (!i2c_check_functionality(client->adapter,
 
859
                                        I2C_FUNC_SMBUS_BYTE_DATA)) {
 
860
                dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
 
861
                return -EIO;
 
862
        }
 
863
 
 
864
        if (!pdata) {
 
865
                dev_err(&client->dev, "no platform data?\n");
 
866
                return -EINVAL;
 
867
        }
 
868
 
 
869
        ret = adp8870_read(client, ADP8870_MFDVID, &reg_val);
 
870
        if (ret < 0)
 
871
                return -EIO;
 
872
 
 
873
        if (ADP8870_MANID(reg_val) != ADP8870_MANUFID) {
 
874
                dev_err(&client->dev, "failed to probe\n");
 
875
                return -ENODEV;
 
876
        }
 
877
 
 
878
        data = kzalloc(sizeof(*data), GFP_KERNEL);
 
879
        if (data == NULL)
 
880
                return -ENOMEM;
 
881
 
 
882
        data->revid = ADP8870_DEVID(reg_val);
 
883
        data->client = client;
 
884
        data->pdata = pdata;
 
885
        data->id = id->driver_data;
 
886
        data->current_brightness = 0;
 
887
        i2c_set_clientdata(client, data);
 
888
 
 
889
        mutex_init(&data->lock);
 
890
 
 
891
        memset(&props, 0, sizeof(props));
 
892
        props.type = BACKLIGHT_RAW;
 
893
        props.max_brightness = props.brightness = ADP8870_MAX_BRIGHTNESS;
 
894
        bl = backlight_device_register(dev_driver_string(&client->dev),
 
895
                        &client->dev, data, &adp8870_bl_ops, &props);
 
896
        if (IS_ERR(bl)) {
 
897
                dev_err(&client->dev, "failed to register backlight\n");
 
898
                ret = PTR_ERR(bl);
 
899
                goto out2;
 
900
        }
 
901
 
 
902
        data->bl = bl;
 
903
 
 
904
        if (pdata->en_ambl_sens)
 
905
                ret = sysfs_create_group(&bl->dev.kobj,
 
906
                        &adp8870_bl_attr_group);
 
907
 
 
908
        if (ret) {
 
909
                dev_err(&client->dev, "failed to register sysfs\n");
 
910
                goto out1;
 
911
        }
 
912
 
 
913
        ret = adp8870_bl_setup(bl);
 
914
        if (ret) {
 
915
                ret = -EIO;
 
916
                goto out;
 
917
        }
 
918
 
 
919
        backlight_update_status(bl);
 
920
 
 
921
        dev_info(&client->dev, "Rev.%d Backlight\n", data->revid);
 
922
 
 
923
        if (pdata->num_leds)
 
924
                adp8870_led_probe(client);
 
925
 
 
926
        return 0;
 
927
 
 
928
out:
 
929
        if (data->pdata->en_ambl_sens)
 
930
                sysfs_remove_group(&data->bl->dev.kobj,
 
931
                        &adp8870_bl_attr_group);
 
932
out1:
 
933
        backlight_device_unregister(bl);
 
934
out2:
 
935
        i2c_set_clientdata(client, NULL);
 
936
        kfree(data);
 
937
 
 
938
        return ret;
 
939
}
 
940
 
 
941
static int __devexit adp8870_remove(struct i2c_client *client)
 
942
{
 
943
        struct adp8870_bl *data = i2c_get_clientdata(client);
 
944
 
 
945
        adp8870_clr_bits(client, ADP8870_MDCR, NSTBY);
 
946
 
 
947
        if (data->led)
 
948
                adp8870_led_remove(client);
 
949
 
 
950
        if (data->pdata->en_ambl_sens)
 
951
                sysfs_remove_group(&data->bl->dev.kobj,
 
952
                        &adp8870_bl_attr_group);
 
953
 
 
954
        backlight_device_unregister(data->bl);
 
955
        i2c_set_clientdata(client, NULL);
 
956
        kfree(data);
 
957
 
 
958
        return 0;
 
959
}
 
960
 
 
961
#ifdef CONFIG_PM
 
962
static int adp8870_i2c_suspend(struct i2c_client *client, pm_message_t message)
 
963
{
 
964
        adp8870_clr_bits(client, ADP8870_MDCR, NSTBY);
 
965
 
 
966
        return 0;
 
967
}
 
968
 
 
969
static int adp8870_i2c_resume(struct i2c_client *client)
 
970
{
 
971
        adp8870_set_bits(client, ADP8870_MDCR, NSTBY);
 
972
 
 
973
        return 0;
 
974
}
 
975
#else
 
976
#define adp8870_i2c_suspend NULL
 
977
#define adp8870_i2c_resume NULL
 
978
#endif
 
979
 
 
980
static const struct i2c_device_id adp8870_id[] = {
 
981
        { "adp8870", 0 },
 
982
        { }
 
983
};
 
984
MODULE_DEVICE_TABLE(i2c, adp8870_id);
 
985
 
 
986
static struct i2c_driver adp8870_driver = {
 
987
        .driver = {
 
988
                .name = KBUILD_MODNAME,
 
989
        },
 
990
        .probe    = adp8870_probe,
 
991
        .remove   = __devexit_p(adp8870_remove),
 
992
        .suspend = adp8870_i2c_suspend,
 
993
        .resume  = adp8870_i2c_resume,
 
994
        .id_table = adp8870_id,
 
995
};
 
996
 
 
997
static int __init adp8870_init(void)
 
998
{
 
999
        return i2c_add_driver(&adp8870_driver);
 
1000
}
 
1001
module_init(adp8870_init);
 
1002
 
 
1003
static void __exit adp8870_exit(void)
 
1004
{
 
1005
        i2c_del_driver(&adp8870_driver);
 
1006
}
 
1007
module_exit(adp8870_exit);
 
1008
 
 
1009
MODULE_LICENSE("GPL v2");
 
1010
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 
1011
MODULE_DESCRIPTION("ADP8870 Backlight driver");
 
1012
MODULE_ALIAS("platform:adp8870-backlight");