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 1185db85093SMarek Behún static int pca963x_brightness(struct pca963x_led *led, 1195029a2e3SAndrew Lunn enum led_brightness brightness) 12056a1740cSRicardo Ribalda Delgado { 1215db85093SMarek Behún struct i2c_client *client = led->chip->client; 1225db85093SMarek Behún struct pca963x_chipdef *chipdef = led->chip->chipdef; 12339118499SMarek Behún u8 ledout_addr, ledout, mask, val; 12439118499SMarek Behún int shift; 1255029a2e3SAndrew Lunn int ret; 12656a1740cSRicardo Ribalda Delgado 1275db85093SMarek Behún ledout_addr = chipdef->ledout_base + (led->led_num / 4); 1285db85093SMarek Behún shift = 2 * (led->led_num % 4); 12939118499SMarek Behún mask = 0x3 << shift; 13039118499SMarek Behún ledout = i2c_smbus_read_byte_data(client, ledout_addr); 13139118499SMarek Behún 1325029a2e3SAndrew Lunn switch (brightness) { 13356a1740cSRicardo Ribalda Delgado case LED_FULL: 13439118499SMarek Behún val = (ledout & ~mask) | (PCA963X_LED_ON << shift); 13539118499SMarek Behún ret = i2c_smbus_write_byte_data(client, ledout_addr, val); 13656a1740cSRicardo Ribalda Delgado break; 13756a1740cSRicardo Ribalda Delgado case LED_OFF: 13839118499SMarek Behún val = ledout & ~mask; 13939118499SMarek Behún ret = i2c_smbus_write_byte_data(client, ledout_addr, val); 14056a1740cSRicardo Ribalda Delgado break; 14156a1740cSRicardo Ribalda Delgado default: 14239118499SMarek Behún ret = i2c_smbus_write_byte_data(client, 14339118499SMarek Behún PCA963X_PWM_BASE + 1445db85093SMarek Behún led->led_num, 1455029a2e3SAndrew Lunn brightness); 1465029a2e3SAndrew Lunn if (ret < 0) 147a8c170b0SMatt Ranostay return ret; 14839118499SMarek Behún 14939118499SMarek Behún val = (ledout & ~mask) | (PCA963X_LED_PWM << shift); 15039118499SMarek Behún ret = i2c_smbus_write_byte_data(client, ledout_addr, val); 15156a1740cSRicardo Ribalda Delgado break; 15256a1740cSRicardo Ribalda Delgado } 153a8c170b0SMatt Ranostay 1545029a2e3SAndrew Lunn return ret; 15556a1740cSRicardo Ribalda Delgado } 15656a1740cSRicardo Ribalda Delgado 1575db85093SMarek Behún static void pca963x_blink(struct pca963x_led *led) 15856a1740cSRicardo Ribalda Delgado { 1595db85093SMarek Behún struct i2c_client *client = led->chip->client; 1605db85093SMarek Behún struct pca963x_chipdef *chipdef = led->chip->chipdef; 16139118499SMarek Behún u8 ledout_addr, ledout, mask, val, mode2; 16239118499SMarek Behún int shift; 16356a1740cSRicardo Ribalda Delgado 1645db85093SMarek Behún ledout_addr = chipdef->ledout_base + (led->led_num / 4); 1655db85093SMarek Behún shift = 2 * (led->led_num % 4); 16639118499SMarek Behún mask = 0x3 << shift; 16739118499SMarek Behún mode2 = i2c_smbus_read_byte_data(client, PCA963X_MODE2); 16856a1740cSRicardo Ribalda Delgado 1695db85093SMarek Behún i2c_smbus_write_byte_data(client, chipdef->grppwm, led->gdc); 17039118499SMarek Behún 1715db85093SMarek Behún i2c_smbus_write_byte_data(client, chipdef->grpfreq, led->gfrq); 17256a1740cSRicardo Ribalda Delgado 17356a1740cSRicardo Ribalda Delgado if (!(mode2 & PCA963X_MODE2_DMBLNK)) 17439118499SMarek Behún i2c_smbus_write_byte_data(client, PCA963X_MODE2, 17556a1740cSRicardo Ribalda Delgado mode2 | PCA963X_MODE2_DMBLNK); 17656a1740cSRicardo Ribalda Delgado 1775db85093SMarek Behún mutex_lock(&led->chip->mutex); 17839118499SMarek Behún 17939118499SMarek Behún ledout = i2c_smbus_read_byte_data(client, ledout_addr); 18039118499SMarek Behún if ((ledout & mask) != (PCA963X_LED_GRP_PWM << shift)) { 18139118499SMarek Behún val = (ledout & ~mask) | (PCA963X_LED_GRP_PWM << shift); 18239118499SMarek Behún i2c_smbus_write_byte_data(client, ledout_addr, val); 18339118499SMarek Behún } 18439118499SMarek Behún 1855db85093SMarek Behún mutex_unlock(&led->chip->mutex); 18656a1740cSRicardo Ribalda Delgado } 18756a1740cSRicardo Ribalda Delgado 1885db85093SMarek Behún static int pca963x_power_state(struct pca963x_led *led) 189a8c170b0SMatt Ranostay { 1905db85093SMarek Behún struct i2c_client *client = led->chip->client; 1915db85093SMarek Behún unsigned long *leds_on = &led->chip->leds_on; 19239118499SMarek Behún unsigned long cached_leds = *leds_on; 193a8c170b0SMatt Ranostay 1945db85093SMarek Behún if (led->led_cdev.brightness) 1955db85093SMarek Behún set_bit(led->led_num, leds_on); 196a8c170b0SMatt Ranostay else 1975db85093SMarek Behún clear_bit(led->led_num, leds_on); 198a8c170b0SMatt Ranostay 199a8c170b0SMatt Ranostay if (!(*leds_on) != !cached_leds) 20039118499SMarek Behún return i2c_smbus_write_byte_data(client, PCA963X_MODE1, 20139118499SMarek Behún *leds_on ? 0 : BIT(4)); 202a8c170b0SMatt Ranostay 203a8c170b0SMatt Ranostay return 0; 204a8c170b0SMatt Ranostay } 205a8c170b0SMatt Ranostay 2065029a2e3SAndrew Lunn static int pca963x_led_set(struct led_classdev *led_cdev, 20756a1740cSRicardo Ribalda Delgado enum led_brightness value) 20856a1740cSRicardo Ribalda Delgado { 2095db85093SMarek Behún struct pca963x_led *led; 210a8c170b0SMatt Ranostay int ret; 21156a1740cSRicardo Ribalda Delgado 2125db85093SMarek Behún led = container_of(led_cdev, struct pca963x_led, led_cdev); 21356a1740cSRicardo Ribalda Delgado 2145db85093SMarek Behún mutex_lock(&led->chip->mutex); 215a8c170b0SMatt Ranostay 2165db85093SMarek Behún ret = pca963x_brightness(led, value); 217a8c170b0SMatt Ranostay if (ret < 0) 218a8c170b0SMatt Ranostay goto unlock; 2195db85093SMarek Behún ret = pca963x_power_state(led); 220a8c170b0SMatt Ranostay 221a8c170b0SMatt Ranostay unlock: 2225db85093SMarek Behún mutex_unlock(&led->chip->mutex); 223a8c170b0SMatt Ranostay return ret; 22456a1740cSRicardo Ribalda Delgado } 22556a1740cSRicardo Ribalda Delgado 2265db85093SMarek Behún static unsigned int pca963x_period_scale(struct pca963x_led *led, 22735c7d301SMatt Ranostay unsigned int val) 22835c7d301SMatt Ranostay { 2295db85093SMarek Behún unsigned int scaling = led->chip->chipdef->scaling; 23035c7d301SMatt Ranostay 23135c7d301SMatt Ranostay return scaling ? DIV_ROUND_CLOSEST(val * scaling, 1000) : val; 23235c7d301SMatt Ranostay } 23335c7d301SMatt Ranostay 23456a1740cSRicardo Ribalda Delgado static int pca963x_blink_set(struct led_classdev *led_cdev, 23556a1740cSRicardo Ribalda Delgado unsigned long *delay_on, unsigned long *delay_off) 23656a1740cSRicardo Ribalda Delgado { 23756a1740cSRicardo Ribalda Delgado unsigned long time_on, time_off, period; 2385db85093SMarek Behún struct pca963x_led *led; 23956a1740cSRicardo Ribalda Delgado u8 gdc, gfrq; 24056a1740cSRicardo Ribalda Delgado 2415db85093SMarek Behún led = container_of(led_cdev, struct pca963x_led, led_cdev); 24256a1740cSRicardo Ribalda Delgado 24356a1740cSRicardo Ribalda Delgado time_on = *delay_on; 24456a1740cSRicardo Ribalda Delgado time_off = *delay_off; 24556a1740cSRicardo Ribalda Delgado 24656a1740cSRicardo Ribalda Delgado /* If both zero, pick reasonable defaults of 500ms each */ 24756a1740cSRicardo Ribalda Delgado if (!time_on && !time_off) { 24856a1740cSRicardo Ribalda Delgado time_on = 500; 24956a1740cSRicardo Ribalda Delgado time_off = 500; 25056a1740cSRicardo Ribalda Delgado } 25156a1740cSRicardo Ribalda Delgado 2525db85093SMarek Behún period = pca963x_period_scale(led, time_on + time_off); 25356a1740cSRicardo Ribalda Delgado 25456a1740cSRicardo Ribalda Delgado /* If period not supported by hardware, default to someting sane. */ 25556a1740cSRicardo Ribalda Delgado if ((period < PCA963X_BLINK_PERIOD_MIN) || 25656a1740cSRicardo Ribalda Delgado (period > PCA963X_BLINK_PERIOD_MAX)) { 25756a1740cSRicardo Ribalda Delgado time_on = 500; 25856a1740cSRicardo Ribalda Delgado time_off = 500; 2595db85093SMarek Behún period = pca963x_period_scale(led, 1000); 26056a1740cSRicardo Ribalda Delgado } 26156a1740cSRicardo Ribalda Delgado 26256a1740cSRicardo Ribalda Delgado /* 26356a1740cSRicardo Ribalda Delgado * From manual: duty cycle = (GDC / 256) -> 26456a1740cSRicardo Ribalda Delgado * (time_on / period) = (GDC / 256) -> 26556a1740cSRicardo Ribalda Delgado * GDC = ((time_on * 256) / period) 26656a1740cSRicardo Ribalda Delgado */ 2675db85093SMarek Behún gdc = (pca963x_period_scale(led, time_on) * 256) / period; 26856a1740cSRicardo Ribalda Delgado 26956a1740cSRicardo Ribalda Delgado /* 27056a1740cSRicardo Ribalda Delgado * From manual: period = ((GFRQ + 1) / 24) in seconds. 27156a1740cSRicardo Ribalda Delgado * So, period (in ms) = (((GFRQ + 1) / 24) * 1000) -> 27256a1740cSRicardo Ribalda Delgado * GFRQ = ((period * 24 / 1000) - 1) 27356a1740cSRicardo Ribalda Delgado */ 27456a1740cSRicardo Ribalda Delgado gfrq = (period * 24 / 1000) - 1; 27556a1740cSRicardo Ribalda Delgado 2765db85093SMarek Behún led->gdc = gdc; 2775db85093SMarek Behún led->gfrq = gfrq; 27856a1740cSRicardo Ribalda Delgado 2795db85093SMarek Behún pca963x_blink(led); 28056a1740cSRicardo Ribalda Delgado 28156a1740cSRicardo Ribalda Delgado *delay_on = time_on; 28256a1740cSRicardo Ribalda Delgado *delay_off = time_off; 28356a1740cSRicardo Ribalda Delgado 28456a1740cSRicardo Ribalda Delgado return 0; 28556a1740cSRicardo Ribalda Delgado } 28656a1740cSRicardo Ribalda Delgado 28756a1740cSRicardo Ribalda Delgado static struct pca963x_platform_data * 288fc0b1ecaSMarek Behún pca963x_get_pdata(struct device *dev, struct pca963x_chipdef *chipdef) 28956a1740cSRicardo Ribalda Delgado { 29056a1740cSRicardo Ribalda Delgado struct pca963x_platform_data *pdata; 29156a1740cSRicardo Ribalda Delgado struct led_info *pca963x_leds; 2920b6034d8SAndy Shevchenko struct fwnode_handle *child; 29356a1740cSRicardo Ribalda Delgado int count; 29456a1740cSRicardo Ribalda Delgado 29539118499SMarek Behún count = device_get_child_node_count(dev); 296fc0b1ecaSMarek Behún if (!count || count > chipdef->n_leds) 29756a1740cSRicardo Ribalda Delgado return ERR_PTR(-ENODEV); 29856a1740cSRicardo Ribalda Delgado 299fc0b1ecaSMarek Behún pca963x_leds = devm_kcalloc(dev, chipdef->n_leds, 300fc0b1ecaSMarek Behún sizeof(struct led_info), GFP_KERNEL); 30156a1740cSRicardo Ribalda Delgado if (!pca963x_leds) 30256a1740cSRicardo Ribalda Delgado return ERR_PTR(-ENOMEM); 30356a1740cSRicardo Ribalda Delgado 30439118499SMarek Behún device_for_each_child_node(dev, child) { 305a44b0f5eSGeert Uytterhoeven struct led_info led = {}; 30656a1740cSRicardo Ribalda Delgado u32 reg; 30756a1740cSRicardo Ribalda Delgado int res; 30856a1740cSRicardo Ribalda Delgado 3090b6034d8SAndy Shevchenko res = fwnode_property_read_u32(child, "reg", ®); 310fc0b1ecaSMarek Behún if ((res != 0) || (reg >= chipdef->n_leds)) 3118a6acd64SRicardo Ribalda Delgado continue; 3120b6034d8SAndy Shevchenko 3130b6034d8SAndy Shevchenko res = fwnode_property_read_string(child, "label", &led.name); 3140b6034d8SAndy Shevchenko if ((res != 0) && is_of_node(child)) 3150b6034d8SAndy Shevchenko led.name = to_of_node(child)->name; 3160b6034d8SAndy Shevchenko 3170b6034d8SAndy Shevchenko fwnode_property_read_string(child, "linux,default-trigger", 3180b6034d8SAndy Shevchenko &led.default_trigger); 3190b6034d8SAndy Shevchenko 32056a1740cSRicardo Ribalda Delgado pca963x_leds[reg] = led; 32156a1740cSRicardo Ribalda Delgado } 32239118499SMarek Behún pdata = devm_kzalloc(dev, sizeof(struct pca963x_platform_data), 32339118499SMarek Behún GFP_KERNEL); 32456a1740cSRicardo Ribalda Delgado if (!pdata) 32556a1740cSRicardo Ribalda Delgado return ERR_PTR(-ENOMEM); 32656a1740cSRicardo Ribalda Delgado 32756a1740cSRicardo Ribalda Delgado pdata->leds.leds = pca963x_leds; 328fc0b1ecaSMarek Behún pdata->leds.num_leds = chipdef->n_leds; 32956a1740cSRicardo Ribalda Delgado 33056a1740cSRicardo Ribalda Delgado /* default to open-drain unless totem pole (push-pull) is specified */ 33139118499SMarek Behún if (device_property_read_bool(dev, "nxp,totem-pole")) 33256a1740cSRicardo Ribalda Delgado pdata->outdrv = PCA963X_TOTEM_POLE; 33356a1740cSRicardo Ribalda Delgado else 33456a1740cSRicardo Ribalda Delgado pdata->outdrv = PCA963X_OPEN_DRAIN; 33556a1740cSRicardo Ribalda Delgado 33656a1740cSRicardo Ribalda Delgado /* default to software blinking unless hardware blinking is specified */ 33739118499SMarek Behún if (device_property_read_bool(dev, "nxp,hw-blink")) 33856a1740cSRicardo Ribalda Delgado pdata->blink_type = PCA963X_HW_BLINK; 33956a1740cSRicardo Ribalda Delgado else 34056a1740cSRicardo Ribalda Delgado pdata->blink_type = PCA963X_SW_BLINK; 34156a1740cSRicardo Ribalda Delgado 34239118499SMarek Behún if (device_property_read_u32(dev, "nxp,period-scale", 343fc0b1ecaSMarek Behún &chipdef->scaling)) 344fc0b1ecaSMarek Behún chipdef->scaling = 1000; 34535c7d301SMatt Ranostay 346bb29b9ccSAnders Darander /* default to non-inverted output, unless inverted is specified */ 34739118499SMarek Behún if (device_property_read_bool(dev, "nxp,inverted-out")) 348bb29b9ccSAnders Darander pdata->dir = PCA963X_INVERTED; 349bb29b9ccSAnders Darander else 350bb29b9ccSAnders Darander pdata->dir = PCA963X_NORMAL; 351bb29b9ccSAnders Darander 35256a1740cSRicardo Ribalda Delgado return pdata; 35356a1740cSRicardo Ribalda Delgado } 35456a1740cSRicardo Ribalda Delgado 35556a1740cSRicardo Ribalda Delgado static const struct of_device_id of_pca963x_match[] = { 35656a1740cSRicardo Ribalda Delgado { .compatible = "nxp,pca9632", }, 35756a1740cSRicardo Ribalda Delgado { .compatible = "nxp,pca9633", }, 35856a1740cSRicardo Ribalda Delgado { .compatible = "nxp,pca9634", }, 3593dfedb9dSPeter Meerwald { .compatible = "nxp,pca9635", }, 36056a1740cSRicardo Ribalda Delgado {}, 36156a1740cSRicardo Ribalda Delgado }; 3624d59ed85SJavier Martinez Canillas MODULE_DEVICE_TABLE(of, of_pca963x_match); 36356a1740cSRicardo Ribalda Delgado 36456a1740cSRicardo Ribalda Delgado static int pca963x_probe(struct i2c_client *client, 36556a1740cSRicardo Ribalda Delgado const struct i2c_device_id *id) 36656a1740cSRicardo Ribalda Delgado { 36739118499SMarek Behún struct device *dev = &client->dev; 368fc0b1ecaSMarek Behún struct pca963x_chipdef *chipdef; 36956a1740cSRicardo Ribalda Delgado struct pca963x_platform_data *pdata; 3705db85093SMarek Behún struct pca963x_led *leds; 371fc0b1ecaSMarek Behún struct pca963x *chip; 37256a1740cSRicardo Ribalda Delgado int i, err; 37356a1740cSRicardo Ribalda Delgado 374fc0b1ecaSMarek Behún chipdef = &pca963x_chipdefs[id->driver_data]; 37539118499SMarek Behún pdata = dev_get_platdata(dev); 37656a1740cSRicardo Ribalda Delgado 37756a1740cSRicardo Ribalda Delgado if (!pdata) { 378fc0b1ecaSMarek Behún pdata = pca963x_get_pdata(dev, chipdef); 37956a1740cSRicardo Ribalda Delgado if (IS_ERR(pdata)) { 38039118499SMarek Behún dev_warn(dev, "could not parse configuration\n"); 38156a1740cSRicardo Ribalda Delgado pdata = NULL; 38256a1740cSRicardo Ribalda Delgado } 38356a1740cSRicardo Ribalda Delgado } 38456a1740cSRicardo Ribalda Delgado 38556a1740cSRicardo Ribalda Delgado if (pdata && (pdata->leds.num_leds < 1 || 386fc0b1ecaSMarek Behún pdata->leds.num_leds > chipdef->n_leds)) { 387fc0b1ecaSMarek Behún dev_err(dev, "board info must claim 1-%d LEDs", 388fc0b1ecaSMarek Behún chipdef->n_leds); 38956a1740cSRicardo Ribalda Delgado return -EINVAL; 39056a1740cSRicardo Ribalda Delgado } 39156a1740cSRicardo Ribalda Delgado 392fc0b1ecaSMarek Behún chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 393fc0b1ecaSMarek Behún if (!chip) 39456a1740cSRicardo Ribalda Delgado return -ENOMEM; 3955db85093SMarek Behún leds = devm_kcalloc(dev, chipdef->n_leds, sizeof(*leds), GFP_KERNEL); 3965db85093SMarek Behún if (!leds) 39756a1740cSRicardo Ribalda Delgado return -ENOMEM; 39856a1740cSRicardo Ribalda Delgado 399fc0b1ecaSMarek Behún i2c_set_clientdata(client, chip); 40056a1740cSRicardo Ribalda Delgado 401fc0b1ecaSMarek Behún mutex_init(&chip->mutex); 402fc0b1ecaSMarek Behún chip->chipdef = chipdef; 403fc0b1ecaSMarek Behún chip->client = client; 4045db85093SMarek Behún chip->leds = leds; 40556a1740cSRicardo Ribalda Delgado 40656a1740cSRicardo Ribalda Delgado /* Turn off LEDs by default*/ 407fc0b1ecaSMarek Behún for (i = 0; i < chipdef->n_leds / 4; i++) 408fc0b1ecaSMarek Behún i2c_smbus_write_byte_data(client, chipdef->ledout_base + i, 0x00); 40956a1740cSRicardo Ribalda Delgado 410fc0b1ecaSMarek Behún for (i = 0; i < chipdef->n_leds; i++) { 4115db85093SMarek Behún struct pca963x_led *led = &leds[i]; 4125db85093SMarek Behún 4135db85093SMarek Behún led->led_num = i; 4145db85093SMarek Behún led->chip = chip; 41556a1740cSRicardo Ribalda Delgado 41656a1740cSRicardo Ribalda Delgado /* Platform data can specify LED names and default triggers */ 41756a1740cSRicardo Ribalda Delgado if (pdata && i < pdata->leds.num_leds) { 41856a1740cSRicardo Ribalda Delgado if (pdata->leds.leds[i].name) 4195db85093SMarek Behún snprintf(led->name, 4205db85093SMarek Behún sizeof(led->name), "pca963x:%s", 42156a1740cSRicardo Ribalda Delgado pdata->leds.leds[i].name); 42256a1740cSRicardo Ribalda Delgado if (pdata->leds.leds[i].default_trigger) 4235db85093SMarek Behún led->led_cdev.default_trigger = 42456a1740cSRicardo Ribalda Delgado pdata->leds.leds[i].default_trigger; 42556a1740cSRicardo Ribalda Delgado } 42656a1740cSRicardo Ribalda Delgado if (!pdata || i >= pdata->leds.num_leds || 42756a1740cSRicardo Ribalda Delgado !pdata->leds.leds[i].name) 4285db85093SMarek Behún snprintf(led->name, sizeof(led->name), 42956a1740cSRicardo Ribalda Delgado "pca963x:%d:%.2x:%d", client->adapter->nr, 43056a1740cSRicardo Ribalda Delgado client->addr, i); 43156a1740cSRicardo Ribalda Delgado 4325db85093SMarek Behún led->led_cdev.name = led->name; 4335db85093SMarek Behún led->led_cdev.brightness_set_blocking = pca963x_led_set; 43456a1740cSRicardo Ribalda Delgado 43556a1740cSRicardo Ribalda Delgado if (pdata && pdata->blink_type == PCA963X_HW_BLINK) 4365db85093SMarek Behún led->led_cdev.blink_set = pca963x_blink_set; 43756a1740cSRicardo Ribalda Delgado 4385db85093SMarek Behún err = devm_led_classdev_register(dev, &led->led_cdev); 43956a1740cSRicardo Ribalda Delgado if (err < 0) 440af26bebeSMarek Behún return err; 44156a1740cSRicardo Ribalda Delgado } 44256a1740cSRicardo Ribalda Delgado 443a8c170b0SMatt Ranostay /* Disable LED all-call address, and power down initially */ 444a8c170b0SMatt Ranostay i2c_smbus_write_byte_data(client, PCA963X_MODE1, BIT(4)); 44556a1740cSRicardo Ribalda Delgado 4460c62f42dSPeter Meerwald if (pdata) { 44739118499SMarek Behún u8 mode2 = i2c_smbus_read_byte_data(client, PCA963X_MODE2); 44856a1740cSRicardo Ribalda Delgado /* Configure output: open-drain or totem pole (push-pull) */ 4490c62f42dSPeter Meerwald if (pdata->outdrv == PCA963X_OPEN_DRAIN) 45069752909SZahari Petkov mode2 &= ~PCA963X_MODE2_OUTDRV; 4510c62f42dSPeter Meerwald else 45269752909SZahari Petkov mode2 |= PCA963X_MODE2_OUTDRV; 453bb29b9ccSAnders Darander /* Configure direction: normal or inverted */ 454bb29b9ccSAnders Darander if (pdata->dir == PCA963X_INVERTED) 45569752909SZahari Petkov mode2 |= PCA963X_MODE2_INVRT; 45639118499SMarek Behún i2c_smbus_write_byte_data(client, PCA963X_MODE2, mode2); 4570c62f42dSPeter Meerwald } 45856a1740cSRicardo Ribalda Delgado 45956a1740cSRicardo Ribalda Delgado return 0; 46056a1740cSRicardo Ribalda Delgado } 46156a1740cSRicardo Ribalda Delgado 46256a1740cSRicardo Ribalda Delgado static struct i2c_driver pca963x_driver = { 46356a1740cSRicardo Ribalda Delgado .driver = { 46456a1740cSRicardo Ribalda Delgado .name = "leds-pca963x", 4650b6034d8SAndy Shevchenko .of_match_table = of_pca963x_match, 46656a1740cSRicardo Ribalda Delgado }, 46756a1740cSRicardo Ribalda Delgado .probe = pca963x_probe, 46856a1740cSRicardo Ribalda Delgado .id_table = pca963x_id, 46956a1740cSRicardo Ribalda Delgado }; 47056a1740cSRicardo Ribalda Delgado 47156a1740cSRicardo Ribalda Delgado module_i2c_driver(pca963x_driver); 47256a1740cSRicardo Ribalda Delgado 47356a1740cSRicardo Ribalda Delgado MODULE_AUTHOR("Peter Meerwald <p.meerwald@bct-electronic.com>"); 47456a1740cSRicardo Ribalda Delgado MODULE_DESCRIPTION("PCA963X LED driver"); 47556a1740cSRicardo Ribalda Delgado MODULE_LICENSE("GPL v2"); 476