Blame view
drivers/leds/leds-pca955x.c
14.7 KB
36edc9395
|
1 |
// SPDX-License-Identifier: GPL-2.0-only |
f46e9203d
|
2 3 4 5 6 |
/* * Copyright 2007-2008 Extreme Engineering Solutions, Inc. * * Author: Nate Case <ncase@xes-inc.com> * |
f46e9203d
|
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
* LED driver for various PCA955x I2C LED drivers * * Supported devices: * * Device Description 7-bit slave address * ------ ----------- ------------------- * PCA9550 2-bit driver 0x60 .. 0x61 * PCA9551 8-bit driver 0x60 .. 0x67 * PCA9552 16-bit driver 0x60 .. 0x67 * PCA9553/01 4-bit driver 0x62 * PCA9553/02 4-bit driver 0x63 * * Philips PCA955x LED driver chips follow a register map as shown below: * * Control Register Description * ---------------- ----------- * 0x0 Input register 0 * .. * NUM_INPUT_REGS - 1 Last Input register X * * NUM_INPUT_REGS Frequency prescaler 0 * NUM_INPUT_REGS + 1 PWM register 0 * NUM_INPUT_REGS + 2 Frequency prescaler 1 * NUM_INPUT_REGS + 3 PWM register 1 * * NUM_INPUT_REGS + 4 LED selector 0 * NUM_INPUT_REGS + 4 * + NUM_LED_REGS - 1 Last LED selector * * where NUM_INPUT_REGS and NUM_LED_REGS vary depending on how many * bits the chip supports. */ |
f46e9203d
|
39 |
#include <linux/ctype.h> |
ed1f4b967
|
40 |
#include <linux/delay.h> |
f46e9203d
|
41 |
#include <linux/err.h> |
0987c7df8
|
42 |
#include <linux/gpio/driver.h> |
f46e9203d
|
43 |
#include <linux/i2c.h> |
ed1f4b967
|
44 45 |
#include <linux/leds.h> #include <linux/module.h> |
ed1f4b967
|
46 |
#include <linux/of.h> |
967f69de8
|
47 |
#include <linux/property.h> |
5a0e3ad6a
|
48 |
#include <linux/slab.h> |
ed1f4b967
|
49 |
#include <linux/string.h> |
f46e9203d
|
50 |
|
561099a1a
|
51 |
#include <dt-bindings/leds/leds-pca955x.h> |
f46e9203d
|
52 53 54 55 56 |
/* LED select registers determine the source that drives LED outputs */ #define PCA955X_LS_LED_ON 0x0 /* Output LOW */ #define PCA955X_LS_LED_OFF 0x1 /* Output HI-Z */ #define PCA955X_LS_BLINK0 0x2 /* Blink at PWM0 rate */ #define PCA955X_LS_BLINK1 0x3 /* Blink at PWM1 rate */ |
52ca7d0f7
|
57 58 59 |
#define PCA955X_GPIO_INPUT LED_OFF #define PCA955X_GPIO_HIGH LED_OFF #define PCA955X_GPIO_LOW LED_FULL |
f46e9203d
|
60 61 62 63 |
enum pca955x_type { pca9550, pca9551, pca9552, |
46de3adb5
|
64 |
ibm_pca9552, |
f46e9203d
|
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
pca9553, }; struct pca955x_chipdef { int bits; u8 slv_addr; /* 7-bit slave address mask */ int slv_addr_shift; /* Number of bits to ignore */ }; static struct pca955x_chipdef pca955x_chipdefs[] = { [pca9550] = { .bits = 2, .slv_addr = /* 110000x */ 0x60, .slv_addr_shift = 1, }, [pca9551] = { .bits = 8, .slv_addr = /* 1100xxx */ 0x60, .slv_addr_shift = 3, }, [pca9552] = { .bits = 16, .slv_addr = /* 1100xxx */ 0x60, .slv_addr_shift = 3, }, |
46de3adb5
|
90 91 92 93 94 |
[ibm_pca9552] = { .bits = 16, .slv_addr = /* 0110xxx */ 0x30, .slv_addr_shift = 3, }, |
f46e9203d
|
95 96 97 98 99 100 101 102 103 104 105 |
[pca9553] = { .bits = 4, .slv_addr = /* 110001x */ 0x62, .slv_addr_shift = 1, }, }; static const struct i2c_device_id pca955x_id[] = { { "pca9550", pca9550 }, { "pca9551", pca9551 }, { "pca9552", pca9552 }, |
46de3adb5
|
106 |
{ "ibm-pca9552", ibm_pca9552 }, |
f46e9203d
|
107 108 109 110 |
{ "pca9553", pca9553 }, { } }; MODULE_DEVICE_TABLE(i2c, pca955x_id); |
e7e11d8ba
|
111 112 113 |
struct pca955x { struct mutex lock; struct pca955x_led *leds; |
f46e9203d
|
114 115 |
struct pca955x_chipdef *chipdef; struct i2c_client *client; |
561099a1a
|
116 117 118 |
#ifdef CONFIG_LEDS_PCA955X_GPIO struct gpio_chip gpio; #endif |
e7e11d8ba
|
119 120 121 122 |
}; struct pca955x_led { struct pca955x *pca955x; |
f46e9203d
|
123 124 125 |
struct led_classdev led_cdev; int led_num; /* 0 .. 15 potentially */ char name[32]; |
561099a1a
|
126 |
u32 type; |
ed1f4b967
|
127 128 129 130 131 132 |
const char *default_trigger; }; struct pca955x_platform_data { struct pca955x_led *leds; int num_leds; |
f46e9203d
|
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
}; /* 8 bits per input register */ static inline int pca95xx_num_input_regs(int bits) { return (bits + 7) / 8; } /* 4 bits per LED selector register */ static inline int pca95xx_num_led_regs(int bits) { return (bits + 3) / 4; } /* * Return an LED selector register value based on an existing one, with * the appropriate 2-bit state value set for the given LED number (0-3). */ static inline u8 pca955x_ledsel(u8 oldval, int led_num, int state) { return (oldval & (~(0x3 << (led_num << 1)))) | ((state & 0x3) << (led_num << 1)); } /* * Write to frequency prescaler register, used to program the * period of the PWM output. period = (PSCx + 1) / 38 */ |
1591caf2d
|
161 |
static int pca955x_write_psc(struct i2c_client *client, int n, u8 val) |
f46e9203d
|
162 |
{ |
e7e11d8ba
|
163 |
struct pca955x *pca955x = i2c_get_clientdata(client); |
1591caf2d
|
164 |
int ret; |
f46e9203d
|
165 |
|
1591caf2d
|
166 |
ret = i2c_smbus_write_byte_data(client, |
f46e9203d
|
167 168 |
pca95xx_num_input_regs(pca955x->chipdef->bits) + 2*n, val); |
1591caf2d
|
169 170 171 172 173 |
if (ret < 0) dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d ", __func__, n, val, ret); return ret; |
f46e9203d
|
174 175 176 177 178 179 180 181 182 |
} /* * Write to PWM register, which determines the duty cycle of the * output. LED is OFF when the count is less than the value of this * register, and ON when it is greater. If PWMx == 0, LED is always OFF. * * Duty cycle is (256 - PWMx) / 256 */ |
1591caf2d
|
183 |
static int pca955x_write_pwm(struct i2c_client *client, int n, u8 val) |
f46e9203d
|
184 |
{ |
e7e11d8ba
|
185 |
struct pca955x *pca955x = i2c_get_clientdata(client); |
1591caf2d
|
186 |
int ret; |
f46e9203d
|
187 |
|
1591caf2d
|
188 |
ret = i2c_smbus_write_byte_data(client, |
f46e9203d
|
189 190 |
pca95xx_num_input_regs(pca955x->chipdef->bits) + 1 + 2*n, val); |
1591caf2d
|
191 192 193 194 195 |
if (ret < 0) dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d ", __func__, n, val, ret); return ret; |
f46e9203d
|
196 197 198 199 200 201 |
} /* * Write to LED selector register, which determines the source that * drives the LED output. */ |
1591caf2d
|
202 |
static int pca955x_write_ls(struct i2c_client *client, int n, u8 val) |
f46e9203d
|
203 |
{ |
e7e11d8ba
|
204 |
struct pca955x *pca955x = i2c_get_clientdata(client); |
1591caf2d
|
205 |
int ret; |
f46e9203d
|
206 |
|
1591caf2d
|
207 |
ret = i2c_smbus_write_byte_data(client, |
f46e9203d
|
208 209 |
pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n, val); |
1591caf2d
|
210 211 212 213 214 |
if (ret < 0) dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d ", __func__, n, val, ret); return ret; |
f46e9203d
|
215 216 217 218 219 220 |
} /* * Read the LED selector register, which determines the source that * drives the LED output. */ |
1591caf2d
|
221 |
static int pca955x_read_ls(struct i2c_client *client, int n, u8 *val) |
f46e9203d
|
222 |
{ |
e7e11d8ba
|
223 |
struct pca955x *pca955x = i2c_get_clientdata(client); |
1591caf2d
|
224 |
int ret; |
f46e9203d
|
225 |
|
1591caf2d
|
226 |
ret = i2c_smbus_read_byte_data(client, |
f46e9203d
|
227 |
pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n); |
1591caf2d
|
228 229 230 231 232 233 234 235 |
if (ret < 0) { dev_err(&client->dev, "%s: reg 0x%x, err %d ", __func__, n, ret); return ret; } *val = (u8)ret; return 0; |
f46e9203d
|
236 |
} |
c3482b825
|
237 238 |
static int pca955x_led_set(struct led_classdev *led_cdev, enum led_brightness value) |
f46e9203d
|
239 |
{ |
e7e11d8ba
|
240 241 |
struct pca955x_led *pca955x_led; struct pca955x *pca955x; |
f46e9203d
|
242 243 244 |
u8 ls; int chip_ls; /* which LSx to use (0-3 potentially) */ int ls_led; /* which set of bits within LSx to use (0-3) */ |
1591caf2d
|
245 |
int ret; |
f46e9203d
|
246 |
|
c3482b825
|
247 |
pca955x_led = container_of(led_cdev, struct pca955x_led, led_cdev); |
e7e11d8ba
|
248 249 250 251 252 253 |
pca955x = pca955x_led->pca955x; chip_ls = pca955x_led->led_num / 4; ls_led = pca955x_led->led_num % 4; mutex_lock(&pca955x->lock); |
f46e9203d
|
254 |
|
1591caf2d
|
255 256 257 |
ret = pca955x_read_ls(pca955x->client, chip_ls, &ls); if (ret) goto out; |
f46e9203d
|
258 |
|
c3482b825
|
259 |
switch (value) { |
f46e9203d
|
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
case LED_FULL: ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_LED_ON); break; case LED_OFF: ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_LED_OFF); break; case LED_HALF: ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_BLINK0); break; default: /* * Use PWM1 for all other values. This has the unwanted * side effect of making all LEDs on the chip share the * same brightness level if set to a value other than * OFF, HALF, or FULL. But, this is probably better than * just turning off for all other values. */ |
1591caf2d
|
277 278 279 |
ret = pca955x_write_pwm(pca955x->client, 1, 255 - value); if (ret) goto out; |
f46e9203d
|
280 281 282 |
ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_BLINK1); break; } |
1591caf2d
|
283 |
ret = pca955x_write_ls(pca955x->client, chip_ls, ls); |
e7e11d8ba
|
284 |
|
1591caf2d
|
285 |
out: |
e7e11d8ba
|
286 |
mutex_unlock(&pca955x->lock); |
f46e9203d
|
287 |
|
1591caf2d
|
288 |
return ret; |
f46e9203d
|
289 |
} |
561099a1a
|
290 291 292 293 |
#ifdef CONFIG_LEDS_PCA955X_GPIO /* * Read the INPUT register, which contains the state of LEDs. */ |
1591caf2d
|
294 |
static int pca955x_read_input(struct i2c_client *client, int n, u8 *val) |
561099a1a
|
295 |
{ |
1591caf2d
|
296 297 298 299 300 301 302 303 304 305 |
int ret = i2c_smbus_read_byte_data(client, n); if (ret < 0) { dev_err(&client->dev, "%s: reg 0x%x, err %d ", __func__, n, ret); return ret; } *val = (u8)ret; return 0; |
561099a1a
|
306 307 308 309 310 311 312 313 314 315 316 317 |
} static int pca955x_gpio_request_pin(struct gpio_chip *gc, unsigned int offset) { struct pca955x *pca955x = gpiochip_get_data(gc); struct pca955x_led *led = &pca955x->leds[offset]; if (led->type == PCA955X_TYPE_GPIO) return 0; return -EBUSY; } |
1591caf2d
|
318 319 |
static int pca955x_set_value(struct gpio_chip *gc, unsigned int offset, int val) |
561099a1a
|
320 321 322 323 324 |
{ struct pca955x *pca955x = gpiochip_get_data(gc); struct pca955x_led *led = &pca955x->leds[offset]; if (val) |
52ca7d0f7
|
325 326 327 |
return pca955x_led_set(&led->led_cdev, PCA955X_GPIO_HIGH); return pca955x_led_set(&led->led_cdev, PCA955X_GPIO_LOW); |
1591caf2d
|
328 329 330 331 332 333 |
} static void pca955x_gpio_set_value(struct gpio_chip *gc, unsigned int offset, int val) { pca955x_set_value(gc, offset, val); |
561099a1a
|
334 335 336 337 338 339 |
} static int pca955x_gpio_get_value(struct gpio_chip *gc, unsigned int offset) { struct pca955x *pca955x = gpiochip_get_data(gc); struct pca955x_led *led = &pca955x->leds[offset]; |
1591caf2d
|
340 341 342 343 |
u8 reg = 0; /* There is nothing we can do about errors */ pca955x_read_input(pca955x->client, led->led_num / 8, ®); |
561099a1a
|
344 345 346 347 348 349 350 |
return !!(reg & (1 << (led->led_num % 8))); } static int pca955x_gpio_direction_input(struct gpio_chip *gc, unsigned int offset) { |
52ca7d0f7
|
351 352 353 354 355 |
struct pca955x *pca955x = gpiochip_get_data(gc); struct pca955x_led *led = &pca955x->leds[offset]; /* To use as input ensure pin is not driven. */ return pca955x_led_set(&led->led_cdev, PCA955X_GPIO_INPUT); |
561099a1a
|
356 357 358 359 360 |
} static int pca955x_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, int val) { |
1591caf2d
|
361 |
return pca955x_set_value(gc, offset, val); |
561099a1a
|
362 363 |
} #endif /* CONFIG_LEDS_PCA955X_GPIO */ |
ed1f4b967
|
364 |
static struct pca955x_platform_data * |
967f69de8
|
365 |
pca955x_get_pdata(struct i2c_client *client, struct pca955x_chipdef *chip) |
ed1f4b967
|
366 |
{ |
ed1f4b967
|
367 |
struct pca955x_platform_data *pdata; |
967f69de8
|
368 |
struct fwnode_handle *child; |
ed1f4b967
|
369 |
int count; |
967f69de8
|
370 |
count = device_get_child_node_count(&client->dev); |
ed1f4b967
|
371 372 373 374 375 376 |
if (!count || count > chip->bits) return ERR_PTR(-ENODEV); pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return ERR_PTR(-ENOMEM); |
a86854d0c
|
377 378 |
pdata->leds = devm_kcalloc(&client->dev, chip->bits, sizeof(struct pca955x_led), |
ed1f4b967
|
379 380 381 |
GFP_KERNEL); if (!pdata->leds) return ERR_PTR(-ENOMEM); |
967f69de8
|
382 |
device_for_each_child_node(&client->dev, child) { |
ed1f4b967
|
383 384 385 |
const char *name; u32 reg; int res; |
967f69de8
|
386 |
res = fwnode_property_read_u32(child, "reg", ®); |
ed1f4b967
|
387 388 |
if ((res != 0) || (reg >= chip->bits)) continue; |
967f69de8
|
389 390 391 |
res = fwnode_property_read_string(child, "label", &name); if ((res != 0) && is_of_node(child)) name = to_of_node(child)->name; |
ed1f4b967
|
392 393 394 |
snprintf(pdata->leds[reg].name, sizeof(pdata->leds[reg].name), "%s", name); |
561099a1a
|
395 |
pdata->leds[reg].type = PCA955X_TYPE_LED; |
967f69de8
|
396 397 |
fwnode_property_read_u32(child, "type", &pdata->leds[reg].type); fwnode_property_read_string(child, "linux,default-trigger", |
ed1f4b967
|
398 399 400 401 402 403 404 405 406 407 408 409 |
&pdata->leds[reg].default_trigger); } pdata->num_leds = chip->bits; return pdata; } static const struct of_device_id of_pca955x_match[] = { { .compatible = "nxp,pca9550", .data = (void *)pca9550 }, { .compatible = "nxp,pca9551", .data = (void *)pca9551 }, { .compatible = "nxp,pca9552", .data = (void *)pca9552 }, |
46de3adb5
|
410 |
{ .compatible = "ibm,pca9552", .data = (void *)ibm_pca9552 }, |
ed1f4b967
|
411 412 413 |
{ .compatible = "nxp,pca9553", .data = (void *)pca9553 }, {}, }; |
ed1f4b967
|
414 |
MODULE_DEVICE_TABLE(of, of_pca955x_match); |
ed1f4b967
|
415 |
|
98ea1ea20
|
416 |
static int pca955x_probe(struct i2c_client *client, |
f46e9203d
|
417 418 |
const struct i2c_device_id *id) { |
e7e11d8ba
|
419 420 |
struct pca955x *pca955x; struct pca955x_led *pca955x_led; |
f46e9203d
|
421 422 |
struct pca955x_chipdef *chip; struct i2c_adapter *adapter; |
95bf14bff
|
423 |
int i, err; |
ed1f4b967
|
424 |
struct pca955x_platform_data *pdata; |
561099a1a
|
425 |
int ngpios = 0; |
f46e9203d
|
426 |
|
5b6cd445d
|
427 |
chip = &pca955x_chipdefs[id->driver_data]; |
1c57d9bd2
|
428 |
adapter = client->adapter; |
87aae1ea8
|
429 |
pdata = dev_get_platdata(&client->dev); |
ed1f4b967
|
430 |
if (!pdata) { |
967f69de8
|
431 |
pdata = pca955x_get_pdata(client, chip); |
ed1f4b967
|
432 433 434 |
if (IS_ERR(pdata)) return PTR_ERR(pdata); } |
f46e9203d
|
435 436 437 438 439 440 441 442 443 |
/* Make sure the slave address / chip type combo given is possible */ if ((client->addr & ~((1 << chip->slv_addr_shift) - 1)) != chip->slv_addr) { dev_err(&client->dev, "invalid slave address %02x ", client->addr); return -ENODEV; } |
b40b0c17d
|
444 |
dev_info(&client->dev, "leds-pca955x: Using %s %d-bit LED driver at " |
f46e9203d
|
445 446 |
"slave address 0x%02x ", |
44b3e31d5
|
447 |
client->name, chip->bits, client->addr); |
f46e9203d
|
448 |
|
aace34c0b
|
449 |
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
f46e9203d
|
450 |
return -EIO; |
ed1f4b967
|
451 452 453 454 455 456 |
if (pdata->num_leds != chip->bits) { dev_err(&client->dev, "board info claims %d LEDs on a %d-bit chip ", pdata->num_leds, chip->bits); return -ENODEV; |
f46e9203d
|
457 |
} |
73759f6ab
|
458 |
pca955x = devm_kzalloc(&client->dev, sizeof(*pca955x), GFP_KERNEL); |
95bf14bff
|
459 460 |
if (!pca955x) return -ENOMEM; |
a86854d0c
|
461 462 |
pca955x->leds = devm_kcalloc(&client->dev, chip->bits, sizeof(*pca955x_led), GFP_KERNEL); |
73759f6ab
|
463 464 |
if (!pca955x->leds) return -ENOMEM; |
e7e11d8ba
|
465 |
|
95bf14bff
|
466 |
i2c_set_clientdata(client, pca955x); |
e7e11d8ba
|
467 468 469 |
mutex_init(&pca955x->lock); pca955x->client = client; pca955x->chipdef = chip; |
f46e9203d
|
470 |
for (i = 0; i < chip->bits; i++) { |
e7e11d8ba
|
471 472 473 |
pca955x_led = &pca955x->leds[i]; pca955x_led->led_num = i; pca955x_led->pca955x = pca955x; |
561099a1a
|
474 475 476 477 478 479 480 481 482 483 484 485 486 |
pca955x_led->type = pdata->leds[i].type; switch (pca955x_led->type) { case PCA955X_TYPE_NONE: break; case PCA955X_TYPE_GPIO: ngpios++; break; case PCA955X_TYPE_LED: /* * Platform data can specify LED names and * default triggers */ |
390c97dc6
|
487 488 489 490 491 492 493 |
if (pdata->leds[i].name[0] == '\0') snprintf(pdata->leds[i].name, sizeof(pdata->leds[i].name), "%d", i); snprintf(pca955x_led->name, sizeof(pca955x_led->name), "pca955x:%s", pdata->leds[i].name); |
f46e9203d
|
494 |
if (pdata->leds[i].default_trigger) |
e7e11d8ba
|
495 |
pca955x_led->led_cdev.default_trigger = |
f46e9203d
|
496 |
pdata->leds[i].default_trigger; |
f46e9203d
|
497 |
|
561099a1a
|
498 499 500 |
pca955x_led->led_cdev.name = pca955x_led->name; pca955x_led->led_cdev.brightness_set_blocking = pca955x_led_set; |
f46e9203d
|
501 |
|
561099a1a
|
502 503 504 505 |
err = devm_led_classdev_register(&client->dev, &pca955x_led->led_cdev); if (err) return err; |
f46e9203d
|
506 |
|
561099a1a
|
507 |
/* Turn off LED */ |
1591caf2d
|
508 509 510 |
err = pca955x_led_set(&pca955x_led->led_cdev, LED_OFF); if (err) return err; |
561099a1a
|
511 512 |
} } |
f46e9203d
|
513 514 |
/* PWM0 is used for half brightness or 50% duty cycle */ |
1591caf2d
|
515 516 517 |
err = pca955x_write_pwm(client, 0, 255 - LED_HALF); if (err) return err; |
f46e9203d
|
518 519 |
/* PWM1 is used for variable brightness, default to OFF */ |
1591caf2d
|
520 521 522 |
err = pca955x_write_pwm(client, 1, 0); if (err) return err; |
f46e9203d
|
523 524 |
/* Set to fast frequency so we do not see flashing */ |
1591caf2d
|
525 526 527 528 529 530 |
err = pca955x_write_psc(client, 0, 0); if (err) return err; err = pca955x_write_psc(client, 1, 0); if (err) return err; |
f46e9203d
|
531 |
|
561099a1a
|
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 |
#ifdef CONFIG_LEDS_PCA955X_GPIO if (ngpios) { pca955x->gpio.label = "gpio-pca955x"; pca955x->gpio.direction_input = pca955x_gpio_direction_input; pca955x->gpio.direction_output = pca955x_gpio_direction_output; pca955x->gpio.set = pca955x_gpio_set_value; pca955x->gpio.get = pca955x_gpio_get_value; pca955x->gpio.request = pca955x_gpio_request_pin; pca955x->gpio.can_sleep = 1; pca955x->gpio.base = -1; pca955x->gpio.ngpio = ngpios; pca955x->gpio.parent = &client->dev; pca955x->gpio.owner = THIS_MODULE; err = devm_gpiochip_add_data(&client->dev, &pca955x->gpio, pca955x); if (err) { /* Use data->gpio.dev as a flag for freeing gpiochip */ pca955x->gpio.parent = NULL; dev_warn(&client->dev, "could not add gpiochip "); return err; } dev_info(&client->dev, "gpios %i...%i ", pca955x->gpio.base, pca955x->gpio.base + pca955x->gpio.ngpio - 1); } #endif |
f46e9203d
|
561 |
return 0; |
f46e9203d
|
562 563 564 565 566 |
} static struct i2c_driver pca955x_driver = { .driver = { .name = "leds-pca955x", |
967f69de8
|
567 |
.of_match_table = of_pca955x_match, |
f46e9203d
|
568 569 |
}, .probe = pca955x_probe, |
f46e9203d
|
570 571 |
.id_table = pca955x_id, }; |
09a0d183e
|
572 |
module_i2c_driver(pca955x_driver); |
f46e9203d
|
573 574 575 576 |
MODULE_AUTHOR("Nate Case <ncase@xes-inc.com>"); MODULE_DESCRIPTION("PCA955x LED driver"); MODULE_LICENSE("GPL v2"); |