136edc939SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 256a1740cSRicardo Ribalda Delgado /* 356a1740cSRicardo Ribalda Delgado * Copyright 2011 bct electronic GmbH 456a1740cSRicardo Ribalda Delgado * Copyright 2013 Qtechnology/AS 556a1740cSRicardo Ribalda Delgado * 656a1740cSRicardo Ribalda Delgado * Author: Peter Meerwald <p.meerwald@bct-electronic.com> 7cea0fad0SRicardo Ribalda Delgado * Author: Ricardo Ribalda <ribalda@kernel.org> 856a1740cSRicardo Ribalda Delgado * 956a1740cSRicardo Ribalda Delgado * Based on leds-pca955x.c 1056a1740cSRicardo Ribalda Delgado * 1156a1740cSRicardo Ribalda Delgado * LED driver for the PCA9633 I2C LED driver (7-bit slave address 0x62) 123dfedb9dSPeter Meerwald * LED driver for the PCA9634/5 I2C LED driver (7-bit slave address set by hw.) 1356a1740cSRicardo Ribalda Delgado * 1456a1740cSRicardo Ribalda Delgado * Note that hardware blinking violates the leds infrastructure driver 1556a1740cSRicardo Ribalda Delgado * interface since the hardware only supports blinking all LEDs with the 1656a1740cSRicardo Ribalda Delgado * same delay_on/delay_off rates. That is, only the LEDs that are set to 1756a1740cSRicardo Ribalda Delgado * blink will actually blink but all LEDs that are set to blink will blink 1856a1740cSRicardo Ribalda Delgado * in identical fashion. The delay_on/delay_off values of the last LED 1956a1740cSRicardo Ribalda Delgado * that is set to blink will be used for all of the blinking LEDs. 2056a1740cSRicardo Ribalda Delgado * Hardware blinking is disabled by default but can be enabled by setting 2156a1740cSRicardo Ribalda Delgado * the 'blink_type' member in the platform_data struct to 'PCA963X_HW_BLINK' 2256a1740cSRicardo Ribalda Delgado * or by adding the 'nxp,hw-blink' property to the DTS. 2356a1740cSRicardo Ribalda Delgado */ 2456a1740cSRicardo Ribalda Delgado 2556a1740cSRicardo Ribalda Delgado #include <linux/module.h> 2656a1740cSRicardo Ribalda Delgado #include <linux/delay.h> 2756a1740cSRicardo Ribalda Delgado #include <linux/string.h> 2856a1740cSRicardo Ribalda Delgado #include <linux/ctype.h> 2956a1740cSRicardo Ribalda Delgado #include <linux/leds.h> 3056a1740cSRicardo Ribalda Delgado #include <linux/err.h> 3156a1740cSRicardo Ribalda Delgado #include <linux/i2c.h> 320b6034d8SAndy Shevchenko #include <linux/property.h> 3356a1740cSRicardo Ribalda Delgado #include <linux/slab.h> 3456a1740cSRicardo Ribalda Delgado #include <linux/of.h> 3556a1740cSRicardo Ribalda Delgado #include <linux/platform_data/leds-pca963x.h> 3656a1740cSRicardo Ribalda Delgado 3756a1740cSRicardo Ribalda Delgado /* LED select registers determine the source that drives LED outputs */ 3856a1740cSRicardo Ribalda Delgado #define PCA963X_LED_OFF 0x0 /* LED driver off */ 3956a1740cSRicardo Ribalda Delgado #define PCA963X_LED_ON 0x1 /* LED driver on */ 4056a1740cSRicardo Ribalda Delgado #define PCA963X_LED_PWM 0x2 /* Controlled through PWM */ 4156a1740cSRicardo Ribalda Delgado #define PCA963X_LED_GRP_PWM 0x3 /* Controlled through PWM/GRPPWM */ 4256a1740cSRicardo Ribalda Delgado 4369752909SZahari Petkov #define PCA963X_MODE2_OUTDRV 0x04 /* Open-drain or totem pole */ 4469752909SZahari Petkov #define PCA963X_MODE2_INVRT 0x10 /* Normal or inverted direction */ 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; 106a8c170b0SMatt Ranostay unsigned long leds_on; 10756a1740cSRicardo Ribalda Delgado }; 10856a1740cSRicardo Ribalda Delgado 10956a1740cSRicardo Ribalda Delgado struct pca963x_led { 11056a1740cSRicardo Ribalda Delgado struct pca963x *chip; 11156a1740cSRicardo Ribalda Delgado struct led_classdev led_cdev; 1123dfedb9dSPeter Meerwald int led_num; /* 0 .. 15 potentially */ 11356a1740cSRicardo Ribalda Delgado char name[32]; 11456a1740cSRicardo Ribalda Delgado u8 gdc; 11556a1740cSRicardo Ribalda Delgado u8 gfrq; 11656a1740cSRicardo Ribalda Delgado }; 11756a1740cSRicardo Ribalda Delgado 1185029a2e3SAndrew Lunn static int pca963x_brightness(struct pca963x_led *pca963x, 1195029a2e3SAndrew Lunn enum led_brightness brightness) 12056a1740cSRicardo Ribalda Delgado { 12156a1740cSRicardo Ribalda Delgado u8 ledout_addr = pca963x->chip->chipdef->ledout_base 12256a1740cSRicardo Ribalda Delgado + (pca963x->led_num / 4); 12356a1740cSRicardo Ribalda Delgado u8 ledout; 12456a1740cSRicardo Ribalda Delgado int shift = 2 * (pca963x->led_num % 4); 12556a1740cSRicardo Ribalda Delgado u8 mask = 0x3 << shift; 1265029a2e3SAndrew Lunn int ret; 12756a1740cSRicardo Ribalda Delgado 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) 144a8c170b0SMatt Ranostay return ret; 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 } 150a8c170b0SMatt Ranostay 1515029a2e3SAndrew Lunn return ret; 15256a1740cSRicardo Ribalda Delgado } 15356a1740cSRicardo Ribalda Delgado 1545029a2e3SAndrew Lunn static void pca963x_blink(struct pca963x_led *pca963x) 15556a1740cSRicardo Ribalda Delgado { 15656a1740cSRicardo Ribalda Delgado u8 ledout_addr = pca963x->chip->chipdef->ledout_base + 15756a1740cSRicardo Ribalda Delgado (pca963x->led_num / 4); 15856a1740cSRicardo Ribalda Delgado u8 ledout; 15956a1740cSRicardo Ribalda Delgado u8 mode2 = i2c_smbus_read_byte_data(pca963x->chip->client, 16056a1740cSRicardo Ribalda Delgado PCA963X_MODE2); 16156a1740cSRicardo Ribalda Delgado int shift = 2 * (pca963x->led_num % 4); 16256a1740cSRicardo Ribalda Delgado u8 mask = 0x3 << shift; 16356a1740cSRicardo Ribalda Delgado 16456a1740cSRicardo Ribalda Delgado i2c_smbus_write_byte_data(pca963x->chip->client, 16556a1740cSRicardo Ribalda Delgado pca963x->chip->chipdef->grppwm, pca963x->gdc); 16656a1740cSRicardo Ribalda Delgado 16756a1740cSRicardo Ribalda Delgado i2c_smbus_write_byte_data(pca963x->chip->client, 16856a1740cSRicardo Ribalda Delgado pca963x->chip->chipdef->grpfreq, pca963x->gfrq); 16956a1740cSRicardo Ribalda Delgado 17056a1740cSRicardo Ribalda Delgado if (!(mode2 & PCA963X_MODE2_DMBLNK)) 17156a1740cSRicardo Ribalda Delgado i2c_smbus_write_byte_data(pca963x->chip->client, PCA963X_MODE2, 17256a1740cSRicardo Ribalda Delgado mode2 | PCA963X_MODE2_DMBLNK); 17356a1740cSRicardo Ribalda Delgado 17456a1740cSRicardo Ribalda Delgado mutex_lock(&pca963x->chip->mutex); 17556a1740cSRicardo Ribalda Delgado ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr); 17656a1740cSRicardo Ribalda Delgado if ((ledout & mask) != (PCA963X_LED_GRP_PWM << shift)) 17756a1740cSRicardo Ribalda Delgado i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr, 17856a1740cSRicardo Ribalda Delgado (ledout & ~mask) | (PCA963X_LED_GRP_PWM << shift)); 17956a1740cSRicardo Ribalda Delgado mutex_unlock(&pca963x->chip->mutex); 18056a1740cSRicardo Ribalda Delgado } 18156a1740cSRicardo Ribalda Delgado 182a8c170b0SMatt Ranostay static int pca963x_power_state(struct pca963x_led *pca963x) 183a8c170b0SMatt Ranostay { 184a8c170b0SMatt Ranostay unsigned long *leds_on = &pca963x->chip->leds_on; 185a8c170b0SMatt Ranostay unsigned long cached_leds = pca963x->chip->leds_on; 186a8c170b0SMatt Ranostay 187a8c170b0SMatt Ranostay if (pca963x->led_cdev.brightness) 188a8c170b0SMatt Ranostay set_bit(pca963x->led_num, leds_on); 189a8c170b0SMatt Ranostay else 190a8c170b0SMatt Ranostay clear_bit(pca963x->led_num, leds_on); 191a8c170b0SMatt Ranostay 192a8c170b0SMatt Ranostay if (!(*leds_on) != !cached_leds) 193a8c170b0SMatt Ranostay return i2c_smbus_write_byte_data(pca963x->chip->client, 194a8c170b0SMatt Ranostay PCA963X_MODE1, *leds_on ? 0 : BIT(4)); 195a8c170b0SMatt Ranostay 196a8c170b0SMatt Ranostay return 0; 197a8c170b0SMatt Ranostay } 198a8c170b0SMatt Ranostay 1995029a2e3SAndrew Lunn static int pca963x_led_set(struct led_classdev *led_cdev, 20056a1740cSRicardo Ribalda Delgado enum led_brightness value) 20156a1740cSRicardo Ribalda Delgado { 20256a1740cSRicardo Ribalda Delgado struct pca963x_led *pca963x; 203a8c170b0SMatt Ranostay int ret; 20456a1740cSRicardo Ribalda Delgado 20556a1740cSRicardo Ribalda Delgado pca963x = container_of(led_cdev, struct pca963x_led, led_cdev); 20656a1740cSRicardo Ribalda Delgado 207a8c170b0SMatt Ranostay mutex_lock(&pca963x->chip->mutex); 208a8c170b0SMatt Ranostay 209a8c170b0SMatt Ranostay ret = pca963x_brightness(pca963x, value); 210a8c170b0SMatt Ranostay if (ret < 0) 211a8c170b0SMatt Ranostay goto unlock; 212a8c170b0SMatt Ranostay ret = pca963x_power_state(pca963x); 213a8c170b0SMatt Ranostay 214a8c170b0SMatt Ranostay unlock: 215a8c170b0SMatt Ranostay mutex_unlock(&pca963x->chip->mutex); 216a8c170b0SMatt Ranostay return ret; 21756a1740cSRicardo Ribalda Delgado } 21856a1740cSRicardo Ribalda Delgado 21935c7d301SMatt Ranostay static unsigned int pca963x_period_scale(struct pca963x_led *pca963x, 22035c7d301SMatt Ranostay unsigned int val) 22135c7d301SMatt Ranostay { 22235c7d301SMatt Ranostay unsigned int scaling = pca963x->chip->chipdef->scaling; 22335c7d301SMatt Ranostay 22435c7d301SMatt Ranostay return scaling ? DIV_ROUND_CLOSEST(val * scaling, 1000) : val; 22535c7d301SMatt Ranostay } 22635c7d301SMatt Ranostay 22756a1740cSRicardo Ribalda Delgado static int pca963x_blink_set(struct led_classdev *led_cdev, 22856a1740cSRicardo Ribalda Delgado unsigned long *delay_on, unsigned long *delay_off) 22956a1740cSRicardo Ribalda Delgado { 23056a1740cSRicardo Ribalda Delgado struct pca963x_led *pca963x; 23156a1740cSRicardo Ribalda Delgado unsigned long time_on, time_off, period; 23256a1740cSRicardo Ribalda Delgado u8 gdc, gfrq; 23356a1740cSRicardo Ribalda Delgado 23456a1740cSRicardo Ribalda Delgado pca963x = container_of(led_cdev, struct pca963x_led, led_cdev); 23556a1740cSRicardo Ribalda Delgado 23656a1740cSRicardo Ribalda Delgado time_on = *delay_on; 23756a1740cSRicardo Ribalda Delgado time_off = *delay_off; 23856a1740cSRicardo Ribalda Delgado 23956a1740cSRicardo Ribalda Delgado /* If both zero, pick reasonable defaults of 500ms each */ 24056a1740cSRicardo Ribalda Delgado if (!time_on && !time_off) { 24156a1740cSRicardo Ribalda Delgado time_on = 500; 24256a1740cSRicardo Ribalda Delgado time_off = 500; 24356a1740cSRicardo Ribalda Delgado } 24456a1740cSRicardo Ribalda Delgado 24535c7d301SMatt Ranostay period = pca963x_period_scale(pca963x, time_on + time_off); 24656a1740cSRicardo Ribalda Delgado 24756a1740cSRicardo Ribalda Delgado /* If period not supported by hardware, default to someting sane. */ 24856a1740cSRicardo Ribalda Delgado if ((period < PCA963X_BLINK_PERIOD_MIN) || 24956a1740cSRicardo Ribalda Delgado (period > PCA963X_BLINK_PERIOD_MAX)) { 25056a1740cSRicardo Ribalda Delgado time_on = 500; 25156a1740cSRicardo Ribalda Delgado time_off = 500; 25235c7d301SMatt Ranostay period = pca963x_period_scale(pca963x, 1000); 25356a1740cSRicardo Ribalda Delgado } 25456a1740cSRicardo Ribalda Delgado 25556a1740cSRicardo Ribalda Delgado /* 25656a1740cSRicardo Ribalda Delgado * From manual: duty cycle = (GDC / 256) -> 25756a1740cSRicardo Ribalda Delgado * (time_on / period) = (GDC / 256) -> 25856a1740cSRicardo Ribalda Delgado * GDC = ((time_on * 256) / period) 25956a1740cSRicardo Ribalda Delgado */ 26035c7d301SMatt Ranostay gdc = (pca963x_period_scale(pca963x, time_on) * 256) / period; 26156a1740cSRicardo Ribalda Delgado 26256a1740cSRicardo Ribalda Delgado /* 26356a1740cSRicardo Ribalda Delgado * From manual: period = ((GFRQ + 1) / 24) in seconds. 26456a1740cSRicardo Ribalda Delgado * So, period (in ms) = (((GFRQ + 1) / 24) * 1000) -> 26556a1740cSRicardo Ribalda Delgado * GFRQ = ((period * 24 / 1000) - 1) 26656a1740cSRicardo Ribalda Delgado */ 26756a1740cSRicardo Ribalda Delgado gfrq = (period * 24 / 1000) - 1; 26856a1740cSRicardo Ribalda Delgado 26956a1740cSRicardo Ribalda Delgado pca963x->gdc = gdc; 27056a1740cSRicardo Ribalda Delgado pca963x->gfrq = gfrq; 27156a1740cSRicardo Ribalda Delgado 2725029a2e3SAndrew Lunn pca963x_blink(pca963x); 27356a1740cSRicardo Ribalda Delgado 27456a1740cSRicardo Ribalda Delgado *delay_on = time_on; 27556a1740cSRicardo Ribalda Delgado *delay_off = time_off; 27656a1740cSRicardo Ribalda Delgado 27756a1740cSRicardo Ribalda Delgado return 0; 27856a1740cSRicardo Ribalda Delgado } 27956a1740cSRicardo Ribalda Delgado 28056a1740cSRicardo Ribalda Delgado static struct pca963x_platform_data * 2810b6034d8SAndy Shevchenko pca963x_get_pdata(struct i2c_client *client, struct pca963x_chipdef *chip) 28256a1740cSRicardo Ribalda Delgado { 28356a1740cSRicardo Ribalda Delgado struct pca963x_platform_data *pdata; 28456a1740cSRicardo Ribalda Delgado struct led_info *pca963x_leds; 2850b6034d8SAndy Shevchenko struct fwnode_handle *child; 28656a1740cSRicardo Ribalda Delgado int count; 28756a1740cSRicardo Ribalda Delgado 2880b6034d8SAndy Shevchenko count = device_get_child_node_count(&client->dev); 28956a1740cSRicardo Ribalda Delgado if (!count || count > chip->n_leds) 29056a1740cSRicardo Ribalda Delgado return ERR_PTR(-ENODEV); 29156a1740cSRicardo Ribalda Delgado 292a86854d0SKees Cook pca963x_leds = devm_kcalloc(&client->dev, 293a86854d0SKees Cook chip->n_leds, sizeof(struct led_info), GFP_KERNEL); 29456a1740cSRicardo Ribalda Delgado if (!pca963x_leds) 29556a1740cSRicardo Ribalda Delgado return ERR_PTR(-ENOMEM); 29656a1740cSRicardo Ribalda Delgado 2970b6034d8SAndy Shevchenko device_for_each_child_node(&client->dev, child) { 298a44b0f5eSGeert Uytterhoeven struct led_info led = {}; 29956a1740cSRicardo Ribalda Delgado u32 reg; 30056a1740cSRicardo Ribalda Delgado int res; 30156a1740cSRicardo Ribalda Delgado 3020b6034d8SAndy Shevchenko res = fwnode_property_read_u32(child, "reg", ®); 3038a6acd64SRicardo Ribalda Delgado if ((res != 0) || (reg >= chip->n_leds)) 3048a6acd64SRicardo Ribalda Delgado continue; 3050b6034d8SAndy Shevchenko 3060b6034d8SAndy Shevchenko res = fwnode_property_read_string(child, "label", &led.name); 3070b6034d8SAndy Shevchenko if ((res != 0) && is_of_node(child)) 3080b6034d8SAndy Shevchenko led.name = to_of_node(child)->name; 3090b6034d8SAndy Shevchenko 3100b6034d8SAndy Shevchenko fwnode_property_read_string(child, "linux,default-trigger", 3110b6034d8SAndy Shevchenko &led.default_trigger); 3120b6034d8SAndy Shevchenko 31356a1740cSRicardo Ribalda Delgado pca963x_leds[reg] = led; 31456a1740cSRicardo Ribalda Delgado } 31556a1740cSRicardo Ribalda Delgado pdata = devm_kzalloc(&client->dev, 31656a1740cSRicardo Ribalda Delgado sizeof(struct pca963x_platform_data), GFP_KERNEL); 31756a1740cSRicardo Ribalda Delgado if (!pdata) 31856a1740cSRicardo Ribalda Delgado return ERR_PTR(-ENOMEM); 31956a1740cSRicardo Ribalda Delgado 32056a1740cSRicardo Ribalda Delgado pdata->leds.leds = pca963x_leds; 3218a6acd64SRicardo Ribalda Delgado pdata->leds.num_leds = chip->n_leds; 32256a1740cSRicardo Ribalda Delgado 32356a1740cSRicardo Ribalda Delgado /* default to open-drain unless totem pole (push-pull) is specified */ 3240b6034d8SAndy Shevchenko if (device_property_read_bool(&client->dev, "nxp,totem-pole")) 32556a1740cSRicardo Ribalda Delgado pdata->outdrv = PCA963X_TOTEM_POLE; 32656a1740cSRicardo Ribalda Delgado else 32756a1740cSRicardo Ribalda Delgado pdata->outdrv = PCA963X_OPEN_DRAIN; 32856a1740cSRicardo Ribalda Delgado 32956a1740cSRicardo Ribalda Delgado /* default to software blinking unless hardware blinking is specified */ 3300b6034d8SAndy Shevchenko if (device_property_read_bool(&client->dev, "nxp,hw-blink")) 33156a1740cSRicardo Ribalda Delgado pdata->blink_type = PCA963X_HW_BLINK; 33256a1740cSRicardo Ribalda Delgado else 33356a1740cSRicardo Ribalda Delgado pdata->blink_type = PCA963X_SW_BLINK; 33456a1740cSRicardo Ribalda Delgado 3350b6034d8SAndy Shevchenko if (device_property_read_u32(&client->dev, "nxp,period-scale", 3360b6034d8SAndy Shevchenko &chip->scaling)) 33735c7d301SMatt Ranostay chip->scaling = 1000; 33835c7d301SMatt Ranostay 339bb29b9ccSAnders Darander /* default to non-inverted output, unless inverted is specified */ 3400b6034d8SAndy Shevchenko if (device_property_read_bool(&client->dev, "nxp,inverted-out")) 341bb29b9ccSAnders Darander pdata->dir = PCA963X_INVERTED; 342bb29b9ccSAnders Darander else 343bb29b9ccSAnders Darander pdata->dir = PCA963X_NORMAL; 344bb29b9ccSAnders Darander 34556a1740cSRicardo Ribalda Delgado return pdata; 34656a1740cSRicardo Ribalda Delgado } 34756a1740cSRicardo Ribalda Delgado 34856a1740cSRicardo Ribalda Delgado static const struct of_device_id of_pca963x_match[] = { 34956a1740cSRicardo Ribalda Delgado { .compatible = "nxp,pca9632", }, 35056a1740cSRicardo Ribalda Delgado { .compatible = "nxp,pca9633", }, 35156a1740cSRicardo Ribalda Delgado { .compatible = "nxp,pca9634", }, 3523dfedb9dSPeter Meerwald { .compatible = "nxp,pca9635", }, 35356a1740cSRicardo Ribalda Delgado {}, 35456a1740cSRicardo Ribalda Delgado }; 3554d59ed85SJavier Martinez Canillas MODULE_DEVICE_TABLE(of, of_pca963x_match); 35656a1740cSRicardo Ribalda Delgado 35756a1740cSRicardo Ribalda Delgado static int pca963x_probe(struct i2c_client *client, 35856a1740cSRicardo Ribalda Delgado const struct i2c_device_id *id) 35956a1740cSRicardo Ribalda Delgado { 36056a1740cSRicardo Ribalda Delgado struct pca963x *pca963x_chip; 36156a1740cSRicardo Ribalda Delgado struct pca963x_led *pca963x; 36256a1740cSRicardo Ribalda Delgado struct pca963x_platform_data *pdata; 36356a1740cSRicardo Ribalda Delgado struct pca963x_chipdef *chip; 36456a1740cSRicardo Ribalda Delgado int i, err; 36556a1740cSRicardo Ribalda Delgado 36656a1740cSRicardo Ribalda Delgado chip = &pca963x_chipdefs[id->driver_data]; 36756a1740cSRicardo Ribalda Delgado pdata = dev_get_platdata(&client->dev); 36856a1740cSRicardo Ribalda Delgado 36956a1740cSRicardo Ribalda Delgado if (!pdata) { 3700b6034d8SAndy Shevchenko pdata = pca963x_get_pdata(client, chip); 37156a1740cSRicardo Ribalda Delgado if (IS_ERR(pdata)) { 37256a1740cSRicardo Ribalda Delgado dev_warn(&client->dev, "could not parse configuration\n"); 37356a1740cSRicardo Ribalda Delgado pdata = NULL; 37456a1740cSRicardo Ribalda Delgado } 37556a1740cSRicardo Ribalda Delgado } 37656a1740cSRicardo Ribalda Delgado 37756a1740cSRicardo Ribalda Delgado if (pdata && (pdata->leds.num_leds < 1 || 37856a1740cSRicardo Ribalda Delgado pdata->leds.num_leds > chip->n_leds)) { 37956a1740cSRicardo Ribalda Delgado dev_err(&client->dev, "board info must claim 1-%d LEDs", 38056a1740cSRicardo Ribalda Delgado chip->n_leds); 38156a1740cSRicardo Ribalda Delgado return -EINVAL; 38256a1740cSRicardo Ribalda Delgado } 38356a1740cSRicardo Ribalda Delgado 38456a1740cSRicardo Ribalda Delgado pca963x_chip = devm_kzalloc(&client->dev, sizeof(*pca963x_chip), 38556a1740cSRicardo Ribalda Delgado GFP_KERNEL); 38656a1740cSRicardo Ribalda Delgado if (!pca963x_chip) 38756a1740cSRicardo Ribalda Delgado return -ENOMEM; 388a86854d0SKees Cook pca963x = devm_kcalloc(&client->dev, chip->n_leds, sizeof(*pca963x), 38956a1740cSRicardo Ribalda Delgado GFP_KERNEL); 39056a1740cSRicardo Ribalda Delgado if (!pca963x) 39156a1740cSRicardo Ribalda Delgado return -ENOMEM; 39256a1740cSRicardo Ribalda Delgado 39356a1740cSRicardo Ribalda Delgado i2c_set_clientdata(client, pca963x_chip); 39456a1740cSRicardo Ribalda Delgado 39556a1740cSRicardo Ribalda Delgado mutex_init(&pca963x_chip->mutex); 39656a1740cSRicardo Ribalda Delgado pca963x_chip->chipdef = chip; 39756a1740cSRicardo Ribalda Delgado pca963x_chip->client = client; 39856a1740cSRicardo Ribalda Delgado pca963x_chip->leds = pca963x; 39956a1740cSRicardo Ribalda Delgado 40056a1740cSRicardo Ribalda Delgado /* Turn off LEDs by default*/ 4013dfedb9dSPeter Meerwald for (i = 0; i < chip->n_leds / 4; i++) 4023dfedb9dSPeter Meerwald i2c_smbus_write_byte_data(client, chip->ledout_base + i, 0x00); 40356a1740cSRicardo Ribalda Delgado 40456a1740cSRicardo Ribalda Delgado for (i = 0; i < chip->n_leds; i++) { 40556a1740cSRicardo Ribalda Delgado pca963x[i].led_num = i; 40656a1740cSRicardo Ribalda Delgado pca963x[i].chip = pca963x_chip; 40756a1740cSRicardo Ribalda Delgado 40856a1740cSRicardo Ribalda Delgado /* Platform data can specify LED names and default triggers */ 40956a1740cSRicardo Ribalda Delgado if (pdata && i < pdata->leds.num_leds) { 41056a1740cSRicardo Ribalda Delgado if (pdata->leds.leds[i].name) 41156a1740cSRicardo Ribalda Delgado snprintf(pca963x[i].name, 41256a1740cSRicardo Ribalda Delgado sizeof(pca963x[i].name), "pca963x:%s", 41356a1740cSRicardo Ribalda Delgado pdata->leds.leds[i].name); 41456a1740cSRicardo Ribalda Delgado if (pdata->leds.leds[i].default_trigger) 41556a1740cSRicardo Ribalda Delgado pca963x[i].led_cdev.default_trigger = 41656a1740cSRicardo Ribalda Delgado pdata->leds.leds[i].default_trigger; 41756a1740cSRicardo Ribalda Delgado } 41856a1740cSRicardo Ribalda Delgado if (!pdata || i >= pdata->leds.num_leds || 41956a1740cSRicardo Ribalda Delgado !pdata->leds.leds[i].name) 42056a1740cSRicardo Ribalda Delgado snprintf(pca963x[i].name, sizeof(pca963x[i].name), 42156a1740cSRicardo Ribalda Delgado "pca963x:%d:%.2x:%d", client->adapter->nr, 42256a1740cSRicardo Ribalda Delgado client->addr, i); 42356a1740cSRicardo Ribalda Delgado 42456a1740cSRicardo Ribalda Delgado pca963x[i].led_cdev.name = pca963x[i].name; 4255029a2e3SAndrew Lunn pca963x[i].led_cdev.brightness_set_blocking = pca963x_led_set; 42656a1740cSRicardo Ribalda Delgado 42756a1740cSRicardo Ribalda Delgado if (pdata && pdata->blink_type == PCA963X_HW_BLINK) 42856a1740cSRicardo Ribalda Delgado pca963x[i].led_cdev.blink_set = pca963x_blink_set; 42956a1740cSRicardo Ribalda Delgado 43056a1740cSRicardo Ribalda Delgado err = led_classdev_register(&client->dev, &pca963x[i].led_cdev); 43156a1740cSRicardo Ribalda Delgado if (err < 0) 43256a1740cSRicardo Ribalda Delgado goto exit; 43356a1740cSRicardo Ribalda Delgado } 43456a1740cSRicardo Ribalda Delgado 435a8c170b0SMatt Ranostay /* Disable LED all-call address, and power down initially */ 436a8c170b0SMatt Ranostay i2c_smbus_write_byte_data(client, PCA963X_MODE1, BIT(4)); 43756a1740cSRicardo Ribalda Delgado 4380c62f42dSPeter Meerwald if (pdata) { 439bb29b9ccSAnders Darander u8 mode2 = i2c_smbus_read_byte_data(pca963x->chip->client, 440bb29b9ccSAnders Darander PCA963X_MODE2); 44156a1740cSRicardo Ribalda Delgado /* Configure output: open-drain or totem pole (push-pull) */ 4420c62f42dSPeter Meerwald if (pdata->outdrv == PCA963X_OPEN_DRAIN) 44369752909SZahari Petkov mode2 &= ~PCA963X_MODE2_OUTDRV; 4440c62f42dSPeter Meerwald else 44569752909SZahari Petkov mode2 |= PCA963X_MODE2_OUTDRV; 446bb29b9ccSAnders Darander /* Configure direction: normal or inverted */ 447bb29b9ccSAnders Darander if (pdata->dir == PCA963X_INVERTED) 44869752909SZahari Petkov mode2 |= PCA963X_MODE2_INVRT; 449bb29b9ccSAnders Darander i2c_smbus_write_byte_data(pca963x->chip->client, PCA963X_MODE2, 450bb29b9ccSAnders Darander mode2); 4510c62f42dSPeter Meerwald } 45256a1740cSRicardo Ribalda Delgado 45356a1740cSRicardo Ribalda Delgado return 0; 45456a1740cSRicardo Ribalda Delgado 45556a1740cSRicardo Ribalda Delgado exit: 4565029a2e3SAndrew Lunn while (i--) 45756a1740cSRicardo Ribalda Delgado led_classdev_unregister(&pca963x[i].led_cdev); 45856a1740cSRicardo Ribalda Delgado 45956a1740cSRicardo Ribalda Delgado return err; 46056a1740cSRicardo Ribalda Delgado } 46156a1740cSRicardo Ribalda Delgado 46256a1740cSRicardo Ribalda Delgado static int pca963x_remove(struct i2c_client *client) 46356a1740cSRicardo Ribalda Delgado { 46456a1740cSRicardo Ribalda Delgado struct pca963x *pca963x = i2c_get_clientdata(client); 46556a1740cSRicardo Ribalda Delgado int i; 46656a1740cSRicardo Ribalda Delgado 4675029a2e3SAndrew Lunn for (i = 0; i < pca963x->chipdef->n_leds; i++) 46856a1740cSRicardo Ribalda Delgado led_classdev_unregister(&pca963x->leds[i].led_cdev); 46956a1740cSRicardo Ribalda Delgado 47056a1740cSRicardo Ribalda Delgado return 0; 47156a1740cSRicardo Ribalda Delgado } 47256a1740cSRicardo Ribalda Delgado 47356a1740cSRicardo Ribalda Delgado static struct i2c_driver pca963x_driver = { 47456a1740cSRicardo Ribalda Delgado .driver = { 47556a1740cSRicardo Ribalda Delgado .name = "leds-pca963x", 4760b6034d8SAndy Shevchenko .of_match_table = of_pca963x_match, 47756a1740cSRicardo Ribalda Delgado }, 47856a1740cSRicardo Ribalda Delgado .probe = pca963x_probe, 47956a1740cSRicardo Ribalda Delgado .remove = pca963x_remove, 48056a1740cSRicardo Ribalda Delgado .id_table = pca963x_id, 48156a1740cSRicardo Ribalda Delgado }; 48256a1740cSRicardo Ribalda Delgado 48356a1740cSRicardo Ribalda Delgado module_i2c_driver(pca963x_driver); 48456a1740cSRicardo Ribalda Delgado 48556a1740cSRicardo Ribalda Delgado MODULE_AUTHOR("Peter Meerwald <p.meerwald@bct-electronic.com>"); 48656a1740cSRicardo Ribalda Delgado MODULE_DESCRIPTION("PCA963X LED driver"); 48756a1740cSRicardo Ribalda Delgado MODULE_LICENSE("GPL v2"); 488