Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
max8925_bl.c
Go to the documentation of this file.
1 /*
2  * Backlight driver for Maxim MAX8925
3  *
4  * Copyright (C) 2009 Marvell International Ltd.
5  * Haojian Zhuang <[email protected]>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 
12 #include <linux/init.h>
13 #include <linux/kernel.h>
14 #include <linux/platform_device.h>
15 #include <linux/fb.h>
16 #include <linux/i2c.h>
17 #include <linux/backlight.h>
18 #include <linux/mfd/max8925.h>
19 #include <linux/slab.h>
20 #include <linux/module.h>
21 
22 #define MAX_BRIGHTNESS (0xff)
23 #define MIN_BRIGHTNESS (0)
24 
25 #define LWX_FREQ(x) (((x - 601) / 100) & 0x7)
26 
28  struct max8925_chip *chip;
29 
32  int reg_cntl;
33 };
34 
35 static int max8925_backlight_set(struct backlight_device *bl, int brightness)
36 {
37  struct max8925_backlight_data *data = bl_get_data(bl);
38  struct max8925_chip *chip = data->chip;
39  unsigned char value;
40  int ret;
41 
42  if (brightness > MAX_BRIGHTNESS)
43  value = MAX_BRIGHTNESS;
44  else
45  value = brightness;
46 
47  ret = max8925_reg_write(chip->i2c, data->reg_cntl, value);
48  if (ret < 0)
49  goto out;
50 
51  if (!data->current_brightness && brightness)
52  /* enable WLED output */
53  ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 1, 1);
54  else if (!brightness)
55  /* disable WLED output */
56  ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 1, 0);
57  if (ret < 0)
58  goto out;
59  dev_dbg(chip->dev, "set brightness %d\n", value);
60  data->current_brightness = value;
61  return 0;
62 out:
63  dev_dbg(chip->dev, "set brightness %d failure with return value:%d\n",
64  value, ret);
65  return ret;
66 }
67 
68 static int max8925_backlight_update_status(struct backlight_device *bl)
69 {
70  int brightness = bl->props.brightness;
71 
72  if (bl->props.power != FB_BLANK_UNBLANK)
73  brightness = 0;
74 
75  if (bl->props.fb_blank != FB_BLANK_UNBLANK)
76  brightness = 0;
77 
78  if (bl->props.state & BL_CORE_SUSPENDED)
79  brightness = 0;
80 
81  return max8925_backlight_set(bl, brightness);
82 }
83 
84 static int max8925_backlight_get_brightness(struct backlight_device *bl)
85 {
86  struct max8925_backlight_data *data = bl_get_data(bl);
87  struct max8925_chip *chip = data->chip;
88  int ret;
89 
90  ret = max8925_reg_read(chip->i2c, data->reg_cntl);
91  if (ret < 0)
92  return -EINVAL;
93  data->current_brightness = ret;
94  dev_dbg(chip->dev, "get brightness %d\n", data->current_brightness);
95  return ret;
96 }
97 
98 static const struct backlight_ops max8925_backlight_ops = {
99  .options = BL_CORE_SUSPENDRESUME,
100  .update_status = max8925_backlight_update_status,
101  .get_brightness = max8925_backlight_get_brightness,
102 };
103 
104 static int __devinit max8925_backlight_probe(struct platform_device *pdev)
105 {
106  struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
107  struct max8925_backlight_pdata *pdata = pdev->dev.platform_data;
109  struct backlight_device *bl;
110  struct backlight_properties props;
111  struct resource *res;
112  unsigned char value;
113  int ret = 0;
114 
115  data = devm_kzalloc(&pdev->dev, sizeof(struct max8925_backlight_data),
116  GFP_KERNEL);
117  if (data == NULL)
118  return -ENOMEM;
119 
120  res = platform_get_resource(pdev, IORESOURCE_REG, 0);
121  if (!res) {
122  dev_err(&pdev->dev, "No REG resource for mode control!\n");
123  ret = -ENXIO;
124  goto out;
125  }
126  data->reg_mode_cntl = res->start;
127  res = platform_get_resource(pdev, IORESOURCE_REG, 1);
128  if (!res) {
129  dev_err(&pdev->dev, "No REG resource for control!\n");
130  ret = -ENXIO;
131  goto out;
132  }
133  data->reg_cntl = res->start;
134 
135  data->chip = chip;
136  data->current_brightness = 0;
137 
138  memset(&props, 0, sizeof(struct backlight_properties));
139  props.type = BACKLIGHT_RAW;
140  props.max_brightness = MAX_BRIGHTNESS;
141  bl = backlight_device_register("max8925-backlight", &pdev->dev, data,
142  &max8925_backlight_ops, &props);
143  if (IS_ERR(bl)) {
144  dev_err(&pdev->dev, "failed to register backlight\n");
145  ret = PTR_ERR(bl);
146  goto out;
147  }
148  bl->props.brightness = MAX_BRIGHTNESS;
149 
150  platform_set_drvdata(pdev, bl);
151 
152  value = 0;
153  if (pdata) {
154  if (pdata->lxw_scl)
155  value |= (1 << 7);
156  if (pdata->lxw_freq)
157  value |= (LWX_FREQ(pdata->lxw_freq) << 4);
158  if (pdata->dual_string)
159  value |= (1 << 1);
160  }
161  ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 0xfe, value);
162  if (ret < 0)
163  goto out_brt;
164 
165  backlight_update_status(bl);
166  return 0;
167 out_brt:
169 out:
170  devm_kfree(&pdev->dev, data);
171  return ret;
172 }
173 
174 static int __devexit max8925_backlight_remove(struct platform_device *pdev)
175 {
176  struct backlight_device *bl = platform_get_drvdata(pdev);
177 
179  return 0;
180 }
181 
182 static struct platform_driver max8925_backlight_driver = {
183  .driver = {
184  .name = "max8925-backlight",
185  .owner = THIS_MODULE,
186  },
187  .probe = max8925_backlight_probe,
188  .remove = __devexit_p(max8925_backlight_remove),
189 };
190 
191 module_platform_driver(max8925_backlight_driver);
192 
193 MODULE_DESCRIPTION("Backlight Driver for Maxim MAX8925");
194 MODULE_AUTHOR("Haojian Zhuang <[email protected]>");
195 MODULE_LICENSE("GPL");
196 MODULE_ALIAS("platform:max8925-backlight");