/* SPDX-License-Identifier: GPL-2.0-only */

#ifndef __ACPI_ACPI_DEVICE_H__
#define __ACPI_ACPI_DEVICE_H__

#include <device/i2c.h>
#include <spi-generic.h>
#include <types.h>

enum acpi_dp_type {
	ACPI_DP_TYPE_UNKNOWN,
	ACPI_DP_TYPE_INTEGER,
	ACPI_DP_TYPE_STRING,
	ACPI_DP_TYPE_REFERENCE,
	ACPI_DP_TYPE_TABLE,
	ACPI_DP_TYPE_ARRAY,
	ACPI_DP_TYPE_CHILD,
	ACPI_DP_TYPE_PACKAGE,
};

struct acpi_dp {
	enum acpi_dp_type type;
	const char *name;
	const char *uuid;
	struct acpi_dp *next;
	union {
		struct acpi_dp *child;
		struct acpi_dp *array;
	};
	union {
		uint64_t integer;
		const char *string;
	};
};

#define ACPI_DESCRIPTOR_LARGE		(1 << 7)
#define ACPI_DESCRIPTOR_INTERRUPT	(ACPI_DESCRIPTOR_LARGE | 9)
#define ACPI_DESCRIPTOR_GPIO		(ACPI_DESCRIPTOR_LARGE | 12)
#define ACPI_DESCRIPTOR_SERIAL_BUS	(ACPI_DESCRIPTOR_LARGE | 14)

/*
 * PRP0001 is a special DT namespace link device ID. It provides a means to use
 * existing DT-compatible device identification in ACPI. When this _HID is used
 * by an ACPI device, the ACPI subsystem in OS looks up "compatible" property in
 * device object's _DSD and will use the value of that property to identify the
 * corresponding device in analogy with the original DT device identification
 * algorithm.
 * More details can be found in Linux kernel documentation:
 * Documentation/acpi/enumeration.txt
 */
#define ACPI_DT_NAMESPACE_HID		"PRP0001"

struct device;
const char *acpi_device_name(const struct device *dev);
const char *acpi_device_hid(const struct device *dev);
uint32_t acpi_device_uid(const struct device *dev);
const char *acpi_device_path(const struct device *dev);
const char *acpi_device_scope(const struct device *dev);
const char *acpi_device_path_join(const struct device *dev, const char *name);
int acpi_device_status(const struct device *dev);
void acpi_device_write_uid(const struct device *dev);

/*
 * ACPI Descriptor for extended Interrupt()
 */

enum acpi_irq_mode {
	ACPI_IRQ_EDGE_TRIGGERED,
	ACPI_IRQ_LEVEL_TRIGGERED
};

enum acpi_irq_polarity {
	ACPI_IRQ_ACTIVE_LOW,
	ACPI_IRQ_ACTIVE_HIGH,
	ACPI_IRQ_ACTIVE_BOTH
};

enum acpi_irq_shared {
	ACPI_IRQ_EXCLUSIVE,
	ACPI_IRQ_SHARED
};

enum acpi_irq_wake {
	ACPI_IRQ_NO_WAKE,
	ACPI_IRQ_WAKE
};

struct acpi_irq {
	unsigned int pin;
	enum acpi_irq_mode mode;
	enum acpi_irq_polarity polarity;
	enum acpi_irq_shared shared;
	enum acpi_irq_wake wake;
};

#define ACPI_IRQ_CFG(_pin, _mode, _pol, _shared, _wake) { \
	.pin = (_pin),						\
	.mode = (_mode),			\
	.polarity = (_pol),			\
	.shared = (_shared),	\
	.wake = (_wake) }

#define ACPI_IRQ_EDGE_LOW(x)	\
	ACPI_IRQ_CFG((x), ACPI_IRQ_EDGE_TRIGGERED, ACPI_IRQ_ACTIVE_LOW, \
		     ACPI_IRQ_EXCLUSIVE, ACPI_IRQ_NO_WAKE)

#define ACPI_IRQ_EDGE_HIGH(x)	\
	ACPI_IRQ_CFG((x), ACPI_IRQ_EDGE_TRIGGERED, ACPI_IRQ_ACTIVE_HIGH, \
		     ACPI_IRQ_EXCLUSIVE, ACPI_IRQ_NO_WAKE)

