156a1740cSRicardo Ribalda Delgado /* 256a1740cSRicardo Ribalda Delgado * Copyright 2011 bct electronic GmbH 356a1740cSRicardo Ribalda Delgado * Copyright 2013 Qtechnology/AS 456a1740cSRicardo Ribalda Delgado * 556a1740cSRicardo Ribalda Delgado * Author: Peter Meerwald <p.meerwald@bct-electronic.com> 656a1740cSRicardo Ribalda Delgado * Author: Ricardo Ribalda <ricardo.ribalda@gmail.com> 756a1740cSRicardo Ribalda Delgado * 856a1740cSRicardo Ribalda Delgado * Based on leds-pca955x.c 956a1740cSRicardo Ribalda Delgado * 1056a1740cSRicardo Ribalda Delgado * This file is subject to the terms and conditions of version 2 of 1156a1740cSRicardo Ribalda Delgado * the GNU General Public License. See the file COPYING in the main 1256a1740cSRicardo Ribalda Delgado * directory of this archive for more details. 1356a1740cSRicardo Ribalda Delgado * 1456a1740cSRicardo Ribalda Delgado * LED driver for the PCA9633 I2C LED driver (7-bit slave address 0x62) 153dfedb9dSPeter Meerwald * LED driver for the PCA9634/5 I2C LED driver (7-bit slave address set by hw.) 1656a1740cSRicardo Ribalda Delgado * 1756a1740cSRicardo Ribalda Delgado * Note that hardware blinking violates the leds infrastructure driver 1856a1740cSRicardo Ribalda Delgado * interface since the hardware only supports blinking all LEDs with the 1956a1740cSRicardo Ribalda Delgado * same delay_on/delay_off rates. That is, only the LEDs that are set to 2056a1740cSRicardo Ribalda Delgado * blink will actually blink but all LEDs that are set to blink will blink 2156a1740cSRicardo Ribalda Delgado * in identical fashion. The delay_on/delay_off values of the last LED 2256a1740cSRicardo Ribalda Delgado * that is set to blink will be used for all of the blinking LEDs. 2356a1740cSRicardo Ribalda Delgado * Hardware blinking is disabled by default but can be enabled by setting 2456a1740cSRicardo Ribalda Delgado * the 'blink_type' member in the platform_data struct to 'PCA963X_HW_BLINK' 2556a1740cSRicardo Ribalda Delgado * or by adding the 'nxp,hw-blink' property to the DTS. 2656a1740cSRicardo Ribalda Delgado */ 2756a1740cSRicardo Ribalda Delgado 2856a1740cSRicardo Ribalda Delgado #include <linux/module.h> 2956a1740cSRicardo Ribalda Delgado #include <linux/delay.h> 3056a1740cSRicardo Ribalda Delgado #include <linux/string.h> 3156a1740cSRicardo Ribalda Delgado #include <linux/ctype.h> 3256a1740cSRicardo Ribalda Delgado #include <linux/leds.h> 3356a1740cSRicardo Ribalda Delgado #include <linux/err.h> 3456a1740cSRicardo Ribalda Delgado #include <linux/i2c.h> 3556a1740cSRicardo Ribalda Delgado #include <linux/slab.h> 3656a1740cSRicardo Ribalda Delgado #include <linux/of.h> 3756a1740cSRicardo Ribalda Delgado #include <linux/platform_data/leds-pca963x.h> 3856a1740cSRicardo Ribalda Delgado 3956a1740cSRicardo Ribalda Delgado /* LED select registers determine the source that drives LED outputs */ 4056a1740cSRicardo Ribalda Delgado #define PCA963X_LED_OFF 0x0 /* LED driver off */ 4156a1740cSRicardo Ribalda Delgado #define PCA963X_LED_ON 0x1 /* LED driver on */ 4256a1740cSRicardo Ribalda Delgado #define PCA963X_LED_PWM 0x2 /* Controlled through PWM */ 4356a1740cSRicardo Ribalda Delgado #define PCA963X_LED_GRP_PWM 0x3 /* Controlled through PWM/GRPPWM */ 4456a1740cSRicardo Ribalda Delgado 4556a1740cSRicardo Ribalda Delgado #define PCA963X_MODE2_DMBLNK 0x20 /* Enable blinking */ 4656a1740cSRicardo Ribalda Delgado 4756a1740cSRicardo Ribalda Delgado #define PCA963X_MODE1 0x00 4856a1740cSRicardo Ribalda Delgado #define PCA963X_MODE2 0x01 4956a1740cSRicardo Ribalda Delgado #define PCA963X_PWM_BASE 0x02 5056a1740cSRicardo Ribalda Delgado 5156a1740cSRicardo Ribalda Delgado enum pca963x_type { 5256a1740cSRicardo Ribalda Delgado pca9633, 5356a1740cSRicardo Ribalda Delgado pca9634, 543dfedb9dSPeter Meerwald pca9635, 5556a1740cSRicardo Ribalda Delgado }; 5656a1740cSRicardo Ribalda Delgado 5756a1740cSRicardo Ribalda Delgado struct pca963x_chipdef { 5856a1740cSRicardo Ribalda Delgado u8 grppwm; 5956a1740cSRicardo Ribalda Delgado u8 grpfreq; 6056a1740cSRicardo Ribalda Delgado u8 ledout_base; 6156a1740cSRicardo Ribalda Delgado int n_leds; 6235c7d301SMatt Ranostay unsigned int scaling; 6356a1740cSRicardo Ribalda Delgado }; 6456a1740cSRicardo Ribalda Delgado 6556a1740cSRicardo Ribalda Delgado static struct pca963x_chipdef pca963x_chipdefs[] = { 6656a1740cSRicardo Ribalda Delgado [pca9633] = { 6756a1740cSRicardo Ribalda Delgado .grppwm = 0x6, 6856a1740cSRicardo Ribalda Delgado .grpfreq = 0x7, 6956a1740cSRicardo Ribalda Delgado .ledout_base = 0x8, 7056a1740cSRicardo Ribalda Delgado .n_leds = 4, 7156a1740cSRicardo Ribalda Delgado }, 7256a1740cSRicardo Ribalda Delgado [pca9634] = { 7356a1740cSRicardo Ribalda Delgado .grppwm = 0xa, 7456a1740cSRicardo Ribalda Delgado .grpfreq = 0xb, 7556a1740cSRicardo Ribalda Delgado .ledout_base = 0xc, 7656a1740cSRicardo Ribalda Delgado .n_leds = 8, 7756a1740cSRicardo Ribalda Delgado }, 783dfedb9dSPeter Meerwald [pca9635] = { 793dfedb9dSPeter Meerwald .grppwm = 0x12, 803dfedb9dSPeter Meerwald .grpfreq = 0x13, 813dfedb9dSPeter Meerwald .ledout_base = 0x14, 823dfedb9dSPeter Meerwald .n_leds = 16, 833dfedb9dSPeter Meerwald }, 8456a1740cSRicardo Ribalda Delgado }; 8556a1740cSRicardo Ribalda Delgado 8656a1740cSRicardo Ribalda Delgado /* Total blink period in milliseconds */ 8756a1740cSRicardo Ribalda Delgado #define PCA963X_BLINK_PERIOD_MIN 42 8856a1740cSRicardo Ribalda Delgado #define PCA963X_BLINK_PERIOD_MAX 10667 8956a1740cSRicardo Ribalda Delgado 9056a1740cSRicardo Ribalda Delgado static const struct i2c_device_id pca963x_id[] = { 9156a1740cSRicardo Ribalda Delgado { "pca9632", pca9633 }, 9256a1740cSRicardo Ribalda Delgado { "pca9633", pca9633 }, 9356a1740cSRicardo Ribalda Delgado { "pca9634", pca9634 }, 943dfedb9dSPeter Meerwald { "pca9635", pca9635 }, 9556a1740cSRicardo Ribalda Delgado { } 9656a1740cSRicardo Ribalda Delgado }; 9756a1740cSRicardo Ribalda Delgado MODULE_DEVICE_TABLE(i2c, pca963x_id); 9856a1740cSRicardo Ribalda Delgado 9956a1740cSRicardo Ribalda Delgado struct pca963x_led; 10056a1740cSRicardo Ribalda Delgado 10156a1740cSRicardo Ribalda Delgado struct pca963x { 10256a1740cSRicardo Ribalda Delgado struct pca963x_chipdef *chipdef; 10356a1740cSRicardo Ribalda Delgado struct mutex mutex; 10456a1740cSRicardo Ribalda Delgado struct i2c_client *client; 10556a1740cSRicardo Ribalda Delgado struct pca963x_led *leds; 10656a1740cSRicardo Ribalda Delgado }; 10756a1740cSRicardo Ribalda Delgado 10856a1740cSRicardo Ribalda Delgado struct pca963x_led { 10956a1740cSRicardo Ribalda Delgado struct pca963x *chip; 11056a1740cSRicardo Ribalda Delgado struct led_classdev led_cdev; 1113dfedb9dSPeter Meerwald int led_num; /* 0 .. 15 potentially */ 11256a1740cSRicardo Ribalda Delgado char name[32]; 11356a1740cSRicardo Ribalda Delgado u8 gdc; 11456a1740cSRicardo Ribalda Delgado u8 gfrq; 11556a1740cSRicardo Ribalda Delgado }; 11656a1740cSRicardo Ribalda Delgado 1175029a2e3SAndrew Lunn static int pca963x_brightness(struct pca963x_led *pca963x, 1185029a2e3SAndrew Lunn enum led_brightness brightness) 11956a1740cSRicardo Ribalda Delgado { 12056a1740cSRicardo Ribalda Delgado u8 ledout_addr = pca963x->chip->chipdef->ledout_base 12156a1740cSRicardo Ribalda Delgado + (pca963x->led_num / 4); 12256a1740cSRicardo Ribalda Delgado u8 ledout; 12356a1740cSRicardo Ribalda Delgado int shift = 2 * (pca963x->led_num % 4); 12456a1740cSRicardo Ribalda Delgado u8 mask = 0x3 << shift; 1255029a2e3SAndrew Lunn int ret; 12656a1740cSRicardo Ribalda Delgado 12756a1740cSRicardo Ribalda Delgado mutex_lock(&pca963x->chip->mutex); 12856a1740cSRicardo Ribalda Delgado ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr); 1295029a2e3SAndrew Lunn switch (brightness) { 13056a1740cSRicardo Ribalda Delgado case LED_FULL: 1315029a2e3SAndrew Lunn ret = i2c_smbus_write_byte_data(pca963x->chip->client, 1325029a2e3SAndrew Lunn ledout_addr, 13356a1740cSRicardo Ribalda Delgado (ledout & ~mask) | (PCA963X_LED_ON << shift)); 13456a1740cSRicardo Ribalda Delgado break; 13556a1740cSRicardo Ribalda Delgado case LED_OFF: 1365029a2e3SAndrew Lunn ret = i2c_smbus_write_byte_data(pca963x->chip->client, 1375029a2e3SAndrew Lunn ledout_addr, ledout & ~mask); 13856a1740cSRicardo Ribalda Delgado break; 13956a1740cSRicardo Ribalda Delgado default: 1405029a2e3SAndrew Lunn ret = i2c_smbus_write_byte_data(pca963x->chip->client, 14156a1740cSRicardo Ribalda Delgado PCA963X_PWM_BASE + pca963x->led_num, 1425029a2e3SAndrew Lunn brightness); 1435029a2e3SAndrew Lunn if (ret < 0) 1445029a2e3SAndrew Lunn goto unlock; 1455029a2e3SAndrew Lunn ret = i2c_smbus_write_byte_data(pca963x->chip->client, 1465029a2e3SAndrew Lunn ledout_addr, 14756a1740cSRicardo Ribalda Delgado (ledout & ~mask) | (PCA963X_LED_PWM << shift)); 14856a1740cSRicardo Ribalda Delgado break; 14956a1740cSRicardo Ribalda Delgado } 1505029a2e3SAndrew Lunn unlock: 15156a1740cSRicardo Ribalda Delgado mutex_unlock(&pca963x->chip->mutex); 1525029a2e3SAndrew Lunn return ret; 15356a1740cSRicardo Ribalda Delgado } 15456a1740cSRicardo Ribalda Delgado 1555029a2e3SAndrew Lunn static void pca963x_blink(struct pca963x_led *pca963x) 15656a1740cSRicardo Ribalda Delgado { 15756a1740cSRicardo Ribalda Delgado u8 ledout_addr = pca963x->chip->chipdef->ledout_base + 15856a1740cSRicardo Ribalda Delgado (pca963x->led_num / 4); 15956a1740cSRicardo Ribalda Delgado u8 ledout; 16056a1740cSRicardo Ribalda Delgado u8 mode2 = i2c_smbus_read_byte_data(pca963x->chip->client, 16156a1740cSRicardo Ribalda Delgado PCA963X_MODE2); 16256a1740cSRicardo Ribalda Delgado int shift = 2 * (pca963x->led_num % 4); 16356a1740cSRicardo Ribalda Delgado u8 mask = 0x3 << shift; 16456a1740cSRicardo Ribalda Delgado 16556a1740cSRicardo Ribalda Delgado i2c_smbus_write_byte_data(pca963x->chip->client, 16656a1740cSRicardo Ribalda Delgado pca963x->chip->chipdef->grppwm, pca963x->gdc); 16756a1740cSRicardo Ribalda Delgado 16856a1740cSRicardo Ribalda Delgado i2c_smbus_write_byte_data(pca963x->chip->client, 16956a1740cSRicardo Ribalda Delgado pca963x->chip->chipdef->grpfreq, pca963x->gfrq); 17056a1740cSRicardo Ribalda Delgado 17156a1740cSRicardo Ribalda Delgado if (!(mode2 & PCA963X_MODE2_DMBLNK)) 17256a1740cSRicardo Ribalda Delgado i2c_smbus_write_byte_data(pca963x->chip->client, PCA963X_MODE2, 17356a1740cSRicardo Ribalda Delgado mode2 | PCA963X_MODE2_DMBLNK); 17456a1740cSRicardo Ribalda Delgado 17556a1740cSRicardo Ribalda Delgado mutex_lock(&pca963x->chip->mutex); 17656a1740cSRicardo Ribalda Delgado ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr); 17756a1740cSRicardo Ribalda Delgado if ((ledout & mask) != (PCA963X_LED_GRP_PWM << shift)) 17856a1740cSRicardo Ribalda Delgado i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr, 17956a1740cSRicardo Ribalda Delgado (ledout & ~mask) | (PCA963X_LED_GRP_PWM << shift)); 18056a1740cSRicardo Ribalda Delgado mutex_unlock(&pca963x->chip->mutex); 18156a1740cSRicardo Ribalda Delgado } 18256a1740cSRicardo Ribalda Delgado 1835029a2e3SAndrew Lunn static int pca963x_led_set(struct led_classdev *led_cdev, 18456a1740cSRicardo Ribalda Delgado enum led_brightness value) 18556a1740cSRicardo Ribalda Delgado { 18656a1740cSRicardo Ribalda Delgado struct pca963x_led *pca963x; 18756a1740cSRicardo Ribalda Delgado 18856a1740cSRicardo Ribalda Delgado pca963x = container_of(led_cdev, struct pca963x_led, led_cdev); 18956a1740cSRicardo Ribalda Delgado 1905029a2e3SAndrew Lunn return pca963x_brightness(pca963x, value); 19156a1740cSRicardo Ribalda Delgado } 19256a1740cSRicardo Ribalda Delgado 19335c7d301SMatt Ranostay static unsigned int pca963x_period_scale(struct pca963x_led *pca963x, 19435c7d301SMatt Ranostay unsigned int val) 19535c7d301SMatt Ranostay { 19635c7d301SMatt Ranostay unsigned int scaling = pca963x->chip->chipdef->scaling; 19735c7d301SMatt Ranostay 19835c7d301SMatt Ranostay return scaling ? DIV_ROUND_CLOSEST(val * scaling, 1000) : val; 19935c7d301SMatt Ranostay } 20035c7d301SMatt Ranostay 20156a1740cSRicardo Ribalda Delgado static int pca963x_blink_set(struct led_classdev *led_cdev, 20256a1740cSRicardo Ribalda Delgado unsigned long *delay_on, unsigned long *delay_off) 20356a1740cSRicardo Ribalda Delgado { 20456a1740cSRicardo Ribalda Delgado struct pca963x_led *pca963x; 20556a1740cSRicardo Ribalda Delgado unsigned long time_on, time_off, period; 20656a1740cSRicardo Ribalda Delgado u8 gdc, gfrq; 20756a1740cSRicardo Ribalda Delgado 20856a1740cSRicardo Ribalda Delgado pca963x = container_of(led_cdev, struct pca963x_led, led_cdev); 20956a1740cSRicardo Ribalda Delgado 21056a1740cSRicardo Ribalda Delgado time_on = *delay_on; 21156a1740cSRicardo Ribalda Delgado time_off = *delay_off; 21256a1740cSRicardo Ribalda Delgado 21356a1740cSRicardo Ribalda Delgado /* If both zero, pick reasonable defaults of 500ms each */ 21456a1740cSRicardo Ribalda Delgado if (!time_on && !time_off) { 21556a1740cSRicardo Ribalda Delgado time_on = 500; 21656a1740cSRicardo Ribalda Delgado time_off = 500; 21756a1740cSRicardo Ribalda Delgado } 21856a1740cSRicardo Ribalda Delgado 21935c7d301SMatt Ranostay period = pca963x_period_scale(pca963x, time_on + time_off); 22056a1740cSRicardo Ribalda Delgado 22156a1740cSRicardo Ribalda Delgado /* If period not supported by hardware, default to someting sane. */ 22256a1740cSRicardo Ribalda Delgado if ((period < PCA963X_BLINK_PERIOD_MIN) || 22356a1740cSRicardo Ribalda Delgado (period > PCA963X_BLINK_PERIOD_MAX)) { 22456a1740cSRicardo Ribalda Delgado time_on = 500; 22556a1740cSRicardo Ribalda Delgado time_off = 500; 22635c7d301SMatt Ranostay period = pca963x_period_scale(pca963x, 1000); 22756a1740cSRicardo Ribalda Delgado } 22856a1740cSRicardo Ribalda Delgado 22956a1740cSRicardo Ribalda Delgado /* 23056a1740cSRicardo Ribalda Delgado * From manual: duty cycle = (GDC / 256) -> 23156a1740cSRicardo Ribalda Delgado * (time_on / period) = (GDC / 256) -> 23256a1740cSRicardo Ribalda Delgado * GDC = ((time_on * 256) / period) 23356a1740cSRicardo Ribalda Delgado */ 23435c7d301SMatt Ranostay gdc = (pca963x_period_scale(pca963x, time_on) * 256) / period; 23556a1740cSRicardo Ribalda Delgado 23656a1740cSRicardo Ribalda Delgado /* 23756a1740cSRicardo Ribalda Delgado * From manual: period = ((GFRQ + 1) / 24) in seconds. 23856a1740cSRicardo Ribalda Delgado * So, period (in ms) = (((GFRQ + 1) / 24) * 1000) -> 23956a1740cSRicardo Ribalda Delgado * GFRQ = ((period * 24 / 1000) - 1) 24056a1740cSRicardo Ribalda Delgado */ 24156a1740cSRicardo Ribalda Delgado gfrq = (period * 24 / 1000) - 1; 24256a1740cSRicardo Ribalda Delgado 24356a1740cSRicardo Ribalda Delgado pca963x->gdc = gdc; 24456a1740cSRicardo Ribalda Delgado pca963x->gfrq = gfrq; 24556a1740cSRicardo Ribalda Delgado 2465029a2e3SAndrew Lunn pca963x_blink(pca963x); 24756a1740cSRicardo Ribalda Delgado 24856a1740cSRicardo Ribalda Delgado *delay_on = time_on; 24956a1740cSRicardo Ribalda Delgado *delay_off = time_off; 25056a1740cSRicardo Ribalda Delgado 25156a1740cSRicardo Ribalda Delgado return 0; 25256a1740cSRicardo Ribalda Delgado } 25356a1740cSRicardo Ribalda Delgado 25456a1740cSRicardo Ribalda Delgado #if IS_ENABLED(CONFIG_OF) 25556a1740cSRicardo Ribalda Delgado static struct pca963x_platform_data * 25656a1740cSRicardo Ribalda Delgado pca963x_dt_init(struct i2c_client *client, struct pca963x_chipdef *chip) 25756a1740cSRicardo Ribalda Delgado { 25856a1740cSRicardo Ribalda Delgado struct device_node *np = client->dev.of_node, *child; 25956a1740cSRicardo Ribalda Delgado struct pca963x_platform_data *pdata; 26056a1740cSRicardo Ribalda Delgado struct led_info *pca963x_leds; 26156a1740cSRicardo Ribalda Delgado int count; 26256a1740cSRicardo Ribalda Delgado 26356a1740cSRicardo Ribalda Delgado count = of_get_child_count(np); 26456a1740cSRicardo Ribalda Delgado if (!count || count > chip->n_leds) 26556a1740cSRicardo Ribalda Delgado return ERR_PTR(-ENODEV); 26656a1740cSRicardo Ribalda Delgado 26756a1740cSRicardo Ribalda Delgado pca963x_leds = devm_kzalloc(&client->dev, 26856a1740cSRicardo Ribalda Delgado sizeof(struct led_info) * chip->n_leds, GFP_KERNEL); 26956a1740cSRicardo Ribalda Delgado if (!pca963x_leds) 27056a1740cSRicardo Ribalda Delgado return ERR_PTR(-ENOMEM); 27156a1740cSRicardo Ribalda Delgado 27256a1740cSRicardo Ribalda Delgado for_each_child_of_node(np, child) { 273a44b0f5eSGeert Uytterhoeven struct led_info led = {}; 27456a1740cSRicardo Ribalda Delgado u32 reg; 27556a1740cSRicardo Ribalda Delgado int res; 27656a1740cSRicardo Ribalda Delgado 2778a6acd64SRicardo Ribalda Delgado res = of_property_read_u32(child, "reg", ®); 2788a6acd64SRicardo Ribalda Delgado if ((res != 0) || (reg >= chip->n_leds)) 2798a6acd64SRicardo Ribalda Delgado continue; 28056a1740cSRicardo Ribalda Delgado led.name = 28156a1740cSRicardo Ribalda Delgado of_get_property(child, "label", NULL) ? : child->name; 28256a1740cSRicardo Ribalda Delgado led.default_trigger = 28356a1740cSRicardo Ribalda Delgado of_get_property(child, "linux,default-trigger", NULL); 28456a1740cSRicardo Ribalda Delgado pca963x_leds[reg] = led; 28556a1740cSRicardo Ribalda Delgado } 28656a1740cSRicardo Ribalda Delgado pdata = devm_kzalloc(&client->dev, 28756a1740cSRicardo Ribalda Delgado sizeof(struct pca963x_platform_data), GFP_KERNEL); 28856a1740cSRicardo Ribalda Delgado if (!pdata) 28956a1740cSRicardo Ribalda Delgado return ERR_PTR(-ENOMEM); 29056a1740cSRicardo Ribalda Delgado 29156a1740cSRicardo Ribalda Delgado pdata->leds.leds = pca963x_leds; 2928a6acd64SRicardo Ribalda Delgado pdata->leds.num_leds = chip->n_leds; 29356a1740cSRicardo Ribalda Delgado 29456a1740cSRicardo Ribalda Delgado /* default to open-drain unless totem pole (push-pull) is specified */ 29556a1740cSRicardo Ribalda Delgado if (of_property_read_bool(np, "nxp,totem-pole")) 29656a1740cSRicardo Ribalda Delgado pdata->outdrv = PCA963X_TOTEM_POLE; 29756a1740cSRicardo Ribalda Delgado else 29856a1740cSRicardo Ribalda Delgado pdata->outdrv = PCA963X_OPEN_DRAIN; 29956a1740cSRicardo Ribalda Delgado 30056a1740cSRicardo Ribalda Delgado /* default to software blinking unless hardware blinking is specified */ 30156a1740cSRicardo Ribalda Delgado if (of_property_read_bool(np, "nxp,hw-blink")) 30256a1740cSRicardo Ribalda Delgado pdata->blink_type = PCA963X_HW_BLINK; 30356a1740cSRicardo Ribalda Delgado else 30456a1740cSRicardo Ribalda Delgado pdata->blink_type = PCA963X_SW_BLINK; 30556a1740cSRicardo Ribalda Delgado 30635c7d301SMatt Ranostay if (of_property_read_u32(np, "nxp,period-scale", &chip->scaling)) 30735c7d301SMatt Ranostay chip->scaling = 1000; 30835c7d301SMatt Ranostay 30956a1740cSRicardo Ribalda Delgado return pdata; 31056a1740cSRicardo Ribalda Delgado } 31156a1740cSRicardo Ribalda Delgado 31256a1740cSRicardo Ribalda Delgado static const struct of_device_id of_pca963x_match[] = { 31356a1740cSRicardo Ribalda Delgado { .compatible = "nxp,pca9632", }, 31456a1740cSRicardo Ribalda Delgado { .compatible = "nxp,pca9633", }, 31556a1740cSRicardo Ribalda Delgado { .compatible = "nxp,pca9634", }, 3163dfedb9dSPeter Meerwald { .compatible = "nxp,pca9635", }, 31756a1740cSRicardo Ribalda Delgado {}, 31856a1740cSRicardo Ribalda Delgado }; 3194d59ed85SJavier Martinez Canillas MODULE_DEVICE_TABLE(of, of_pca963x_match); 32056a1740cSRicardo Ribalda Delgado #else 32156a1740cSRicardo Ribalda Delgado static struct pca963x_platform_data * 32256a1740cSRicardo Ribalda Delgado pca963x_dt_init(struct i2c_client *client, struct pca963x_chipdef *chip) 32356a1740cSRicardo Ribalda Delgado { 32456a1740cSRicardo Ribalda Delgado return ERR_PTR(-ENODEV); 32556a1740cSRicardo Ribalda Delgado } 32656a1740cSRicardo Ribalda Delgado #endif 32756a1740cSRicardo Ribalda Delgado 32856a1740cSRicardo Ribalda Delgado static int pca963x_probe(struct i2c_client *client, 32956a1740cSRicardo Ribalda Delgado const struct i2c_device_id *id) 33056a1740cSRicardo Ribalda Delgado { 33156a1740cSRicardo Ribalda Delgado struct pca963x *pca963x_chip; 33256a1740cSRicardo Ribalda Delgado struct pca963x_led *pca963x; 33356a1740cSRicardo Ribalda Delgado struct pca963x_platform_data *pdata; 33456a1740cSRicardo Ribalda Delgado struct pca963x_chipdef *chip; 33556a1740cSRicardo Ribalda Delgado int i, err; 33656a1740cSRicardo Ribalda Delgado 33756a1740cSRicardo Ribalda Delgado chip = &pca963x_chipdefs[id->driver_data]; 33856a1740cSRicardo Ribalda Delgado pdata = dev_get_platdata(&client->dev); 33956a1740cSRicardo Ribalda Delgado 34056a1740cSRicardo Ribalda Delgado if (!pdata) { 34156a1740cSRicardo Ribalda Delgado pdata = pca963x_dt_init(client, chip); 34256a1740cSRicardo Ribalda Delgado if (IS_ERR(pdata)) { 34356a1740cSRicardo Ribalda Delgado dev_warn(&client->dev, "could not parse configuration\n"); 34456a1740cSRicardo Ribalda Delgado pdata = NULL; 34556a1740cSRicardo Ribalda Delgado } 34656a1740cSRicardo Ribalda Delgado } 34756a1740cSRicardo Ribalda Delgado 34856a1740cSRicardo Ribalda Delgado if (pdata && (pdata->leds.num_leds < 1 || 34956a1740cSRicardo Ribalda Delgado pdata->leds.num_leds > chip->n_leds)) { 35056a1740cSRicardo Ribalda Delgado dev_err(&client->dev, "board info must claim 1-%d LEDs", 35156a1740cSRicardo Ribalda Delgado chip->n_leds); 35256a1740cSRicardo Ribalda Delgado return -EINVAL; 35356a1740cSRicardo Ribalda Delgado } 35456a1740cSRicardo Ribalda Delgado 35556a1740cSRicardo Ribalda Delgado pca963x_chip = devm_kzalloc(&client->dev, sizeof(*pca963x_chip), 35656a1740cSRicardo Ribalda Delgado GFP_KERNEL); 35756a1740cSRicardo Ribalda Delgado if (!pca963x_chip) 35856a1740cSRicardo Ribalda Delgado return -ENOMEM; 35956a1740cSRicardo Ribalda Delgado pca963x = devm_kzalloc(&client->dev, chip->n_leds * sizeof(*pca963x), 36056a1740cSRicardo Ribalda Delgado GFP_KERNEL); 36156a1740cSRicardo Ribalda Delgado if (!pca963x) 36256a1740cSRicardo Ribalda Delgado return -ENOMEM; 36356a1740cSRicardo Ribalda Delgado 36456a1740cSRicardo Ribalda Delgado i2c_set_clientdata(client, pca963x_chip); 36556a1740cSRicardo Ribalda Delgado 36656a1740cSRicardo Ribalda Delgado mutex_init(&pca963x_chip->mutex); 36756a1740cSRicardo Ribalda Delgado pca963x_chip->chipdef = chip; 36856a1740cSRicardo Ribalda Delgado pca963x_chip->client = client; 36956a1740cSRicardo Ribalda Delgado pca963x_chip->leds = pca963x; 37056a1740cSRicardo Ribalda Delgado 37156a1740cSRicardo Ribalda Delgado /* Turn off LEDs by default*/ 3723dfedb9dSPeter Meerwald for (i = 0; i < chip->n_leds / 4; i++) 3733dfedb9dSPeter Meerwald i2c_smbus_write_byte_data(client, chip->ledout_base + i, 0x00); 37456a1740cSRicardo Ribalda Delgado 37556a1740cSRicardo Ribalda Delgado for (i = 0; i < chip->n_leds; i++) { 37656a1740cSRicardo Ribalda Delgado pca963x[i].led_num = i; 37756a1740cSRicardo Ribalda Delgado pca963x[i].chip = pca963x_chip; 37856a1740cSRicardo Ribalda Delgado 37956a1740cSRicardo Ribalda Delgado /* Platform data can specify LED names and default triggers */ 38056a1740cSRicardo Ribalda Delgado if (pdata && i < pdata->leds.num_leds) { 38156a1740cSRicardo Ribalda Delgado if (pdata->leds.leds[i].name) 38256a1740cSRicardo Ribalda Delgado snprintf(pca963x[i].name, 38356a1740cSRicardo Ribalda Delgado sizeof(pca963x[i].name), "pca963x:%s", 38456a1740cSRicardo Ribalda Delgado pdata->leds.leds[i].name); 38556a1740cSRicardo Ribalda Delgado if (pdata->leds.leds[i].default_trigger) 38656a1740cSRicardo Ribalda Delgado pca963x[i].led_cdev.default_trigger = 38756a1740cSRicardo Ribalda Delgado pdata->leds.leds[i].default_trigger; 38856a1740cSRicardo Ribalda Delgado } 38956a1740cSRicardo Ribalda Delgado if (!pdata || i >= pdata->leds.num_leds || 39056a1740cSRicardo Ribalda Delgado !pdata->leds.leds[i].name) 39156a1740cSRicardo Ribalda Delgado snprintf(pca963x[i].name, sizeof(pca963x[i].name), 39256a1740cSRicardo Ribalda Delgado "pca963x:%d:%.2x:%d", client->adapter->nr, 39356a1740cSRicardo Ribalda Delgado client->addr, i); 39456a1740cSRicardo Ribalda Delgado 39556a1740cSRicardo Ribalda Delgado pca963x[i].led_cdev.name = pca963x[i].name; 3965029a2e3SAndrew Lunn pca963x[i].led_cdev.brightness_set_blocking = pca963x_led_set; 39756a1740cSRicardo Ribalda Delgado 39856a1740cSRicardo Ribalda Delgado if (pdata && pdata->blink_type == PCA963X_HW_BLINK) 39956a1740cSRicardo Ribalda Delgado pca963x[i].led_cdev.blink_set = pca963x_blink_set; 40056a1740cSRicardo Ribalda Delgado 40156a1740cSRicardo Ribalda Delgado err = led_classdev_register(&client->dev, &pca963x[i].led_cdev); 40256a1740cSRicardo Ribalda Delgado if (err < 0) 40356a1740cSRicardo Ribalda Delgado goto exit; 40456a1740cSRicardo Ribalda Delgado } 40556a1740cSRicardo Ribalda Delgado 40656a1740cSRicardo Ribalda Delgado /* Disable LED all-call address and set normal mode */ 40756a1740cSRicardo Ribalda Delgado i2c_smbus_write_byte_data(client, PCA963X_MODE1, 0x00); 40856a1740cSRicardo Ribalda Delgado 4090c62f42dSPeter Meerwald if (pdata) { 41056a1740cSRicardo Ribalda Delgado /* Configure output: open-drain or totem pole (push-pull) */ 4110c62f42dSPeter Meerwald if (pdata->outdrv == PCA963X_OPEN_DRAIN) 41256a1740cSRicardo Ribalda Delgado i2c_smbus_write_byte_data(client, PCA963X_MODE2, 0x01); 4130c62f42dSPeter Meerwald else 4140c62f42dSPeter Meerwald i2c_smbus_write_byte_data(client, PCA963X_MODE2, 0x05); 4150c62f42dSPeter Meerwald } 41656a1740cSRicardo Ribalda Delgado 41756a1740cSRicardo Ribalda Delgado return 0; 41856a1740cSRicardo Ribalda Delgado 41956a1740cSRicardo Ribalda Delgado exit: 4205029a2e3SAndrew Lunn while (i--) 42156a1740cSRicardo Ribalda Delgado led_classdev_unregister(&pca963x[i].led_cdev); 42256a1740cSRicardo Ribalda Delgado 42356a1740cSRicardo Ribalda Delgado return err; 42456a1740cSRicardo Ribalda Delgado } 42556a1740cSRicardo Ribalda Delgado 42656a1740cSRicardo Ribalda Delgado static int pca963x_remove(struct i2c_client *client) 42756a1740cSRicardo Ribalda Delgado { 42856a1740cSRicardo Ribalda Delgado struct pca963x *pca963x = i2c_get_clientdata(client); 42956a1740cSRicardo Ribalda Delgado int i; 43056a1740cSRicardo Ribalda Delgado 4315029a2e3SAndrew Lunn for (i = 0; i < pca963x->chipdef->n_leds; i++) 43256a1740cSRicardo Ribalda Delgado led_classdev_unregister(&pca963x->leds[i].led_cdev); 43356a1740cSRicardo Ribalda Delgado 43456a1740cSRicardo Ribalda Delgado return 0; 43556a1740cSRicardo Ribalda Delgado } 43656a1740cSRicardo Ribalda Delgado 43756a1740cSRicardo Ribalda Delgado static struct i2c_driver pca963x_driver = { 43856a1740cSRicardo Ribalda Delgado .driver = { 43956a1740cSRicardo Ribalda Delgado .name = "leds-pca963x", 44056a1740cSRicardo Ribalda Delgado .of_match_table = of_match_ptr(of_pca963x_match), 44156a1740cSRicardo Ribalda Delgado }, 44256a1740cSRicardo Ribalda Delgado .probe = pca963x_probe, 44356a1740cSRicardo Ribalda Delgado .remove = pca963x_remove, 44456a1740cSRicardo Ribalda Delgado .id_table = pca963x_id, 44556a1740cSRicardo Ribalda Delgado }; 44656a1740cSRicardo Ribalda Delgado 44756a1740cSRicardo Ribalda Delgado module_i2c_driver(pca963x_driver); 44856a1740cSRicardo Ribalda Delgado 44956a1740cSRicardo Ribalda Delgado MODULE_AUTHOR("Peter Meerwald <p.meerwald@bct-electronic.com>"); 45056a1740cSRicardo Ribalda Delgado MODULE_DESCRIPTION("PCA963X LED driver"); 45156a1740cSRicardo Ribalda Delgado MODULE_LICENSE("GPL v2"); 452