Lines Matching +full:register +full:- +full:bit +full:- +full:led
1 // SPDX-License-Identifier: GPL-2.0
3 * PCIe Enclosure management driver created for LED interfaces based on
5 * they blink - it is hardware defined.
13 * _DSM Definitions for PCIe SSD Status LED
16 * Two backends are supported to manipulate indications: Direct NPEM register
20 * Copyright (c) 2021-2022 Dell Inc.
21 * Copyright (c) 2023-2024 Intel Corporation
39 u32 bit; member
65 /* _DSM PCIe SSD LED States correspond to NPEM register values */
81 for (ind = inds; ind->bit; ind++)
85 * should not touch bits that are not defined and for which LED devices are
99 supported_indications |= ind->bit; in reg_to_indications()
105 * struct npem_led - LED details
108 * @name: LED name
109 * @led: LED device
115 struct led_classdev led; member
119 * struct npem_ops - backend specific callbacks
125 * inds: bit mask to set
137 * struct npem - NPEM device properties
140 * @lock: serializes concurrent access to NPEM device by multiple LED devices
141 * @pos: cached offset of NPEM Capability Register in Configuration Space;
143 * @supported_indications: cached bit mask of supported indications;
144 * non-indication and reserved bits in the NPEM Capability Register are
145 * cleared in this bit mask
146 * @active_indications: cached bit mask of active indications;
147 * non-indication and reserved bits in the NPEM Control Register are
148 * cleared in this bit mask
153 * (on first access to an LED), IPMI drivers are given a chance to load.
154 * If they are not loaded in time, users will see various errors on LED
155 * access in dmesg. Once they are loaded, the errors go away and LED
158 * @leds: array containing LED class devices of all supported LEDs
174 int ret = pci_read_config_dword(npem->dev, npem->pos + reg, val); in npem_read_reg()
181 int pos = npem->pos + PCI_NPEM_CTRL; in npem_write_ctrl()
182 int ret = pci_write_config_dword(npem->dev, pos, reg); in npem_write_ctrl()
202 *inds = ctrl & npem->supported_indications; in npem_get_active_indications()
212 lockdep_assert_held(&npem->lock); in npem_set_active_indications()
214 /* This bit is always required */ in npem_set_active_indications()
224 * the status register, but rather poll under interrupt at a reduced in npem_set_active_indications()
240 * All writes to control register, including writes that do not change in npem_set_active_indications()
241 * the register value, are NPEM commands and should eventually result in npem_set_active_indications()
242 * in a command completion indication in the NPEM Status Register. in npem_set_active_indications()
246 * Register may not be updated, or other conflicting bits may be in npem_set_active_indications()
247 * cleared. Spec is not strict here. Read NPEM Control register after in npem_set_active_indications()
248 * write to keep cache in-sync. in npem_set_active_indications()
250 return npem_get_active_indications(npem, &npem->active_indications); in npem_set_active_indications()
272 handle = ACPI_HANDLE(&pdev->dev); in npem_has_dsm()
277 BIT(GET_SUPPORTED_STATES_DSM) | in npem_has_dsm()
278 BIT(GET_STATE_DSM) | BIT(SET_STATE_DSM)); in npem_has_dsm()
289 * dsm_evaluate() - send DSM PCIe SSD Status LED command
291 * @dsm_func: DSM LED Function
301 acpi_handle handle = ACPI_HANDLE(&pdev->dev); in dsm_evaluate()
320 return -EIO; in dsm_evaluate()
322 if (out_obj->buffer.length < sizeof(struct dsm_output)) { in dsm_evaluate()
324 return -EIO; in dsm_evaluate()
327 memcpy(output, out_obj->buffer.pointer, sizeof(struct dsm_output)); in dsm_evaluate()
342 return -EIO; in dsm_get()
350 int ret = dsm_get(npem->dev, GET_STATE_DSM, buf); in dsm_get_active_indications()
353 *buf &= npem->supported_indications; in dsm_get_active_indications()
360 int ret = dsm_evaluate(npem->dev, SET_STATE_DSM, &output, value); in dsm_set_active_indications()
368 * Not all bits are set. If this bit is set, the platform in dsm_set_active_indications()
370 * should check the resulting PCIe SSD Status LED States to see in dsm_set_active_indications()
373 * PCI Firmware Specification, r3.3 Table 4-19. in dsm_set_active_indications()
376 return -EIO; in dsm_set_active_indications()
381 return -EIO; in dsm_set_active_indications()
384 npem->active_indications = output.state; in dsm_set_active_indications()
392 .name = "_DSM PCIe SSD Status LED Management",
400 lockdep_assert_held(&npem->lock); in npem_initialize_active_indications()
402 if (npem->active_inds_initialized) in npem_initialize_active_indications()
405 ret = npem->ops->get_active_indications(npem, in npem_initialize_active_indications()
406 &npem->active_indications); in npem_initialize_active_indications()
410 npem->active_inds_initialized = true; in npem_initialize_active_indications()
419 static enum led_brightness brightness_get(struct led_classdev *led) in brightness_get() argument
421 struct npem_led *nled = container_of(led, struct npem_led, led); in brightness_get()
422 struct npem *npem = nled->npem; in brightness_get()
425 ret = mutex_lock_interruptible(&npem->lock); in brightness_get()
433 if (npem->active_indications & nled->indication->bit) in brightness_get()
437 mutex_unlock(&npem->lock); in brightness_get()
441 static int brightness_set(struct led_classdev *led, in brightness_set() argument
444 struct npem_led *nled = container_of(led, struct npem_led, led); in brightness_set()
445 struct npem *npem = nled->npem; in brightness_set()
449 ret = mutex_lock_interruptible(&npem->lock); in brightness_set()
458 indications = npem->active_indications & ~(nled->indication->bit); in brightness_set()
460 indications = npem->active_indications | nled->indication->bit; in brightness_set()
462 ret = npem->ops->set_active_indications(npem, indications); in brightness_set()
465 mutex_unlock(&npem->lock); in brightness_set()
477 for (cnt = 0; cnt < npem->led_cnt; cnt++) { in npem_free()
478 nled = &npem->leds[cnt]; in npem_free()
480 if (nled->name[0]) in npem_free()
481 led_classdev_unregister(&nled->led); in npem_free()
484 mutex_destroy(&npem->lock); in npem_free()
490 struct led_classdev *led = &nled->led; in pci_npem_set_led_classdev() local
492 char *name = nled->name; in pci_npem_set_led_classdev()
495 init_data.devicename = pci_name(npem->dev); in pci_npem_set_led_classdev()
496 init_data.default_label = nled->indication->name; in pci_npem_set_led_classdev()
498 ret = led_compose_name(&npem->dev->dev, &init_data, name); in pci_npem_set_led_classdev()
502 led->name = name; in pci_npem_set_led_classdev()
503 led->brightness_set_blocking = brightness_set; in pci_npem_set_led_classdev()
504 led->brightness_get = brightness_get; in pci_npem_set_led_classdev()
505 led->max_brightness = 1; in pci_npem_set_led_classdev()
506 led->default_trigger = "none"; in pci_npem_set_led_classdev()
507 led->flags = 0; in pci_npem_set_led_classdev()
509 ret = led_classdev_register(&npem->dev->dev, led); in pci_npem_set_led_classdev()
519 u32 supported = reg_to_indications(caps, ops->inds); in pci_npem_init()
529 return -ENOMEM; in pci_npem_init()
531 npem->supported_indications = supported; in pci_npem_init()
532 npem->led_cnt = supported_cnt; in pci_npem_init()
533 npem->pos = pos; in pci_npem_init()
534 npem->dev = dev; in pci_npem_init()
535 npem->ops = ops; in pci_npem_init()
537 mutex_init(&npem->lock); in pci_npem_init()
540 if (!(npem->supported_indications & indication->bit)) in pci_npem_init()
543 nled = &npem->leds[led_idx++]; in pci_npem_init()
544 nled->indication = indication; in pci_npem_init()
545 nled->npem = npem; in pci_npem_init()
554 dev->npem = npem; in pci_npem_init()
560 npem_free(dev->npem); in pci_npem_remove()
571 * OS should use the DSM for LED control if it is available in pci_npem_create()
589 pci_info(dev, "Configuring %s\n", ops->name); in pci_npem_create()
593 pci_err(dev, "Failed to register %s, err: %d\n", ops->name, in pci_npem_create()