#define ACPI_IRQ_LEVEL_LOW(x)	\
	ACPI_IRQ_CFG((x), ACPI_IRQ_LEVEL_TRIGGERED, ACPI_IRQ_ACTIVE_LOW, \
		     ACPI_IRQ_SHARED, ACPI_IRQ_NO_WAKE)

#define ACPI_IRQ_LEVEL_HIGH(x)	\
	ACPI_IRQ_CFG((x), ACPI_IRQ_LEVEL_TRIGGERED, ACPI_IRQ_ACTIVE_HIGH, \
		     ACPI_IRQ_SHARED, ACPI_IRQ_NO_WAKE)

#define ACPI_IRQ_WAKE_EDGE_LOW(x)	\
	ACPI_IRQ_CFG((x), ACPI_IRQ_EDGE_TRIGGERED, ACPI_IRQ_ACTIVE_LOW, \
		     ACPI_IRQ_EXCLUSIVE, ACPI_IRQ_WAKE)

#define ACPI_IRQ_WAKE_EDGE_HIGH(x)	\
	ACPI_IRQ_CFG((x), ACPI_IRQ_EDGE_TRIGGERED, ACPI_IRQ_ACTIVE_HIGH, \
		     ACPI_IRQ_EXCLUSIVE, ACPI_IRQ_WAKE)

#define ACPI_IRQ_WAKE_LEVEL_LOW(x)	\
	ACPI_IRQ_CFG((x), ACPI_IRQ_LEVEL_TRIGGERED, ACPI_IRQ_ACTIVE_LOW, \
		     ACPI_IRQ_SHARED, ACPI_IRQ_WAKE)

#define ACPI_IRQ_WAKE_LEVEL_HIGH(x)					\
	ACPI_IRQ_CFG((x), ACPI_IRQ_LEVEL_TRIGGERED, ACPI_IRQ_ACTIVE_HIGH, \
		     ACPI_IRQ_SHARED, ACPI_IRQ_WAKE)

/* Write extended Interrupt() descriptor to SSDT AML output */
void acpi_device_write_interrupt(const struct acpi_irq *irq);

/*
 * ACPI Descriptors for GpioIo() and GpioInterrupt()
 */

enum acpi_gpio_type {
	ACPI_GPIO_TYPE_INTERRUPT,
	ACPI_GPIO_TYPE_IO
};

enum acpi_gpio_pull {
	ACPI_GPIO_PULL_DEFAULT,
	ACPI_GPIO_PULL_UP,
	ACPI_GPIO_PULL_DOWN,
	ACPI_GPIO_PULL_NONE
};

enum acpi_gpio_io_restrict {
	ACPI_GPIO_IO_RESTRICT_NONE,
	ACPI_GPIO_IO_RESTRICT_INPUT,
	ACPI_GPIO_IO_RESTRICT_OUTPUT,
	ACPI_GPIO_IO_RESTRICT_PRESERVE
};

#define ACPI_GPIO_REVISION_ID		1
#define ACPI_GPIO_MAX_PINS		8

struct acpi_gpio {
	int pin_count;
	uint16_t pins[ACPI_GPIO_MAX_PINS];

	enum acpi_gpio_type type;
	enum acpi_gpio_pull pull;
	const char *resource;

	/* GpioInt */
	uint16_t interrupt_debounce_timeout;	/* 1/100 ms */
	struct acpi_irq irq;

	/* GpioIo */
	uint16_t output_drive_strength;		/* 1/100 mA */
	int io_shared;
	enum acpi_gpio_io_restrict io_restrict;
	/*
	 * As per ACPI spec, GpioIo does not have any polarity associated with it. Linux kernel
	 * uses `active_low` argument within GPIO _DSD property to allow BIOS to indicate if the
	 * corresponding GPIO should be treated as active low. Thus, if the GPIO has active high
	 * polarity or if it does not have any polarity, then the `active_low` argument is
	 * supposed to be set to 0.
	 *
	 * Reference:
	 * https://www.kernel.org/doc/html/latest/firmware-guide/acpi/gpio-properties.html
	 */
	bool active_low;
};

/* GpioIo-related macros */
#define ACPI_GPIO_CFG(_gpio, _io_restrict, _active_low) { \
	.type = ACPI_GPIO_TYPE_IO, \
	.pull = ACPI_GPIO_PULL_DEFAULT, \
	.io_restrict = _io_restrict, \
	.active_low = _active_low, \
	.pin_count = 1, \
	.pins = { (_gpio) } }

