Commit 3154c344696e58b7e15317cd624816dbe3832ad1
Committed by
Samuel Ortiz
1 parent
adb70483f4
Exists in
master
and in
4 other branches
mfd: Adopt mfd_data in 88pm860x led
Copy 88pm860x platform data into different mfd_data structure for led driver. So move the identification of device node from led driver to mfd driver. Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Showing 3 changed files with 79 additions and 93 deletions Side-by-side Diff
drivers/leds/leds-88pm860x.c
... | ... | @@ -17,6 +17,7 @@ |
17 | 17 | #include <linux/leds.h> |
18 | 18 | #include <linux/slab.h> |
19 | 19 | #include <linux/workqueue.h> |
20 | +#include <linux/mfd/core.h> | |
20 | 21 | #include <linux/mfd/88pm860x.h> |
21 | 22 | |
22 | 23 | #define LED_PWM_SHIFT (3) |
... | ... | @@ -118,7 +119,8 @@ |
118 | 119 | |
119 | 120 | struct pm860x_led *led; |
120 | 121 | struct pm860x_chip *chip; |
121 | - int mask; | |
122 | + unsigned char buf[3]; | |
123 | + int mask, ret; | |
122 | 124 | |
123 | 125 | led = container_of(work, struct pm860x_led, work); |
124 | 126 | chip = led->chip; |
125 | 127 | |
126 | 128 | |
... | ... | @@ -128,16 +130,27 @@ |
128 | 130 | pm860x_set_bits(led->i2c, __led_off(led->port), |
129 | 131 | LED_CURRENT_MASK, led->iset); |
130 | 132 | } |
133 | + pm860x_set_bits(led->i2c, __blink_off(led->port), | |
134 | + LED_BLINK_MASK, LED_ON_CONTINUOUS); | |
131 | 135 | mask = __blink_ctl_mask(led->port); |
132 | 136 | pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask); |
133 | - } else if (led->brightness == 0) { | |
134 | - pm860x_set_bits(led->i2c, __led_off(led->port), | |
135 | - LED_CURRENT_MASK, 0); | |
136 | - mask = __blink_ctl_mask(led->port); | |
137 | - pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0); | |
138 | 137 | } |
139 | 138 | pm860x_set_bits(led->i2c, __led_off(led->port), LED_PWM_MASK, |
140 | 139 | led->brightness); |
140 | + | |
141 | + if (led->brightness == 0) { | |
142 | + pm860x_bulk_read(led->i2c, __led_off(led->port), 3, buf); | |
143 | + ret = buf[0] & LED_PWM_MASK; | |
144 | + ret |= buf[1] & LED_PWM_MASK; | |
145 | + ret |= buf[2] & LED_PWM_MASK; | |
146 | + if (ret == 0) { | |
147 | + /* unset current since no led is lighting */ | |
148 | + pm860x_set_bits(led->i2c, __led_off(led->port), | |
149 | + LED_CURRENT_MASK, 0); | |
150 | + mask = __blink_ctl_mask(led->port); | |
151 | + pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0); | |
152 | + } | |
153 | + } | |
141 | 154 | led->current_brightness = led->brightness; |
142 | 155 | dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n", |
143 | 156 | __led_off(led->port), led->brightness); |
144 | 157 | |
145 | 158 | |
... | ... | @@ -153,31 +166,12 @@ |
153 | 166 | schedule_work(&data->work); |
154 | 167 | } |
155 | 168 | |
156 | -static int __check_device(struct pm860x_led_pdata *pdata, char *name) | |
157 | -{ | |
158 | - struct pm860x_led_pdata *p = pdata; | |
159 | - int ret = -EINVAL; | |
160 | - | |
161 | - while (p && p->id) { | |
162 | - if ((p->id != PM8606_ID_LED) || (p->flags < 0)) | |
163 | - break; | |
164 | - | |
165 | - if (!strncmp(name, pm860x_led_name[p->flags], | |
166 | - MFD_NAME_SIZE)) { | |
167 | - ret = (int)p->flags; | |
168 | - break; | |
169 | - } | |
170 | - p++; | |
171 | - } | |
172 | - return ret; | |
173 | -} | |
174 | - | |
175 | 169 | static int pm860x_led_probe(struct platform_device *pdev) |
176 | 170 | { |
177 | 171 | struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); |
178 | - struct pm860x_platform_data *pm860x_pdata; | |
179 | 172 | struct pm860x_led_pdata *pdata; |
180 | 173 | struct pm860x_led *data; |
174 | + struct mfd_cell *cell; | |
181 | 175 | struct resource *res; |
182 | 176 | int ret; |
183 | 177 | |
... | ... | @@ -187,10 +181,11 @@ |
187 | 181 | return -EINVAL; |
188 | 182 | } |
189 | 183 | |
190 | - if (pdev->dev.parent->platform_data) { | |
191 | - pm860x_pdata = pdev->dev.parent->platform_data; | |
192 | - pdata = pm860x_pdata->led; | |
193 | - } else { | |
184 | + cell = pdev->dev.platform_data; | |
185 | + if (cell == NULL) | |
186 | + return -ENODEV; | |
187 | + pdata = cell->mfd_data; | |
188 | + if (pdata == NULL) { | |
194 | 189 | dev_err(&pdev->dev, "No platform data!\n"); |
195 | 190 | return -EINVAL; |
196 | 191 | } |
197 | 192 | |
... | ... | @@ -198,12 +193,12 @@ |
198 | 193 | data = kzalloc(sizeof(struct pm860x_led), GFP_KERNEL); |
199 | 194 | if (data == NULL) |
200 | 195 | return -ENOMEM; |
201 | - strncpy(data->name, res->name, MFD_NAME_SIZE); | |
196 | + strncpy(data->name, res->name, MFD_NAME_SIZE - 1); | |
202 | 197 | dev_set_drvdata(&pdev->dev, data); |
203 | 198 | data->chip = chip; |
204 | 199 | data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion; |
205 | 200 | data->iset = pdata->iset; |
206 | - data->port = __check_device(pdata, data->name); | |
201 | + data->port = pdata->flags; | |
207 | 202 | if (data->port < 0) { |
208 | 203 | dev_err(&pdev->dev, "check device failed\n"); |
209 | 204 | kfree(data); |
... | ... | @@ -221,6 +216,7 @@ |
221 | 216 | dev_err(&pdev->dev, "Failed to register LED: %d\n", ret); |
222 | 217 | goto out; |
223 | 218 | } |
219 | + pm860x_led_set(&data->cdev, 0); | |
224 | 220 | return 0; |
225 | 221 | out: |
226 | 222 | kfree(data); |
drivers/mfd/88pm860x-core.c
... | ... | @@ -26,58 +26,33 @@ |
26 | 26 | {PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,}, |
27 | 27 | }; |
28 | 28 | |
29 | +static struct resource led_resources[] __initdata = { | |
30 | + {PM8606_LED1_RED, PM8606_LED1_RED, "led0-red", IORESOURCE_IO,}, | |
31 | + {PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,}, | |
32 | + {PM8606_LED1_BLUE, PM8606_LED1_BLUE, "led0-blue", IORESOURCE_IO,}, | |
33 | + {PM8606_LED2_RED, PM8606_LED2_RED, "led1-red", IORESOURCE_IO,}, | |
34 | + {PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_IO,}, | |
35 | + {PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_IO,}, | |
36 | +}; | |
37 | + | |
29 | 38 | static struct mfd_cell bk_devs[] __initdata = { |
30 | 39 | {"88pm860x-backlight", 0,}, |
31 | 40 | {"88pm860x-backlight", 1,}, |
32 | 41 | {"88pm860x-backlight", 2,}, |
33 | 42 | }; |
34 | 43 | |
35 | -static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)]; | |
36 | - | |
37 | -char pm860x_led_name[][MFD_NAME_SIZE] = { | |
38 | - "led0-red", | |
39 | - "led0-green", | |
40 | - "led0-blue", | |
41 | - "led1-red", | |
42 | - "led1-green", | |
43 | - "led1-blue", | |
44 | +static struct mfd_cell led_devs[] __initdata = { | |
45 | + {"88pm860x-led", 0,}, | |
46 | + {"88pm860x-led", 1,}, | |
47 | + {"88pm860x-led", 2,}, | |
48 | + {"88pm860x-led", 3,}, | |
49 | + {"88pm860x-led", 4,}, | |
50 | + {"88pm860x-led", 5,}, | |
44 | 51 | }; |
45 | -EXPORT_SYMBOL(pm860x_led_name); | |
46 | 52 | |
47 | -#define PM8606_LED_RESOURCE(_i, _x) \ | |
48 | -{ \ | |
49 | - .name = pm860x_led_name[_i], \ | |
50 | - .start = PM8606_##_x, \ | |
51 | - .end = PM8606_##_x, \ | |
52 | - .flags = IORESOURCE_IO, \ | |
53 | -} | |
53 | +static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)]; | |
54 | +static struct pm860x_led_pdata led_pdata[ARRAY_SIZE(led_devs)]; | |
54 | 55 | |
55 | -static struct resource led_resources[] = { | |
56 | - PM8606_LED_RESOURCE(PM8606_LED1_RED, RGB1B), | |
57 | - PM8606_LED_RESOURCE(PM8606_LED1_GREEN, RGB1C), | |
58 | - PM8606_LED_RESOURCE(PM8606_LED1_BLUE, RGB1D), | |
59 | - PM8606_LED_RESOURCE(PM8606_LED2_RED, RGB2B), | |
60 | - PM8606_LED_RESOURCE(PM8606_LED2_GREEN, RGB2C), | |
61 | - PM8606_LED_RESOURCE(PM8606_LED2_BLUE, RGB2D), | |
62 | -}; | |
63 | - | |
64 | -#define PM8606_LED_DEVS(_i) \ | |
65 | -{ \ | |
66 | - .name = "88pm860x-led", \ | |
67 | - .num_resources = 1, \ | |
68 | - .resources = &led_resources[_i], \ | |
69 | - .id = _i, \ | |
70 | -} | |
71 | - | |
72 | -static struct mfd_cell led_devs[] = { | |
73 | - PM8606_LED_DEVS(PM8606_LED1_RED), | |
74 | - PM8606_LED_DEVS(PM8606_LED1_GREEN), | |
75 | - PM8606_LED_DEVS(PM8606_LED1_BLUE), | |
76 | - PM8606_LED_DEVS(PM8606_LED2_RED), | |
77 | - PM8606_LED_DEVS(PM8606_LED2_GREEN), | |
78 | - PM8606_LED_DEVS(PM8606_LED2_BLUE), | |
79 | -}; | |
80 | - | |
81 | 56 | static struct resource touch_resources[] = { |
82 | 57 | { |
83 | 58 | .start = PM8607_IRQ_PEN, |
84 | 59 | |
85 | 60 | |
86 | 61 | |
... | ... | @@ -611,25 +586,41 @@ |
611 | 586 | } |
612 | 587 | } |
613 | 588 | |
614 | -static void __devinit device_8606_init(struct pm860x_chip *chip, | |
615 | - struct i2c_client *i2c, | |
616 | - struct pm860x_platform_data *pdata) | |
589 | +static void __devinit device_led_init(struct pm860x_chip *chip, | |
590 | + struct i2c_client *i2c, | |
591 | + struct pm860x_platform_data *pdata) | |
617 | 592 | { |
618 | 593 | int ret; |
594 | + int i, j, id; | |
619 | 595 | |
620 | - if (pdata && pdata->led) { | |
621 | - ret = mfd_add_devices(chip->dev, 0, &led_devs[0], | |
622 | - ARRAY_SIZE(led_devs), | |
623 | - &led_resources[0], 0); | |
624 | - if (ret < 0) { | |
625 | - dev_err(chip->dev, "Failed to add led " | |
626 | - "subdev\n"); | |
627 | - goto out_dev; | |
596 | + if ((pdata == NULL) || (pdata->led == NULL)) | |
597 | + return; | |
598 | + | |
599 | + if (pdata->num_leds > ARRAY_SIZE(led_devs)) | |
600 | + pdata->num_leds = ARRAY_SIZE(led_devs); | |
601 | + | |
602 | + for (i = 0; i < pdata->num_leds; i++) { | |
603 | + memcpy(&led_pdata[i], &pdata->led[i], | |
604 | + sizeof(struct pm860x_led_pdata)); | |
605 | + led_devs[i].mfd_data = &led_pdata[i]; | |
606 | + | |
607 | + for (j = 0; j < ARRAY_SIZE(led_devs); j++) { | |
608 | + id = led_resources[j].start; | |
609 | + if (led_pdata[i].flags != id) | |
610 | + continue; | |
611 | + | |
612 | + led_devs[i].num_resources = 1; | |
613 | + led_devs[i].resources = &led_resources[j], | |
614 | + ret = mfd_add_devices(chip->dev, 0, | |
615 | + &led_devs[i], 1, | |
616 | + &led_resources[j], 0); | |
617 | + if (ret < 0) { | |
618 | + dev_err(chip->dev, "Failed to add " | |
619 | + "led subdev\n"); | |
620 | + return; | |
621 | + } | |
628 | 622 | } |
629 | 623 | } |
630 | - return; | |
631 | -out_dev: | |
632 | - device_irq_exit(chip); | |
633 | 624 | } |
634 | 625 | |
635 | 626 | static void __devinit device_8607_init(struct pm860x_chip *chip, |
... | ... | @@ -748,7 +739,7 @@ |
748 | 739 | switch (chip->id) { |
749 | 740 | case CHIP_PM8606: |
750 | 741 | device_bk_init(chip, chip->client, pdata); |
751 | - device_8606_init(chip, chip->client, pdata); | |
742 | + device_led_init(chip, chip->client, pdata); | |
752 | 743 | break; |
753 | 744 | case CHIP_PM8607: |
754 | 745 | device_8607_init(chip, chip->client, pdata); |
... | ... | @@ -759,7 +750,7 @@ |
759 | 750 | switch (chip->id) { |
760 | 751 | case CHIP_PM8607: |
761 | 752 | device_bk_init(chip, chip->companion, pdata); |
762 | - device_8606_init(chip, chip->companion, pdata); | |
753 | + device_led_init(chip, chip->companion, pdata); | |
763 | 754 | break; |
764 | 755 | case CHIP_PM8606: |
765 | 756 | device_8607_init(chip, chip->companion, pdata); |
include/linux/mfd/88pm860x.h
... | ... | @@ -356,11 +356,10 @@ |
356 | 356 | int i2c_port; /* Controlled by GI2C or PI2C */ |
357 | 357 | int irq_mode; /* Clear interrupt by read/write(0/1) */ |
358 | 358 | int irq_base; /* IRQ base number of 88pm860x */ |
359 | + int num_leds; | |
359 | 360 | int num_backlights; |
360 | 361 | struct regulator_init_data *regulator[PM8607_MAX_REGULATOR]; |
361 | 362 | }; |
362 | - | |
363 | -extern char pm860x_led_name[][MFD_NAME_SIZE]; | |
364 | 363 | |
365 | 364 | extern int pm860x_reg_read(struct i2c_client *, int); |
366 | 365 | extern int pm860x_reg_write(struct i2c_client *, int, unsigned char); |