brintos

brintos / linux-shallow public Read only

0
0
Text · 20.2 KiB · 7b04ea1 Raw
875 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Intel Lightning Mountain SoC LED Serial Shift Output Controller driver4 *5 * Copyright (c) 2020 Intel Corporation.6 */7 8#include <linux/bitfield.h>9#include <linux/clk.h>10#include <linux/gpio/consumer.h>11#include <linux/gpio/driver.h>12#include <linux/init.h>13#include <linux/kernel.h>14#include <linux/leds.h>15#include <linux/mfd/syscon.h>16#include <linux/module.h>17#include <linux/platform_device.h>18#include <linux/property.h>19#include <linux/regmap.h>20#include <linux/sizes.h>21#include <linux/uaccess.h>22 23#define SSO_DEV_NAME			"lgm-sso"24 25#define LED_BLINK_H8_0			0x026#define LED_BLINK_H8_1			0x427#define GET_FREQ_OFFSET(pin, src)	(((pin) * 6) + ((src) * 2))28#define GET_SRC_OFFSET(pinc)		(((pin) * 6) + 4)29 30#define DUTY_CYCLE(x)			(0x8 + ((x) * 4))31#define SSO_CON0			0x2B032#define SSO_CON0_RZFL			BIT(26)33#define SSO_CON0_BLINK_R		BIT(30)34#define SSO_CON0_SWU			BIT(31)35 36#define SSO_CON1			0x2B437#define SSO_CON1_FCDSC			GENMASK(21, 20) /* Fixed Divider Shift Clock */38#define SSO_CON1_FPID			GENMASK(24, 23)39#define SSO_CON1_GPTD			GENMASK(26, 25)40#define SSO_CON1_US			GENMASK(31, 30)41 42#define SSO_CPU				0x2B843#define SSO_CON2			0x2C444#define SSO_CON3			0x2C845 46/* Driver MACRO */47#define MAX_PIN_NUM_PER_BANK		SZ_3248#define MAX_GROUP_NUM			SZ_449#define PINS_PER_GROUP			SZ_850#define FPID_FREQ_RANK_MAX		SZ_451#define SSO_LED_MAX_NUM			SZ_3252#define MAX_FREQ_RANK			1053#define DEF_GPTC_CLK_RATE		20000000054#define SSO_DEF_BRIGHTNESS		LED_HALF55#define DATA_CLK_EDGE			0 /* 0-rising, 1-falling */56 57static const u32 freq_div_tbl[] = {4000, 2000, 1000, 800};58static const int freq_tbl[] = {2, 4, 8, 10, 50000, 100000, 200000, 250000};59static const int shift_clk_freq_tbl[] = {25000000, 12500000, 6250000, 3125000};60 61/*62 * Update Source to update the SOUTs63 * SW - Software has to update the SWU bit64 * GPTC - General Purpose timer is used as clock source65 * FPID - Divided FSC clock (FPID) is used as clock source66 */67enum {68	US_SW = 0,69	US_GPTC = 1,70	US_FPID = 271};72 73enum {74	MAX_FPID_FREQ_RANK = 5, /* 1 to 4 */75	MAX_GPTC_FREQ_RANK = 9, /* 5 to 8 */76	MAX_GPTC_HS_FREQ_RANK = 10, /* 9 to 10 */77};78 79enum {80	LED_GRP0_PIN_MAX = 24,81	LED_GRP1_PIN_MAX = 29,82	LED_GRP2_PIN_MAX = 32,83};84 85enum {86	LED_GRP0_0_23,87	LED_GRP1_24_28,88	LED_GRP2_29_31,89	LED_GROUP_MAX,90};91 92enum {93	CLK_SRC_FPID = 0,94	CLK_SRC_GPTC = 1,95	CLK_SRC_GPTC_HS = 2,96};97 98struct sso_led_priv;99 100struct sso_led_desc {101	const char *name;102	const char *default_trigger;103	unsigned int brightness;104	unsigned int blink_rate;105	unsigned int retain_state_suspended:1;106	unsigned int retain_state_shutdown:1;107	unsigned int panic_indicator:1;108	unsigned int hw_blink:1;109	unsigned int hw_trig:1;110	unsigned int blinking:1;111	int freq_idx;112	u32 pin;113};114 115struct sso_led {116	struct list_head list;117	struct led_classdev cdev;118	struct gpio_desc *gpiod;119	struct sso_led_desc desc;120	struct sso_led_priv *priv;121};122 123struct sso_gpio {124	struct gpio_chip chip;125	int shift_clk_freq;126	int edge;127	int freq;128	u32 pins;129	u32 alloc_bitmap;130};131 132struct sso_led_priv {133	struct regmap *mmap;134	struct device *dev;135	struct platform_device *pdev;136	struct clk_bulk_data clocks[2];137	u32 fpid_clkrate;138	u32 gptc_clkrate;139	u32 freq[MAX_FREQ_RANK];140	struct list_head led_list;141	struct sso_gpio gpio;142};143 144static int sso_get_blink_rate_idx(struct sso_led_priv *priv, u32 rate)145{146	int i;147 148	for (i = 0; i < MAX_FREQ_RANK; i++) {149		if (rate <= priv->freq[i])150			return i;151	}152 153	return -1;154}155 156static unsigned int sso_led_pin_to_group(u32 pin)157{158	if (pin < LED_GRP0_PIN_MAX)159		return LED_GRP0_0_23;160	else if (pin < LED_GRP1_PIN_MAX)161		return LED_GRP1_24_28;162	else163		return LED_GRP2_29_31;164}165 166static u32 sso_led_get_freq_src(int freq_idx)167{168	if (freq_idx < MAX_FPID_FREQ_RANK)169		return CLK_SRC_FPID;170	else if (freq_idx < MAX_GPTC_FREQ_RANK)171		return CLK_SRC_GPTC;172	else173		return CLK_SRC_GPTC_HS;174}175 176static u32 sso_led_pin_blink_off(u32 pin, unsigned int group)177{178	if (group == LED_GRP2_29_31)179		return pin - LED_GRP1_PIN_MAX;180	else if (group == LED_GRP1_24_28)181		return pin - LED_GRP0_PIN_MAX;182	else	/* led 0 - 23 in led 32 location */183		return SSO_LED_MAX_NUM - LED_GRP1_PIN_MAX;184}185 186static struct sso_led187*cdev_to_sso_led_data(struct led_classdev *led_cdev)188{189	return container_of(led_cdev, struct sso_led, cdev);190}191 192static void sso_led_freq_set(struct sso_led_priv *priv, u32 pin, int freq_idx)193{194	u32 reg, off, freq_src, val_freq;195	u32 low, high, val;196	unsigned int group;197 198	if (!freq_idx)199		return;200 201	group = sso_led_pin_to_group(pin);202	freq_src = sso_led_get_freq_src(freq_idx);203	off = sso_led_pin_blink_off(pin, group);204 205	if (group == LED_GRP0_0_23)206		return;207	else if (group == LED_GRP1_24_28)208		reg = LED_BLINK_H8_0;209	else210		reg = LED_BLINK_H8_1;211 212	if (freq_src == CLK_SRC_FPID)213		val_freq = freq_idx - 1;214	else if (freq_src == CLK_SRC_GPTC)215		val_freq = freq_idx - MAX_FPID_FREQ_RANK;216 217	/* set blink rate idx */218	if (freq_src != CLK_SRC_GPTC_HS) {219		low = GET_FREQ_OFFSET(off, freq_src);220		high = low + 2;221		val = val_freq << high;222		regmap_update_bits(priv->mmap, reg, GENMASK(high, low), val);223	}224 225	/* select clock source */226	low = GET_SRC_OFFSET(off);227	high = low + 2;228	val = freq_src << high;229	regmap_update_bits(priv->mmap, reg, GENMASK(high, low), val);230}231 232static void sso_led_brightness_set(struct led_classdev *led_cdev,233				   enum led_brightness brightness)234{235	struct sso_led_priv *priv;236	struct sso_led_desc *desc;237	struct sso_led *led;238	int val;239 240	led = cdev_to_sso_led_data(led_cdev);241	priv = led->priv;242	desc = &led->desc;243 244	desc->brightness = brightness;245	regmap_write(priv->mmap, DUTY_CYCLE(desc->pin), brightness);246 247	if (brightness == LED_OFF)248		val = 0;249	else250		val = 1;251 252	/* HW blink off */253	if (desc->hw_blink && !val && desc->blinking) {254		desc->blinking = 0;255		regmap_update_bits(priv->mmap, SSO_CON2, BIT(desc->pin), 0);256	} else if (desc->hw_blink && val && !desc->blinking) {257		desc->blinking = 1;258		regmap_update_bits(priv->mmap, SSO_CON2, BIT(desc->pin),259				   1 << desc->pin);260	}261 262	if (!desc->hw_trig)263		gpiod_set_value(led->gpiod, val);264}265 266static enum led_brightness sso_led_brightness_get(struct led_classdev *led_cdev)267{268	struct sso_led *led = cdev_to_sso_led_data(led_cdev);269 270	return (enum led_brightness)led->desc.brightness;271}272 273static int274delay_to_freq_idx(struct sso_led *led, unsigned long *delay_on,275		  unsigned long *delay_off)276{277	struct sso_led_priv *priv = led->priv;278	unsigned long delay;279	int freq_idx;280	u32 freq;281 282	if (!*delay_on && !*delay_off) {283		*delay_on = *delay_off = (1000 / priv->freq[0]) / 2;284		return 0;285	}286 287	delay = *delay_on + *delay_off;288	freq = 1000 / delay;289 290	freq_idx = sso_get_blink_rate_idx(priv, freq);291	if (freq_idx == -1)292		freq_idx = MAX_FREQ_RANK - 1;293 294	delay = 1000 / priv->freq[freq_idx];295	*delay_on = *delay_off = delay / 2;296 297	if (!*delay_on)298		*delay_on = *delay_off = 1;299 300	return freq_idx;301}302 303static int304sso_led_blink_set(struct led_classdev *led_cdev, unsigned long *delay_on,305		  unsigned long *delay_off)306{307	struct sso_led_priv *priv;308	struct sso_led *led;309	int freq_idx;310 311	led = cdev_to_sso_led_data(led_cdev);312	priv = led->priv;313	freq_idx = delay_to_freq_idx(led, delay_on, delay_off);314 315	sso_led_freq_set(priv, led->desc.pin, freq_idx);316	regmap_update_bits(priv->mmap, SSO_CON2, BIT(led->desc.pin),317			   1 << led->desc.pin);318	led->desc.freq_idx = freq_idx;319	led->desc.blink_rate = priv->freq[freq_idx];320	led->desc.blinking = 1;321 322	return 1;323}324 325static void sso_led_hw_cfg(struct sso_led_priv *priv, struct sso_led *led)326{327	struct sso_led_desc *desc = &led->desc;328 329	/* set freq */330	if (desc->hw_blink) {331		sso_led_freq_set(priv, desc->pin, desc->freq_idx);332		regmap_update_bits(priv->mmap, SSO_CON2, BIT(desc->pin),333				   1 << desc->pin);334	}335 336	if (desc->hw_trig)337		regmap_update_bits(priv->mmap, SSO_CON3, BIT(desc->pin),338				   1 << desc->pin);339 340	/* set brightness */341	regmap_write(priv->mmap, DUTY_CYCLE(desc->pin), desc->brightness);342 343	/* enable output */344	if (!desc->hw_trig && desc->brightness)345		gpiod_set_value(led->gpiod, 1);346}347 348static int sso_create_led(struct sso_led_priv *priv, struct sso_led *led,349			  struct fwnode_handle *child)350{351	struct sso_led_desc *desc = &led->desc;352	struct led_init_data init_data;353	int err;354 355	init_data.fwnode = child;356	init_data.devicename = SSO_DEV_NAME;357	init_data.default_label = ":";358 359	led->cdev.default_trigger = desc->default_trigger;360	led->cdev.brightness_set = sso_led_brightness_set;361	led->cdev.brightness_get = sso_led_brightness_get;362	led->cdev.brightness = desc->brightness;363	led->cdev.max_brightness = LED_FULL;364 365	if (desc->retain_state_shutdown)366		led->cdev.flags |= LED_RETAIN_AT_SHUTDOWN;367	if (desc->retain_state_suspended)368		led->cdev.flags |= LED_CORE_SUSPENDRESUME;369	if (desc->panic_indicator)370		led->cdev.flags |= LED_PANIC_INDICATOR;371 372	if (desc->hw_blink)373		led->cdev.blink_set = sso_led_blink_set;374 375	sso_led_hw_cfg(priv, led);376 377	err = devm_led_classdev_register_ext(priv->dev, &led->cdev, &init_data);378	if (err)379		return err;380 381	list_add(&led->list, &priv->led_list);382 383	return 0;384}385 386static void sso_init_freq(struct sso_led_priv *priv)387{388	int i;389 390	priv->freq[0] = 0;391	for (i = 1; i < MAX_FREQ_RANK; i++) {392		if (i < MAX_FPID_FREQ_RANK) {393			priv->freq[i] = priv->fpid_clkrate / freq_div_tbl[i - 1];394		} else if (i < MAX_GPTC_FREQ_RANK) {395			priv->freq[i] = priv->gptc_clkrate /396				freq_div_tbl[i - MAX_FPID_FREQ_RANK];397		} else if (i < MAX_GPTC_HS_FREQ_RANK) {398			priv->freq[i] = priv->gptc_clkrate;399		}400	}401}402 403static int sso_gpio_request(struct gpio_chip *chip, unsigned int offset)404{405	struct sso_led_priv *priv = gpiochip_get_data(chip);406 407	if (priv->gpio.alloc_bitmap & BIT(offset))408		return -EINVAL;409 410	priv->gpio.alloc_bitmap |= BIT(offset);411	regmap_write(priv->mmap, DUTY_CYCLE(offset), 0xFF);412 413	return 0;414}415 416static void sso_gpio_free(struct gpio_chip *chip, unsigned int offset)417{418	struct sso_led_priv *priv = gpiochip_get_data(chip);419 420	priv->gpio.alloc_bitmap &= ~BIT(offset);421	regmap_write(priv->mmap, DUTY_CYCLE(offset), 0x0);422}423 424static int sso_gpio_get_dir(struct gpio_chip *chip, unsigned int offset)425{426	return GPIO_LINE_DIRECTION_OUT;427}428 429static int430sso_gpio_dir_out(struct gpio_chip *chip, unsigned int offset, int value)431{432	struct sso_led_priv *priv = gpiochip_get_data(chip);433	bool bit = !!value;434 435	regmap_update_bits(priv->mmap, SSO_CPU, BIT(offset), bit << offset);436	if (!priv->gpio.freq)437		regmap_update_bits(priv->mmap, SSO_CON0, SSO_CON0_SWU,438				   SSO_CON0_SWU);439 440	return 0;441}442 443static int sso_gpio_get(struct gpio_chip *chip, unsigned int offset)444{445	struct sso_led_priv *priv = gpiochip_get_data(chip);446	u32 reg_val;447 448	regmap_read(priv->mmap, SSO_CPU, &reg_val);449 450	return !!(reg_val & BIT(offset));451}452 453static void sso_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)454{455	struct sso_led_priv *priv = gpiochip_get_data(chip);456 457	regmap_update_bits(priv->mmap, SSO_CPU, BIT(offset), value << offset);458	if (!priv->gpio.freq)459		regmap_update_bits(priv->mmap, SSO_CON0, SSO_CON0_SWU,460				   SSO_CON0_SWU);461}462 463static int sso_gpio_gc_init(struct device *dev, struct sso_led_priv *priv)464{465	struct gpio_chip *gc = &priv->gpio.chip;466 467	gc->request             = sso_gpio_request;468	gc->free                = sso_gpio_free;469	gc->get_direction       = sso_gpio_get_dir;470	gc->direction_output    = sso_gpio_dir_out;471	gc->get                 = sso_gpio_get;472	gc->set                 = sso_gpio_set;473 474	gc->label               = "lgm-sso";475	gc->base                = -1;476	/* To exclude pins from control, use "gpio-reserved-ranges" */477	gc->ngpio               = priv->gpio.pins;478	gc->parent              = dev;479	gc->owner               = THIS_MODULE;480 481	return devm_gpiochip_add_data(dev, gc, priv);482}483 484static int sso_gpio_get_freq_idx(int freq)485{486	int idx;487 488	for (idx = 0; idx < ARRAY_SIZE(freq_tbl); idx++) {489		if (freq <= freq_tbl[idx])490			return idx;491	}492 493	return -1;494}495 496static void sso_register_shift_clk(struct sso_led_priv *priv)497{498	int idx, size = ARRAY_SIZE(shift_clk_freq_tbl);499	u32 val = 0;500 501	for (idx = 0; idx < size; idx++) {502		if (shift_clk_freq_tbl[idx] <= priv->gpio.shift_clk_freq) {503			val = idx;504			break;505		}506	}507 508	if (idx == size)509		dev_warn(priv->dev, "%s: Invalid freq %d\n",510			 __func__, priv->gpio.shift_clk_freq);511 512	regmap_update_bits(priv->mmap, SSO_CON1, SSO_CON1_FCDSC,513			   FIELD_PREP(SSO_CON1_FCDSC, val));514}515 516static int sso_gpio_freq_set(struct sso_led_priv *priv)517{518	int freq_idx;519	u32 val;520 521	freq_idx = sso_gpio_get_freq_idx(priv->gpio.freq);522	if (freq_idx == -1)523		freq_idx = ARRAY_SIZE(freq_tbl) - 1;524 525	val = freq_idx % FPID_FREQ_RANK_MAX;526 527	if (!priv->gpio.freq) {528		regmap_update_bits(priv->mmap, SSO_CON0, SSO_CON0_BLINK_R, 0);529		regmap_update_bits(priv->mmap, SSO_CON1, SSO_CON1_US,530				   FIELD_PREP(SSO_CON1_US, US_SW));531	} else if (freq_idx < FPID_FREQ_RANK_MAX) {532		regmap_update_bits(priv->mmap, SSO_CON0, SSO_CON0_BLINK_R,533				   SSO_CON0_BLINK_R);534		regmap_update_bits(priv->mmap, SSO_CON1, SSO_CON1_US,535				   FIELD_PREP(SSO_CON1_US, US_FPID));536		regmap_update_bits(priv->mmap, SSO_CON1, SSO_CON1_FPID,537				   FIELD_PREP(SSO_CON1_FPID, val));538	} else {539		regmap_update_bits(priv->mmap, SSO_CON0, SSO_CON0_BLINK_R,540				   SSO_CON0_BLINK_R);541		regmap_update_bits(priv->mmap, SSO_CON1, SSO_CON1_US,542				   FIELD_PREP(SSO_CON1_US, US_GPTC));543		regmap_update_bits(priv->mmap, SSO_CON1, SSO_CON1_GPTD,544				   FIELD_PREP(SSO_CON1_GPTD, val));545	}546 547	return 0;548}549 550static int sso_gpio_hw_init(struct sso_led_priv *priv)551{552	u32 activate;553	int i, err;554 555	/* Clear all duty cycles */556	for (i = 0; i < priv->gpio.pins; i++) {557		err = regmap_write(priv->mmap, DUTY_CYCLE(i), 0);558		if (err)559			return err;560	}561 562	/* 4 groups for total 32 pins */563	for (i = 1; i <= MAX_GROUP_NUM; i++) {564		activate = !!(i * PINS_PER_GROUP <= priv->gpio.pins ||565			      priv->gpio.pins > (i - 1) * PINS_PER_GROUP);566		err = regmap_update_bits(priv->mmap, SSO_CON1, BIT(i - 1),567					 activate << (i - 1));568		if (err)569			return err;570	}571 572	/* NO HW directly controlled pin by default */573	err = regmap_write(priv->mmap, SSO_CON3, 0);574	if (err)575		return err;576 577	/* NO BLINK for all pins */578	err = regmap_write(priv->mmap, SSO_CON2, 0);579	if (err)580		return err;581 582	/* OUTPUT 0 by default */583	err = regmap_write(priv->mmap, SSO_CPU, 0);584	if (err)585		return err;586 587	/* update edge */588	err = regmap_update_bits(priv->mmap, SSO_CON0, SSO_CON0_RZFL,589				 FIELD_PREP(SSO_CON0_RZFL, priv->gpio.edge));590	if (err)591		return err;592 593	/* Set GPIO update rate */594	sso_gpio_freq_set(priv);595 596	/* Register shift clock */597	sso_register_shift_clk(priv);598 599	return 0;600}601 602static void sso_led_shutdown(struct sso_led *led)603{604	struct sso_led_priv *priv = led->priv;605 606	/* unregister led */607	devm_led_classdev_unregister(priv->dev, &led->cdev);608 609	/* clear HW control bit */610	if (led->desc.hw_trig)611		regmap_update_bits(priv->mmap, SSO_CON3, BIT(led->desc.pin), 0);612 613	led->priv = NULL;614}615 616static int617__sso_led_dt_parse(struct sso_led_priv *priv, struct fwnode_handle *fw_ssoled)618{619	struct fwnode_handle *fwnode_child;620	struct device *dev = priv->dev;621	struct sso_led_desc *desc;622	struct sso_led *led;623	const char *tmp;624	u32 prop;625	int ret;626 627	fwnode_for_each_child_node(fw_ssoled, fwnode_child) {628		led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);629		if (!led) {630			ret = -ENOMEM;631			goto __dt_err;632		}633 634		INIT_LIST_HEAD(&led->list);635		led->priv = priv;636		desc = &led->desc;637 638		led->gpiod = devm_fwnode_gpiod_get(dev, fwnode_child, NULL,639						   GPIOD_ASIS, NULL);640		if (IS_ERR(led->gpiod)) {641			ret = dev_err_probe(dev, PTR_ERR(led->gpiod), "led: get gpio fail!\n");642			goto __dt_err;643		}644 645		fwnode_property_read_string(fwnode_child,646					    "linux,default-trigger",647					    &desc->default_trigger);648 649		if (fwnode_property_present(fwnode_child,650					    "retain-state-suspended"))651			desc->retain_state_suspended = 1;652 653		if (fwnode_property_present(fwnode_child,654					    "retain-state-shutdown"))655			desc->retain_state_shutdown = 1;656 657		if (fwnode_property_present(fwnode_child, "panic-indicator"))658			desc->panic_indicator = 1;659 660		ret = fwnode_property_read_u32(fwnode_child, "reg", &prop);661		if (ret)662			goto __dt_err;663		if (prop >= SSO_LED_MAX_NUM) {664			dev_err(dev, "invalid LED pin:%u\n", prop);665			ret = -EINVAL;666			goto __dt_err;667		}668		desc->pin = prop;669 670		if (fwnode_property_present(fwnode_child, "intel,sso-hw-blink"))671			desc->hw_blink = 1;672 673		desc->hw_trig = fwnode_property_read_bool(fwnode_child,674							  "intel,sso-hw-trigger");675		if (desc->hw_trig) {676			desc->default_trigger = NULL;677			desc->retain_state_shutdown = 0;678			desc->retain_state_suspended = 0;679			desc->panic_indicator = 0;680			desc->hw_blink = 0;681		}682 683		if (fwnode_property_read_u32(fwnode_child,684					     "intel,sso-blink-rate-hz", &prop)) {685			/* default first freq rate */686			desc->freq_idx = 0;687			desc->blink_rate = priv->freq[desc->freq_idx];688		} else {689			desc->freq_idx = sso_get_blink_rate_idx(priv, prop);690			if (desc->freq_idx == -1)691				desc->freq_idx = MAX_FREQ_RANK - 1;692 693			desc->blink_rate = priv->freq[desc->freq_idx];694		}695 696		if (!fwnode_property_read_string(fwnode_child, "default-state", &tmp)) {697			if (!strcmp(tmp, "on"))698				desc->brightness = LED_FULL;699		}700 701		ret = sso_create_led(priv, led, fwnode_child);702		if (ret)703			goto __dt_err;704	}705 706	return 0;707 708__dt_err:709	fwnode_handle_put(fwnode_child);710	/* unregister leds */711	list_for_each_entry(led, &priv->led_list, list)712		sso_led_shutdown(led);713 714	return ret;715}716 717static int sso_led_dt_parse(struct sso_led_priv *priv)718{719	struct fwnode_handle *fwnode = dev_fwnode(priv->dev);720	struct fwnode_handle *fw_ssoled;721	struct device *dev = priv->dev;722	int count;723	int ret;724 725	count = device_get_child_node_count(dev);726	if (!count)727		return 0;728 729	fw_ssoled = fwnode_get_named_child_node(fwnode, "ssoled");730	if (fw_ssoled) {731		ret = __sso_led_dt_parse(priv, fw_ssoled);732		fwnode_handle_put(fw_ssoled);733		if (ret)734			return ret;735	}736 737	return 0;738}739 740static int sso_probe_gpios(struct sso_led_priv *priv)741{742	struct device *dev = priv->dev;743	int ret;744 745	if (device_property_read_u32(dev, "ngpios", &priv->gpio.pins))746		priv->gpio.pins = MAX_PIN_NUM_PER_BANK;747 748	if (priv->gpio.pins > MAX_PIN_NUM_PER_BANK)749		return -EINVAL;750 751	if (device_property_read_u32(dev, "intel,sso-update-rate-hz",752				     &priv->gpio.freq))753		priv->gpio.freq = 0;754 755	priv->gpio.edge = DATA_CLK_EDGE;756	priv->gpio.shift_clk_freq = -1;757 758	ret = sso_gpio_hw_init(priv);759	if (ret)760		return ret;761 762	return sso_gpio_gc_init(dev, priv);763}764 765static void sso_clock_disable_unprepare(void *data)766{767	struct sso_led_priv *priv = data;768 769	clk_bulk_disable_unprepare(ARRAY_SIZE(priv->clocks), priv->clocks);770}771 772static int intel_sso_led_probe(struct platform_device *pdev)773{774	struct device *dev = &pdev->dev;775	struct sso_led_priv *priv;776	int ret;777 778	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);779	if (!priv)780		return -ENOMEM;781 782	priv->pdev = pdev;783	priv->dev = dev;784 785	/* gate clock */786	priv->clocks[0].id = "sso";787 788	/* fpid clock */789	priv->clocks[1].id = "fpid";790 791	ret = devm_clk_bulk_get(dev, ARRAY_SIZE(priv->clocks), priv->clocks);792	if (ret) {793		dev_err(dev, "Getting clocks failed!\n");794		return ret;795	}796 797	ret = clk_bulk_prepare_enable(ARRAY_SIZE(priv->clocks), priv->clocks);798	if (ret) {799		dev_err(dev, "Failed to prepare and enable clocks!\n");800		return ret;801	}802 803	ret = devm_add_action_or_reset(dev, sso_clock_disable_unprepare, priv);804	if (ret)805		return ret;806 807	priv->fpid_clkrate = clk_get_rate(priv->clocks[1].clk);808 809	priv->mmap = syscon_node_to_regmap(dev->of_node);810 811	priv->mmap = syscon_node_to_regmap(dev->of_node);812	if (IS_ERR(priv->mmap)) {813		dev_err(dev, "Failed to map iomem!\n");814		return PTR_ERR(priv->mmap);815	}816 817	ret = sso_probe_gpios(priv);818	if (ret) {819		regmap_exit(priv->mmap);820		return ret;821	}822 823	INIT_LIST_HEAD(&priv->led_list);824 825	platform_set_drvdata(pdev, priv);826	sso_init_freq(priv);827 828	priv->gptc_clkrate = DEF_GPTC_CLK_RATE;829 830	ret = sso_led_dt_parse(priv);831	if (ret) {832		regmap_exit(priv->mmap);833		return ret;834	}835	dev_info(priv->dev, "sso LED init success!\n");836 837	return 0;838}839 840static void intel_sso_led_remove(struct platform_device *pdev)841{842	struct sso_led_priv *priv;843	struct sso_led *led, *n;844 845	priv = platform_get_drvdata(pdev);846 847	list_for_each_entry_safe(led, n, &priv->led_list, list) {848		list_del(&led->list);849		sso_led_shutdown(led);850	}851 852	regmap_exit(priv->mmap);853}854 855static const struct of_device_id of_sso_led_match[] = {856	{ .compatible = "intel,lgm-ssoled" },857	{}858};859 860MODULE_DEVICE_TABLE(of, of_sso_led_match);861 862static struct platform_driver intel_sso_led_driver = {863	.probe		= intel_sso_led_probe,864	.remove_new	= intel_sso_led_remove,865	.driver		= {866			.name = "lgm-ssoled",867			.of_match_table = of_sso_led_match,868	},869};870 871module_platform_driver(intel_sso_led_driver);872 873MODULE_DESCRIPTION("Intel SSO LED/GPIO driver");874MODULE_LICENSE("GPL v2");875