/* Basic output GPIO with default pull settings */
#define ACPI_GPIO_OUTPUT_CFG(gpio, active_low) \
		ACPI_GPIO_CFG(gpio, ACPI_GPIO_IO_RESTRICT_OUTPUT, active_low)

#define ACPI_GPIO_OUTPUT(gpio)			ACPI_GPIO_OUTPUT_CFG(gpio, 0)
#define ACPI_GPIO_OUTPUT_ACTIVE_HIGH(gpio)	ACPI_GPIO_OUTPUT_CFG(gpio, 0)
#define ACPI_GPIO_OUTPUT_ACTIVE_LOW(gpio)	ACPI_GPIO_OUTPUT_CFG(gpio, 1)

/* Basic input GPIO with default pull settings */
#define ACPI_GPIO_INPUT_CFG(gpio, polarity) \
		ACPI_GPIO_CFG(gpio, ACPI_GPIO_IO_RESTRICT_INPUT, polarity)

#define ACPI_GPIO_INPUT(gpio)			ACPI_GPIO_INPUT_CFG(gpio, 0)
#define ACPI_GPIO_INPUT_ACTIVE_HIGH(gpio)	ACPI_GPIO_INPUT_CFG(gpio, 0)
#define ACPI_GPIO_INPUT_ACTIVE_LOW(gpio)	ACPI_GPIO_INPUT_CFG(gpio, 1)

/* GpioInt-related macros */
#define ACPI_GPIO_IRQ_CFG(_gpio, _mode, _polarity, _wake) { \
	.type = ACPI_GPIO_TYPE_INTERRUPT, \
	.pull = ACPI_GPIO_PULL_DEFAULT, \
	.irq.mode = _mode, \
	.irq.polarity = _polarity, \
	.irq.wake = _wake, \
	.pin_count = 1, \
	.pins = { (_gpio) } }

#define ACPI_GPIO_IRQ_EDGE(gpio, polarity) \
		ACPI_GPIO_IRQ_CFG(gpio, ACPI_IRQ_EDGE_TRIGGERED, polarity, 0)

#define ACPI_GPIO_IRQ_EDGE_WAKE(gpio, polarity) \
		ACPI_GPIO_IRQ_CFG(gpio, ACPI_IRQ_EDGE_TRIGGERED, polarity, ACPI_IRQ_WAKE)

#define ACPI_GPIO_IRQ_LEVEL(gpio, polarity) \
		ACPI_GPIO_IRQ_CFG(gpio, ACPI_IRQ_LEVEL_TRIGGERED, polarity, 0)

#define ACPI_GPIO_IRQ_LEVEL_WAKE(gpio, polarity) \
		ACPI_GPIO_IRQ_CFG(gpio, ACPI_IRQ_LEVEL_TRIGGERED, polarity, ACPI_IRQ_WAKE)

/* Edge Triggered Active High GPIO interrupt */
#define ACPI_GPIO_IRQ_EDGE_HIGH(gpio) \
		ACPI_GPIO_IRQ_EDGE(gpio, ACPI_IRQ_ACTIVE_HIGH)

/* Edge Triggered Active Low GPIO interrupt */
#define ACPI_GPIO_IRQ_EDGE_LOW(gpio) \
		ACPI_GPIO_IRQ_EDGE(gpio, ACPI_IRQ_ACTIVE_LOW)

/* Edge Triggered Active Both GPIO interrupt */
#define ACPI_GPIO_IRQ_EDGE_BOTH(gpio) \
		ACPI_GPIO_IRQ_EDGE(gpio, ACPI_IRQ_ACTIVE_BOTH)

/* Edge Triggered Active High GPIO interrupt with wake */
#define ACPI_GPIO_IRQ_EDGE_HIGH_WAKE(gpio) \
		ACPI_GPIO_IRQ_EDGE_WAKE(gpio, ACPI_IRQ_ACTIVE_HIGH)

/* Edge Triggered Active Low GPIO interrupt with wake */
#define ACPI_GPIO_IRQ_EDGE_LOW_WAKE(gpio) \
		ACPI_GPIO_IRQ_EDGE_WAKE(gpio, ACPI_IRQ_ACTIVE_LOW)

/* Edge Triggered Active Both GPIO interrupt with wake */
#define ACPI_GPIO_IRQ_EDGE_BOTH_WAKE(gpio) \
		ACPI_GPIO_IRQ_EDGE_WAKE(gpio, ACPI_IRQ_ACTIVE_BOTH)

/* Level Triggered Active High GPIO interrupt */
#define ACPI_GPIO_IRQ_LEVEL_HIGH(gpio) \
		ACPI_GPIO_IRQ_LEVEL(gpio, ACPI_IRQ_ACTIVE_HIGH)

/* Level Triggered Active Low GPIO interrupt */
#define ACPI_GPIO_IRQ_LEVEL_LOW(gpio) \
		ACPI_GPIO_IRQ_LEVEL(gpio, ACPI_IRQ_ACTIVE_LOW)

/* Level Triggered Active High GPIO interrupt with wake */
#define ACPI_GPIO_IRQ_LEVEL_HIGH_WAKE(gpio) \
		ACPI_GPIO_IRQ_LEVEL_WAKE(gpio, ACPI_IRQ_ACTIVE_HIGH)

/* Level Triggered Active Low GPIO interrupt with wake */
#define ACPI_GPIO_IRQ_LEVEL_LOW_WAKE(gpio) \
		ACPI_GPIO_IRQ_LEVEL_WAKE(gpio, ACPI_IRQ_ACTIVE_LOW)

/* Write GpioIo() or GpioInt() descriptor to SSDT AML output */
void acpi_device_write_gpio(const struct acpi_gpio *gpio);

/*
 * ACPI Descriptors for Serial Bus interfaces
 */

#define ACPI_SERIAL_BUS_TYPE_I2C		1
#define ACPI_SERIAL_BUS_TYPE_SPI		2
#define ACPI_SERIAL_BUS_TYPE_UART		3

#define ACPI_I2C_SERIAL_BUS_REVISION_ID		1 /* TODO: upgrade to 2 */
#define ACPI_I2C_TYPE_SPECIFIC_REVISION_ID	1
#define ACPI_SPI_SERIAL_BUS_REVISION_ID		1
#define ACPI_SPI_TYPE_SPECIFIC_REVISION_ID	1
#define ACPI_UART_SERIAL_BUS_REVISION_ID	1
#define ACPI_UART_TYPE_SPECIFIC_REVISION_ID	1

/*
 * ACPI I2C Bus
 */

struct acpi_i2c {
	/* I2C Address */
	uint16_t address;
	/* 7 or 10 bit Address Mode */
	enum i2c_address_mode mode_10bit;
	/* I2C Bus Speed in Hz */
	enum i2c_speed speed;
	/* Reference to I2C controller */
	const char *resource;
};

/* Write I2cSerialBus() descriptor to SSDT AML output */
void acpi_device_write_i2c(const struct acpi_i2c *i2c);

/*
 * ACPI SPI Bus
 */

struct acpi_spi {
	/* Device selection */
	uint16_t device_select;
	/* Device selection line is active high or low */
	enum spi_polarity device_select_polarity;
	/* 3 or 4 wire SPI connection */
	enum spi_wire_mode wire_mode;
	/* Connection speed in HZ */
	unsigned int speed;
	/* Size in bits of smallest transfer unit */
	u8 data_bit_length;
	/* Phase of clock pulse on which to capture data */
	enum spi_clock_phase clock_phase;
	/* Indicate if clock is high or low during first phase */
	enum spi_polarity clock_polarity;
	/* Reference to SPI controller */
	const char *resource;
};

/* Write SPI Bus descriptor to SSDT AML output */
void acpi_device_write_spi(const struct acpi_spi *spi);

/*
 * ACPI UART Bus
 */

enum acpi_uart_data_bits {
	ACPI_UART_DATA_BITS_5,
	ACPI_UART_DATA_BITS_6,
	ACPI_UART_DATA_BITS_7,
	ACPI_UART_DATA_BITS_8,
	ACPI_UART_DATA_BITS_9
};

enum acpi_uart_stop_bits {
	ACPI_UART_STOP_BITS_0,
	ACPI_UART_STOP_BITS_1,
	ACPI_UART_STOP_BITS_1_5,
	ACPI_UART_STOP_BITS_2
};

enum acpi_uart_lines {
	ACPI_UART_LINE_DTD = BIT(2),	/* Data Carrier Detect */
	ACPI_UART_LINE_RI = BIT(3),	/* Ring Indicator */
	ACPI_UART_LINE_DSR = BIT(4),	/* Data Set Ready */
	ACPI_UART_LINE_DTR = BIT(5),	/* Data Terminal Ready */
	ACPI_UART_LINE_CTS = BIT(6),	/* Clear to Send */
	ACPI_UART_LINE_RTS = BIT(7)	/* Request to Send */
};

enum acpi_uart_endian {
	ACPI_UART_ENDIAN_LITTLE,
	ACPI_UART_ENDIAN_BIG
};

enum acpi_uart_parity {
	ACPI_UART_PARITY_NONE,
	ACPI_UART_PARITY_EVEN,
	ACPI_UART_PARITY_ODD,
	ACPI_UART_PARITY_MARK,
	ACPI_UART_PARITY_SPACE
};

enum acpi_uart_flow_control {
	ACPI_UART_FLOW_NONE,
	ACPI_UART_FLOW_HARDWARE,
	ACPI_UART_FLOW_SOFTWARE
};

struct acpi_uart {
	/* Initial Baud Rate in bits per second */
	uint32_t initial_baud_rate;
	/* Number of bits of data in a packet (value between 5-9) */
	enum acpi_uart_data_bits data_bits;
	/* Number of bits to signal end of packet */
	enum acpi_uart_stop_bits stop_bits;
	/* Bitmask indicating presence or absence of particular line */
	unsigned int lines_in_use;
	/* Specify if the device expects big or little endian format */
	enum acpi_uart_endian endian;
	/* Specify the type of parity bits included after the data in a packet */
	enum acpi_uart_parity parity;
	/* Specify the flow control method */
	enum acpi_uart_flow_control flow_control;
	/* Upper limit in bytes of the buffer sizes for this device */
	uint16_t rx_fifo_bytes;
	uint16_t tx_fifo_bytes;
	/* Set true if UART is shared, false if it is exclusive for one device */
	bool shared;
	/* Reference to UART controller */
	const char *resource;
};

#define ACPI_UART_RAW_DEVICE(baud_rate, fifo_bytes) { \
	.initial_baud_rate = (baud_rate), \
	.data_bits = ACPI_UART_DATA_BITS_8, \
	.stop_bits = ACPI_UART_STOP_BITS_1, \
	.endian = ACPI_UART_ENDIAN_LITTLE, \
	.parity = ACPI_UART_PARITY_NONE, \
	.flow_control = ACPI_UART_FLOW_NONE, \
	.rx_fifo_bytes = (fifo_bytes), \
	.tx_fifo_bytes = (fifo_bytes), \
	.shared = false }

/* Write UARTSerialBusV2() descriptor to SSDT AML output */
void acpi_device_write_uart(const struct acpi_uart *uart);

/* GPIO/timing information for the power on/off sequences */
struct acpi_power_res_params {
	/* GPIO used to take device out of reset or to put it into reset. */
	struct acpi_gpio *reset_gpio;
	/* Delay to be inserted after device is taken out of reset.
	 * (_ON method delay)
	 */
	unsigned int reset_delay_ms;
	/* Delay to be inserted after device is put into reset.
	 * (_OFF method delay)
	 */
	unsigned int reset_off_delay_ms;
	/* GPIO used to enable device. */
	struct acpi_gpio *enable_gpio;
	/* Delay to be inserted after device is enabled.
	 * (_ON method delay)
	 */
	unsigned int enable_delay_ms;
	/* Delay to be inserted after device is disabled.
	 * (_OFF method delay)
	 */
	unsigned int enable_off_delay_ms;
	/* GPIO used to stop operation of device. */
	struct acpi_gpio *stop_gpio;
	/* Delay to be inserted after disabling stop.
	 * (_ON method delay)
	 */
	unsigned int stop_delay_ms;
	/* Delay to be inserted after enabling stop.
	 * (_OFF method delay)
	 */
	unsigned int stop_off_delay_ms;

	/* Write a _STA method that uses the state of the GPIOs to determine if
	 * the PowerResource is ON or OFF. If this is false, the _STA method
	 * will always return ON.
	 */
	bool use_gpio_for_status;
};

/*
 * Add a basic PowerResource block for a device that includes
 * GPIOs to control enable, reset and stop operation of the device. Each
 * GPIO is optional, but at least one must be provided.
 *
 * Reset - Put the device into / take the device out of reset.
 * Enable - Enable / disable power to device.
 * Stop - Stop / start operation of device.
 */
void acpi_device_add_power_res(const struct acpi_power_res_params *params);

/*
 * Writing Device Properties objects via _DSD
 *
 * http://uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf
 * http://uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.pdf
 *
 * The Device Property Hierarchy can be multiple levels deep with multiple
 * children possible in each level.  In order to support this flexibility
 * the device property hierarchy must be built up before being written out.
 *
 * For example:
 *
 * // Child table with string and integer
 * struct acpi_dp *child = acpi_dp_new_table("CHLD");
 * acpi_dp_add_string(child, "childstring", "CHILD");
 * acpi_dp_add_integer(child, "childint", 100);
 *
 * // _DSD table with integer and gpio and child pointer
 * struct acpi_dp *dsd = acpi_dp_new_table("_DSD");
 * acpi_dp_add_integer(dsd, "number1", 1);
 * acpi_dp_add_gpio(dsd, "gpio", "\_SB.PCI0.GPIO", 0, 0, 1);
 * acpi_dp_add_child(dsd, "child", child);
 *
 * // Write entries into SSDT and clean up resources
 * acpi_dp_write(dsd);
 *
 * Name(_DSD, Package() {
 *   ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301")
 *   Package() {
 *     Package() { "gpio", Package() { \_SB.PCI0.GPIO, 0, 0, 0 } }
 *     Package() { "number1", 1 }
 *   }
 *   ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b")
 *   Package() {
 *     Package() { "child", CHLD }
 *   }
 * }
 * Name(CHLD, Package() {
 *   ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301")
 *   Package() {
 *     Package() { "childstring", "CHILD" }
 *     Package() { "childint", 100 }
 *   }
 * }
 */

/* Start a new Device Property table with provided ACPI reference */
struct acpi_dp *acpi_dp_new_table(const char *ref);

/* Add package of device properties with a unique UUID */
struct acpi_dp *acpi_dp_add_package(struct acpi_dp *dp, struct acpi_dp *package);

/* Add integer Device Property */
struct acpi_dp *acpi_dp_add_integer(struct acpi_dp *dp, const char *name,
				    uint64_t value);

/* Add string Device Property */
struct acpi_dp *acpi_dp_add_string(struct acpi_dp *dp, const char *name,
				   const char *string);

/* Add ACPI reference Device Property */
struct acpi_dp *acpi_dp_add_reference(struct acpi_dp *dp, const char *name,
				      const char *reference);

/* Add an array of Device Properties */
struct acpi_dp *acpi_dp_add_array(struct acpi_dp *dp, struct acpi_dp *array);

/* Add an array of integers Device Property */
struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
					  const uint64_t *array, int len);

/* Add a GPIO binding Device Property */
struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
				 const char *ref, int index, int pin,
				 int active_low);

struct acpi_gpio_res_params {
	/* Reference to the parent device. */
	const char *ref;
	/* Index to the GpioIo resource within the _CRS. */
	int index;
	/* Index to the pin within the GpioIo resource, usually 0. */
	int pin;
	/* Flag to indicate if pin is active low. */
	int active_low;
};

/* Add a GPIO binding device property for array of GPIOs */
struct acpi_dp *acpi_dp_add_gpio_array(struct acpi_dp *dp, const char *name,
				       const struct acpi_gpio_res_params *params,
				       size_t param_count);

/* Add a child table of Device Properties */
struct acpi_dp *acpi_dp_add_child(struct acpi_dp *dp, const char *name,
				  struct acpi_dp *child);

/* Add a list of Device Properties, returns the number of properties added */
size_t acpi_dp_add_property_list(struct acpi_dp *dp,
				 const struct acpi_dp *property_list,
				 size_t property_count);

/* Write Device Property hierarchy and clean up resources */
void acpi_dp_write(struct acpi_dp *table);

/*
 * Helper function to write a PCI device with _ADR object defined.
 *
 * IMPORTANT: Scope of a device created in SSDT cannot be used to add ACPI nodes under that
 * scope in DSDT. So, if there are any references to this PCI device scope required from static
 * asl files, do not use this function and instead add the device to DSDT as well.
 */
void acpi_device_write_pci_dev(const struct device *dev);

#endif /* __ACPI_ACPI_DEVICE_H__ */
