Commit d3eaf587 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branch 'device-properties'

* device-properties:
  leds: leds-gpio: Fix multiple instances registration without 'label' property
  leds: leds-gpio: Fix legacy GPIO number case
  ACPI / property: Drop size_prop from acpi_dev_get_property_reference()
  leds: leds-gpio: Convert gpio_blink_set() to use GPIO descriptors
  ACPI / GPIO: Document ACPI GPIO mappings API
  net: rfkill: gpio: Add default GPIO driver mappings for ACPI
  ACPI / GPIO: Driver GPIO mappings for ACPI GPIOs
  input: gpio_keys_polled: Make use of device property API
  leds: leds-gpio: Make use of device property API
  gpio: Support for unified device properties interface
  Driver core: Unified interface for firmware node properties
  input: gpio_keys_polled: Add support for GPIO descriptors
  leds: leds-gpio: Add support for GPIO descriptors
  gpio: sch: Consolidate core and resume banks
  gpio / ACPI: Add support for _DSD device properties
  misc: at25: Make use of device property API
  ACPI: Allow drivers to match using Device Tree compatible property
  Driver core: Unified device properties interface for platform firmware
  ACPI: Add support for device specific properties
parents b2776bf7 29470ea8
_DSD Device Properties Related to GPIO
--------------------------------------
With the release of ACPI 5.1 and the _DSD configuration objecte names
can finally be given to GPIOs (and other things as well) returned by
_CRS. Previously, we were only able to use an integer index to find
the corresponding GPIO, which is pretty error prone (it depends on
the _CRS output ordering, for example).
With _DSD we can now query GPIOs using a name instead of an integer
index, like the ASL example below shows:
// Bluetooth device with reset and shutdown GPIOs
Device (BTH)
{
Name (_HID, ...)
Name (_CRS, ResourceTemplate ()
{
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
"\\_SB.GPO0", 0, ResourceConsumer) {15}
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
"\\_SB.GPO0", 0, ResourceConsumer) {27, 31}
})
Name (_DSD, Package ()
{
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package ()
{
Package () {"reset-gpio", Package() {^BTH, 1, 1, 0 }},
Package () {"shutdown-gpio", Package() {^BTH, 0, 0, 0 }},
}
})
}
The format of the supported GPIO property is:
Package () { "name", Package () { ref, index, pin, active_low }}
ref - The device that has _CRS containing GpioIo()/GpioInt() resources,
typically this is the device itself (BTH in our case).
index - Index of the GpioIo()/GpioInt() resource in _CRS starting from zero.
pin - Pin in the GpioIo()/GpioInt() resource. Typically this is zero.
active_low - If 1 the GPIO is marked as active_low.
Since ACPI GpioIo() resource does not have a field saying whether it is
active low or high, the "active_low" argument can be used here. Setting
it to 1 marks the GPIO as active low.
In our Bluetooth example the "reset-gpio" refers to the second GpioIo()
resource, second pin in that resource with the GPIO number of 31.
ACPI GPIO Mappings Provided by Drivers
--------------------------------------
There are systems in which the ACPI tables do not contain _DSD but provide _CRS
with GpioIo()/GpioInt() resources and device drivers still need to work with
them.
In those cases ACPI device identification objects, _HID, _CID, _CLS, _SUB, _HRV,
available to the driver can be used to identify the device and that is supposed
to be sufficient to determine the meaning and purpose of all of the GPIO lines
listed by the GpioIo()/GpioInt() resources returned by _CRS. In other words,
the driver is supposed to know what to use the GpioIo()/GpioInt() resources for
once it has identified the device. Having done that, it can simply assign names
to the GPIO lines it is going to use and provide the GPIO subsystem with a
mapping between those names and the ACPI GPIO resources corresponding to them.
To do that, the driver needs to define a mapping table as a NULL-terminated
array of struct acpi_gpio_mapping objects that each contain a name, a pointer
to an array of line data (struct acpi_gpio_params) objects and the size of that
array. Each struct acpi_gpio_params object consists of three fields,
crs_entry_index, line_index, active_low, representing the index of the target
GpioIo()/GpioInt() resource in _CRS starting from zero, the index of the target
line in that resource starting from zero, and the active-low flag for that line,
respectively, in analogy with the _DSD GPIO property format specified above.
For the example Bluetooth device discussed previously the data structures in
question would look like this:
static const struct acpi_gpio_params reset_gpio = { 1, 1, false };
static const struct acpi_gpio_params shutdown_gpio = { 0, 0, false };
static const struct acpi_gpio_mapping bluetooth_acpi_gpios[] = {
{ "reset-gpio", &reset_gpio, 1 },
{ "shutdown-gpio", &shutdown_gpio, 1 },
{ },
};
Next, the mapping table needs to be passed as the second argument to
acpi_dev_add_driver_gpios() that will register it with the ACPI device object
pointed to by its first argument. That should be done in the driver's .probe()
routine. On removal, the driver should unregister its GPIO mapping table by
calling acpi_dev_remove_driver_gpios() on the ACPI device object where that
table was previously registered.
......@@ -219,6 +219,24 @@ part of the IRQ interface, e.g. IRQF_TRIGGER_FALLING, as are system wakeup
capabilities.
GPIOs and ACPI
==============
On ACPI systems, GPIOs are described by GpioIo()/GpioInt() resources listed by
the _CRS configuration objects of devices. Those resources do not provide
connection IDs (names) for GPIOs, so it is necessary to use an additional
mechanism for this purpose.
Systems compliant with ACPI 5.1 or newer may provide a _DSD configuration object
which, among other things, may be used to provide connection IDs for specific
GPIOs described by the GpioIo()/GpioInt() resources in _CRS. If that is the
case, it will be handled by the GPIO subsystem automatically. However, if the
_DSD is not present, the mappings between GpioIo()/GpioInt() resources and GPIO
connection IDs need to be provided by device drivers.
For details refer to Documentation/acpi/gpio-properties.txt
Interacting With the Legacy GPIO Subsystem
==========================================
Many kernel subsystems still handle GPIOs using the legacy integer-based
......
......@@ -41,7 +41,7 @@ static void h1940bt_enable(int on)
mdelay(10);
gpio_set_value(S3C2410_GPH(1), 0);
h1940_led_blink_set(-EINVAL, GPIO_LED_BLINK, NULL, NULL);
h1940_led_blink_set(NULL, GPIO_LED_BLINK, NULL, NULL);
}
else {
gpio_set_value(S3C2410_GPH(1), 1);
......@@ -50,7 +50,7 @@ static void h1940bt_enable(int on)
mdelay(10);
gpio_set_value(H1940_LATCH_BLUETOOTH_POWER, 0);
h1940_led_blink_set(-EINVAL, GPIO_LED_NO_BLINK_LOW, NULL, NULL);
h1940_led_blink_set(NULL, GPIO_LED_NO_BLINK_LOW, NULL, NULL);
}
}
......
......@@ -19,8 +19,10 @@
#define H1940_SUSPEND_RESUMEAT (0x30081000)
#define H1940_SUSPEND_CHECK (0x30080000)
struct gpio_desc;
extern void h1940_pm_return(void);
extern int h1940_led_blink_set(unsigned gpio, int state,
extern int h1940_led_blink_set(struct gpio_desc *desc, int state,
unsigned long *delay_on,
unsigned long *delay_off);
......
......@@ -359,10 +359,11 @@ static struct platform_device h1940_battery = {
static DEFINE_SPINLOCK(h1940_blink_spin);
int h1940_led_blink_set(unsigned gpio, int state,
int h1940_led_blink_set(struct gpio_desc *desc, int state,
unsigned long *delay_on, unsigned long *delay_off)
{
int blink_gpio, check_gpio1, check_gpio2;
int gpio = desc ? desc_to_gpio(desc) : -EINVAL;
switch (gpio) {
case H1940_LATCH_LED_GREEN:
......
......@@ -250,9 +250,10 @@ static void rx1950_disable_charger(void)
static DEFINE_SPINLOCK(rx1950_blink_spin);
static int rx1950_led_blink_set(unsigned gpio, int state,
static int rx1950_led_blink_set(struct gpio_desc *desc, int state,
unsigned long *delay_on, unsigned long *delay_off)
{
int gpio = desc_to_gpio(desc);
int blink_gpio, check_gpio;
switch (gpio) {
......
......@@ -306,9 +306,10 @@ EXPORT_SYMBOL(orion_gpio_set_blink);
#define ORION_BLINK_HALF_PERIOD 100 /* ms */
int orion_gpio_led_blink_set(unsigned gpio, int state,
int orion_gpio_led_blink_set(struct gpio_desc *desc, int state,
unsigned long *delay_on, unsigned long *delay_off)
{
unsigned gpio = desc_to_gpio(desc);
if (delay_on && delay_off && !*delay_on && !*delay_off)
*delay_on = *delay_off = ORION_BLINK_HALF_PERIOD;
......
......@@ -14,12 +14,15 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/irqdomain.h>
struct gpio_desc;
/*
* Orion-specific GPIO API extensions.
*/
void orion_gpio_set_unused(unsigned pin);
void orion_gpio_set_blink(unsigned pin, int blink);
int orion_gpio_led_blink_set(unsigned gpio, int state,
int orion_gpio_led_blink_set(struct gpio_desc *desc, int state,
unsigned long *delay_on, unsigned long *delay_off);
#define GPIO_INPUT_OK (1 << 0)
......
......@@ -47,6 +47,7 @@ acpi-y += int340x_thermal.o
acpi-y += power.o
acpi-y += event.o
acpi-y += sysfs.o
acpi-y += property.o
acpi-$(CONFIG_X86) += acpi_cmos_rtc.o
acpi-$(CONFIG_DEBUG_FS) += debugfs.o
acpi-$(CONFIG_ACPI_NUMA) += numa.o
......
......@@ -173,4 +173,10 @@ static inline void suspend_nvs_restore(void) {}
bool acpi_osi_is_win8(void);
#endif
/*--------------------------------------------------------------------------
Device properties
-------------------------------------------------------------------------- */
void acpi_init_properties(struct acpi_device *adev);
void acpi_free_properties(struct acpi_device *adev);
#endif /* _ACPI_INTERNAL_H_ */
This diff is collapsed.
......@@ -124,17 +124,56 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
if (list_empty(&acpi_dev->pnp.ids))
return 0;
len = snprintf(modalias, size, "acpi:");
size -= len;
list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
count = snprintf(&modalias[len], size, "%s:", id->id);
if (count < 0)
return -EINVAL;
if (count >= size)
return -ENOMEM;
len += count;
size -= count;
/*
* If the device has PRP0001 we expose DT compatible modalias
* instead in form of of:NnameTCcompatible.
*/
if (acpi_dev->data.of_compatible) {
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
const union acpi_object *of_compatible, *obj;
int i, nval;
char *c;
acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
/* DT strings are all in lower case */
for (c = buf.pointer; *c != '\0'; c++)
*c = tolower(*c);
len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
ACPI_FREE(buf.pointer);
of_compatible = acpi_dev->data.of_compatible;
if (of_compatible->type == ACPI_TYPE_PACKAGE) {
nval = of_compatible->package.count;
obj = of_compatible->package.elements;
} else { /* Must be ACPI_TYPE_STRING. */
nval = 1;
obj = of_compatible;
}
for (i = 0; i < nval; i++, obj++) {
count = snprintf(&modalias[len], size, "C%s",
obj->string.pointer);
if (count < 0)
return -EINVAL;
if (count >= size)
return -ENOMEM;
len += count;
size -= count;
}
} else {
len = snprintf(modalias, size, "acpi:");
size -= len;
list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
count = snprintf(&modalias[len], size, "%s:", id->id);
if (count < 0)
return -EINVAL;
if (count >= size)
return -ENOMEM;
len += count;
size -= count;
}
}
modalias[len] = '\0';
......@@ -902,6 +941,51 @@ int acpi_match_device_ids(struct acpi_device *device,
}
EXPORT_SYMBOL(acpi_match_device_ids);
/* Performs match against special "PRP0001" shoehorn ACPI ID */
static bool acpi_of_driver_match_device(struct device *dev,
const struct device_driver *drv)
{
const union acpi_object *of_compatible, *obj;
struct acpi_device *adev;
int i, nval;
adev = ACPI_COMPANION(dev);
if (!adev)
return false;
of_compatible = adev->data.of_compatible;
if (!drv->of_match_table || !of_compatible)
return false;
if (of_compatible->type == ACPI_TYPE_PACKAGE) {
nval = of_compatible->package.count;
obj = of_compatible->package.elements;
} else { /* Must be ACPI_TYPE_STRING. */
nval = 1;
obj = of_compatible;
}
/* Now we can look for the driver DT compatible strings */
for (i = 0; i < nval; i++, obj++) {
const struct of_device_id *id;
for (id = drv->of_match_table; id->compatible[0]; id++)
if (!strcasecmp(obj->string.pointer, id->compatible))
return true;
}
return false;
}
bool acpi_driver_match_device(struct device *dev,
const struct device_driver *drv)
{
if (!drv->acpi_match_table)
return acpi_of_driver_match_device(dev, drv);
return !!acpi_match_device(drv->acpi_match_table, dev);
}
EXPORT_SYMBOL_GPL(acpi_driver_match_device);
static void acpi_free_power_resources_lists(struct acpi_device *device)
{
int i;
......@@ -922,6 +1006,7 @@ static void acpi_device_release(struct device *dev)
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
acpi_free_properties(acpi_dev);
acpi_free_pnp_ids(&acpi_dev->pnp);
acpi_free_power_resources_lists(acpi_dev);
kfree(acpi_dev);
......@@ -1304,6 +1389,26 @@ int acpi_device_add(struct acpi_device *device,
return result;
}
struct acpi_device *acpi_get_next_child(struct device *dev,
struct acpi_device *child)
{
struct acpi_device *adev = ACPI_COMPANION(dev);
struct list_head *head, *next;
if (!adev)
return NULL;
head = &adev->children;
if (list_empty(head))
return NULL;
if (!child)
return list_first_entry(head, struct acpi_device, node);
next = child->node.next;
return next == head ? NULL : list_entry(next, struct acpi_device, node);
}
/* --------------------------------------------------------------------------
Driver Management
-------------------------------------------------------------------------- */
......@@ -1923,9 +2028,11 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
device->device_type = type;
device->handle = handle;
device->parent = acpi_bus_get_parent(handle);
device->fwnode.type = FWNODE_ACPI;
acpi_set_device_status(device, sta);
acpi_device_get_busid(device);
acpi_set_pnp_ids(handle, &device->pnp, type);
acpi_init_properties(device);
acpi_bus_get_flags(device);
device->flags.match_driver = false;
device->flags.initialized = true;
......
......@@ -4,7 +4,7 @@ obj-y := component.o core.o bus.o dd.o syscore.o \
driver.o class.o platform.o \
cpu.o firmware.o init.o map.o devres.o \
attribute_container.o transport_class.o \
topology.o container.o
topology.o container.o property.o
obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
obj-y += power/
......
This diff is collapsed.
......@@ -108,6 +108,38 @@ struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev,
}
EXPORT_SYMBOL(__devm_gpiod_get_index);
/**
* devm_get_gpiod_from_child - get a GPIO descriptor from a device's child node
* @dev: GPIO consumer
* @child: firmware node (child of @dev)
*
* GPIO descriptors returned from this function are automatically disposed on
* driver detach.
*/
struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
struct fwnode_handle *child)
{
struct gpio_desc **dr;
struct gpio_desc *desc;
dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
GFP_KERNEL);
if (!dr)
return ERR_PTR(-ENOMEM);
desc = fwnode_get_named_gpiod(child, "gpios");
if (IS_ERR(desc)) {
devres_free(dr);
return desc;
}
*dr = desc;
devres_add(dev, dr);
return desc;
}
EXPORT_SYMBOL(devm_get_gpiod_from_child);
/**
* devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional()
* @dev: GPIO consumer
......
This diff is collapsed.
......@@ -287,9 +287,45 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
}
}
int acpi_dev_add_driver_gpios(struct acpi_device *adev,
const struct acpi_gpio_mapping *gpios)
{
if (adev && gpios) {
adev->driver_gpios = gpios;
return 0;
}
return -EINVAL;
}
EXPORT_SYMBOL_GPL(acpi_dev_add_driver_gpios);
static bool acpi_get_driver_gpio_data(struct acpi_device *adev,
const char *name, int index,
struct acpi_reference_args *args)
{
const struct acpi_gpio_mapping *gm;
if (!adev->driver_gpios)
return false;
for (gm = adev->driver_gpios; gm->name; gm++)
if (!strcmp(name, gm->name) && gm->data && index < gm->size) {
const struct acpi_gpio_params *par = gm->data + index;
args->adev = adev;
args->args[0] = par->crs_entry_index;
args->args[1] = par->line_index;
args->args[2] = par->active_low;
args->nargs = 3;
return true;
}
return false;
}
struct acpi_gpio_lookup {
struct acpi_gpio_info info;
int index;
int pin_index;
struct gpio_desc *desc;
int n;
};
......@@ -303,13 +339,24 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data)
if (lookup->n++ == lookup->index && !lookup->desc) {
const struct acpi_resource_gpio *agpio = &ares->data.gpio;
int pin_index = lookup->pin_index;
if (pin_index >= agpio->pin_table_length)
return 1;
lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
agpio->pin_table[0]);
agpio->pin_table[pin_index]);
lookup->info.gpioint =
agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT;
lookup->info.active_low =
agpio->polarity == ACPI_ACTIVE_LOW;
/*
* ActiveLow is only specified for GpioInt resource. If
* GpioIo is used then the only way to set the flag is
* to use _DSD "gpios" property.
*/
if (lookup->info.gpioint)
lookup->info.active_low =
agpio->polarity == ACPI_ACTIVE_LOW;
}
return 1;
......@@ -317,40 +364,79 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data)
/**
* acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources
* @dev: pointer to a device to get GPIO from
* @adev: pointer to a ACPI device to get GPIO from
* @propname: Property name of the GPIO (optional)
* @index: index of GpioIo/GpioInt resource (starting from %0)
* @info: info pointer to fill in (optional)
*
* Function goes through ACPI resources for @dev and based on @index looks
* Function goes through ACPI resources for @adev and based on @index looks
* up a GpioIo/GpioInt resource, translates it to the Linux GPIO descriptor,
* and returns it. @index matches GpioIo/GpioInt resources only so if there
* are total %3 GPIO resources, the index goes from %0 to %2.
*
* If @propname is specified the GPIO is looked using device property. In
* that case @index is used to select the GPIO entry in the property value
* (in case of multiple).
*
* If the GPIO cannot be translated or there is an error an ERR_PTR is
* returned.
*
* Note: if the GPIO resource has multiple entries in the pin list, this
* function only returns the first.
*/
struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
const char *propname, int index,
struct acpi_gpio_info *info)
{
struct acpi_gpio_lookup lookup;
struct list_head resource_list;
struct acpi_device *adev;
acpi_handle handle;
bool active_low = false;
int ret;
if (!dev)
return ERR_PTR(-EINVAL);
handle = ACPI_HANDLE(dev);
if (!handle || acpi_bus_get_device(handle, &adev))
if (!adev)
return ERR_PTR(-ENODEV);
memset(&lookup, 0, sizeof(lookup));
lookup.index = index;
if (propname) {
struct acpi_reference_args args;
dev_dbg(&adev->dev, "GPIO: looking up %s\n", propname);
memset(&args, 0, sizeof(args));
ret = acpi_dev_get_property_reference(adev, propname,
index, &args);
if (ret) {
bool found = acpi_get_driver_gpio_data(adev, propname,
index, &args);
if (!found)
return ERR_PTR(ret);
}
/*
* The property was found and resolved so need to
* lookup the GPIO based on returned args instead.
*/
adev = args.adev;
if (args.nargs >= 2) {
lookup.index = args.args[0];
lookup.pin_index = args.args[1];
/*
* 3rd argument, if present is used to
* specify active_low.
*/
if (args.nargs >= 3)
active_low = !!args.args[2];
}
dev_dbg(&adev->dev, "GPIO: _DSD returned %s %zd %llu %llu %llu\n",
dev_name(&adev->dev), args.nargs,
args.args[0], args.args[1], args.args[2]);
} else {
dev_dbg(&adev->dev, "GPIO: looking up %d in _CRS\n", index);
}
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio,
&lookup);
......@@ -359,8 +445,11 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
acpi_dev_free_resource_list(&resource_list);
if (lookup.desc && info)
if (lookup.desc && info) {
*info = lookup.info;
if (active_low)
info->active_low = active_low;
}
return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT);
}
......
......@@ -1505,14 +1505,36 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
unsigned int idx,
enum gpio_lookup_flags *flags)
{
static const char * const suffixes[] = { "gpios", "gpio" };
struct acpi_device *adev = ACPI_COMPANION(dev);
struct acpi_gpio_info info;
struct gpio_desc *desc;
char propname[32];
int i;
desc = acpi_get_gpiod_by_index(dev, idx, &info);
if (IS_ERR(desc))
return desc;
/* Try first from _DSD */
for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
if (con_id && strcmp(con_id, "gpios")) {
snprintf(propname, sizeof(propname), "%s-%s",
con_id, suffixes[i]);
} else {
snprintf(propname, sizeof(propname), "%s",
suffixes[i]);
}
desc = acpi_get_gpiod_by_index(adev, propname, idx, &info);
if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER))
break;
}
if (info.gpioint && info.active_low)
/* Then from plain _CRS GPIOs */
if (IS_ERR(desc)) {
desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
if (IS_ERR(desc))
return desc;
}
if (info.active_low)
*flags |= GPIO_ACTIVE_LOW;
return desc;
......@@ -1712,6 +1734,61 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,
}
EXPORT_SYMBOL_GPL(__gpiod_get_index);
/**
* fwnode_get_named_gpiod - obtain a GPIO from firmware node
* @fwnode: handle of the firmware node
* @propname: name of the firmware property representing the GPIO
*
* This function can be used for drivers that get their configuration
* from firmware.
*
* Function properly finds the corresponding GPIO using whatever is the
* underlying firmware interface and then makes sure that the GPIO
* descriptor is requested before it is returned to the caller.
*
* In case of error an ERR_PTR() is returned.
*/
struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
const char *propname)
{
struct gpio_desc *desc = ERR_PTR(-ENODEV);
bool active_low = false;
int ret;
if (!fwnode)
return ERR_PTR(-EINVAL);
if (is_of_node(fwnode)) {
enum of_gpio_flags flags;
desc = of_get_named_gpiod_flags(of_node(fwnode), propname, 0,
&flags);
if (!IS_ERR(desc))
active_low = flags & OF_GPIO_ACTIVE_LOW;
} else if (is_acpi_node(fwnode)) {
struct acpi_gpio_info info;
desc = acpi_get_gpiod_by_index(acpi_node(fwnode), propname, 0,
&info);
if (!IS_ERR(desc))
active_low = info.active_low;
}
if (IS_ERR(desc))
return desc;
ret = gpiod_request(desc, NULL);
if (ret)
return ERR_PTR(ret);
/* Only value flag can be set from both DT and ACPI is active_low */
if (active_low)
set_bit(FLAG_ACTIVE_LOW, &desc->flags);
return desc;
}
EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod);
/**
* gpiod_get_index_optional - obtain an optional GPIO from a multi-index GPIO
* function
......
......@@ -34,7 +34,8 @@ void acpi_gpiochip_remove(struct gpio_chip *chip);
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
const char *propname, int index,
struct acpi_gpio_info *info);
#else
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
......@@ -47,8 +48,8 @@ static inline void
acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }
static inline struct gpio_desc *
acpi_get_gpiod_by_index(struct device *dev, int index,
struct acpi_gpio_info *info)
acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname,
int index, struct acpi_gpio_info *info)
{
return ERR_PTR(-ENOSYS);
}
......
......@@ -23,10 +23,9 @@
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/property.h>
#define DRV_NAME "gpio-keys-polled"
......@@ -51,15 +50,14 @@ static void gpio_keys_polled_check_state(struct input_dev *input,
int state;
if (bdata->can_sleep)
state = !!gpio_get_value_cansleep(button->gpio);
state = !!gpiod_get_value_cansleep(button->gpiod);
else
state = !!gpio_get_value(button->gpio);
state = !!gpiod_get_value(button->gpiod);
if (state != bdata->last_state) {
unsigned int type = button->type ?: EV_KEY;
input_event(input, type, button->code,
!!(state ^ button->active_low));
input_event(input, type, button->code, state);
input_sync(input);
bdata->count = 0;
bdata->last_state = state;
......@@ -102,21 +100,15 @@ static void gpio_keys_polled_close(struct input_polled_dev *dev)
pdata->disable(bdev->dev);
}
#ifdef CONFIG_OF
static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct device *dev)
{
struct device_node *node, *pp;
struct gpio_keys_platform_data *pdata;
struct gpio_keys_button *button;
struct fwnode_handle *child;
int error;
int nbuttons;
int i;
node = dev->of_node;
if (!node)
return NULL;
nbuttons = of_get_child_count(node);
nbuttons = device_get_child_node_count(dev);
if (nbuttons == 0)
return NULL;
......@@ -126,52 +118,44 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
return ERR_PTR(-ENOMEM);
pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
pdata->nbuttons = nbuttons;
pdata->rep = !!of_get_property(node, "autorepeat", NULL);
of_property_read_u32(node, "poll-interval", &pdata->poll_interval);
pdata->rep = device_property_present(dev, "autorepeat");
device_property_read_u32(dev, "poll-interval", &pdata->poll_interval);
i = 0;
for_each_child_of_node(node, pp) {
int gpio;
enum of_gpio_flags flags;
device_for_each_child_node(dev, child) {
struct gpio_desc *desc;
if (!of_find_property(pp, "gpios", NULL)) {
pdata->nbuttons--;
dev_warn(dev, "Found button without gpios\n");
continue;
}
gpio = of_get_gpio_flags(pp, 0, &flags);
if (gpio < 0) {
error = gpio;
desc = devm_get_gpiod_from_child(dev, child);
if (IS_ERR(desc)) {
error = PTR_ERR(desc);
if (error != -EPROBE_DEFER)
dev_err(dev,
"Failed to get gpio flags, error: %d\n",
error);
fwnode_handle_put(child);
return ERR_PTR(error);
}
button = &pdata->buttons[i++];
button->gpio = gpio;
button->active_low = flags & OF_GPIO_ACTIVE_LOW;
button = &pdata->buttons[pdata->nbuttons++];
button->gpiod = desc;
if (of_property_read_u32(pp, "linux,code", &button->code)) {
dev_err(dev, "Button without keycode: 0x%x\n",
button->gpio);
if (fwnode_property_read_u32(child, "linux,code", &button->code)) {
dev_err(dev, "Button without keycode: %d\n",
pdata->nbuttons - 1);
fwnode_handle_put(child);
return ERR_PTR(-EINVAL);
}
button->desc = of_get_property(pp, "label", NULL);
fwnode_property_read_string(child, "label", &button->desc);
if (of_property_read_u32(pp, "linux,input-type", &button->type))
if (fwnode_property_read_u32(child, "linux,input-type",
&button->type))
button->type = EV_KEY;
button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
button->wakeup = fwnode_property_present(child, "gpio-key,wakeup");
if (of_property_read_u32(pp, "debounce-interval",
&button->debounce_interval))
if (fwnode_property_read_u32(child, "debounce-interval",
&button->debounce_interval))
button->debounce_interval = 5;
}
......@@ -187,15 +171,6 @@ static const struct of_device_id gpio_keys_polled_of_match[] = {
};
MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match);
#else
static inline struct gpio_keys_platform_data *
gpio_keys_polled_get_devtree_pdata(struct device *dev)
{
return NULL;
}
#endif
static int gpio_keys_polled_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
......@@ -259,7 +234,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
struct gpio_keys_button_data *bdata = &bdev->data[i];
unsigned int gpio = button->gpio;
unsigned int type = button->type ?: EV_KEY;
if (button->wakeup) {
......@@ -267,15 +241,31 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
return -EINVAL;
}
error = devm_gpio_request_one(&pdev->dev, gpio, GPIOF_IN,
button->desc ? : DRV_NAME);
if (error) {
dev_err(dev, "unable to claim gpio %u, err=%d\n",
gpio, error);
return error;
/*
* Legacy GPIO number so request the GPIO here and
* convert it to descriptor.
*/
if (!button->gpiod && gpio_is_valid(button->gpio)) {
unsigned flags = 0;
if (button->active_low)
flags |= GPIOF_ACTIVE_LOW;
error = devm_gpio_request_one(&pdev->dev, button->gpio,
flags, button->desc ? : DRV_NAME);
if (error) {
dev_err(dev, "unable to claim gpio %u, err=%d\n",
button->gpio, error);
return error;
}
button->gpiod = gpio_to_desc(button->gpio);
}
bdata->can_sleep = gpio_cansleep(gpio);
if (IS_ERR(button->gpiod))
return PTR_ERR(button->gpiod);
bdata->can_sleep = gpiod_cansleep(button->gpiod);
bdata->last_state = -1;
bdata->threshold = DIV_ROUND_UP(button->debounce_interval,
pdata->poll_interval);
......@@ -308,7 +298,7 @@ static struct platform_driver gpio_keys_polled_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(gpio_keys_polled_of_match),
.of_match_table = gpio_keys_polled_of_match,
},
};
module_platform_driver(gpio_keys_polled_driver);
......
......@@ -12,25 +12,23 @@
*/
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
struct gpio_led_data {
struct led_classdev cdev;
unsigned gpio;
struct gpio_desc *gpiod;
struct work_struct work;
u8 new_level;
u8 can_sleep;
u8 active_low;
u8 blinking;
int (*platform_gpio_blink_set)(unsigned gpio, int state,
int (*platform_gpio_blink_set)(struct gpio_desc *desc, int state,
unsigned long *delay_on, unsigned long *delay_off);
};
......@@ -40,12 +38,11 @@ static void gpio_led_work(struct work_struct *work)
container_of(work, struct gpio_led_data, work);
if (led_dat->blinking) {
led_dat->platform_gpio_blink_set(led_dat->gpio,
led_dat->new_level,
NULL, NULL);
led_dat->platform_gpio_blink_set(led_dat->gpiod,
led_dat->new_level, NULL, NULL);
led_dat->blinking = 0;
} else
gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
gpiod_set_value_cansleep(led_dat->gpiod, led_dat->new_level);
}
static void gpio_led_set(struct led_classdev *led_cdev,
......@@ -60,9 +57,6 @@ static void gpio_led_set(struct led_classdev *led_cdev,
else
level = 1;
if (led_dat->active_low)
level = !level;
/* Setting GPIOs with I2C/etc requires a task context, and we don't
* seem to have a reliable way to know if we're already in one; so
* let's just assume the worst.
......@@ -72,11 +66,11 @@ static void gpio_led_set(struct led_classdev *led_cdev,
schedule_work(&led_dat->work);
} else {
if (led_dat->blinking) {
led_dat->platform_gpio_blink_set(led_dat->gpio, level,
led_dat->platform_gpio_blink_set(led_dat->gpiod, level,
NULL, NULL);
led_dat->blinking = 0;
} else
gpio_set_value(led_dat->gpio, level);
gpiod_set_value(led_dat->gpiod, level);
}
}
......@@ -87,34 +81,49 @@ static int gpio_blink_set(struct led_classdev *led_cdev,
container_of(led_cdev, struct gpio_led_data, cdev);
led_dat->blinking = 1;
return led_dat->platform_gpio_blink_set(led_dat->gpio, GPIO_LED_BLINK,
return led_dat->platform_gpio_blink_set(led_dat->gpiod, GPIO_LED_BLINK,
delay_on, delay_off);
}
static int create_gpio_led(const struct gpio_led *template,
struct gpio_led_data *led_dat, struct device *parent,
int (*blink_set)(unsigned, int, unsigned long *, unsigned long *))
int (*blink_set)(struct gpio_desc *, int, unsigned long *,
unsigned long *))
{
int ret, state;
led_dat->gpio = -1;
led_dat->gpiod = template->gpiod;
if (!led_dat->gpiod) {
/*
* This is the legacy code path for platform code that
* still uses GPIO numbers. Ultimately we would like to get
* rid of this block completely.
*/
unsigned long flags = 0;
/* skip leds that aren't available */
if (!gpio_is_valid(template->gpio)) {
dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n",
template->gpio, template->name);
return 0;
}
/* skip leds that aren't available */
if (!gpio_is_valid(template->gpio)) {
dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n",
template->gpio, template->name);
return 0;
}
if (template->active_low)
flags |= GPIOF_ACTIVE_LOW;
ret = devm_gpio_request(parent, template->gpio, template->name);
if (ret < 0)
return ret;
ret = devm_gpio_request_one(parent, template->gpio, flags,
template->name);
if (ret < 0)
return ret;
led_dat->gpiod = gpio_to_desc(template->gpio);
if (IS_ERR(led_dat->gpiod))
return PTR_ERR(led_dat->gpiod);
}
led_dat->cdev.name = template->name;
led_dat->cdev.default_trigger = template->default_trigger;
led_dat->gpio = template->gpio;
led_dat->can_sleep = gpio_cansleep(template->gpio);
led_dat->active_low = template->active_low;
led_dat->can_sleep = gpiod_cansleep(led_dat->gpiod);
led_dat->blinking = 0;
if (blink_set) {
led_dat->platform_gpio_blink_set = blink_set;
......@@ -122,30 +131,24 @@ static int create_gpio_led(const struct gpio_led *template,
}
led_dat->cdev.brightness_set = gpio_led_set;
if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
state = !!gpio_get_value_cansleep(led_dat->gpio) ^ led_dat->active_low;
state = !!gpiod_get_value_cansleep(led_dat->gpiod);
else
state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
if (!template->retain_state_suspended)
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);
ret = gpiod_direction_output(led_dat->gpiod, state);
if (ret < 0)
return ret;
INIT_WORK(&led_dat->work, gpio_led_work);
ret = led_classdev_register(parent, &led_dat->cdev);
if (ret < 0)
return ret;
return 0;
return led_classdev_register(parent, &led_dat->cdev);
}
static void delete_gpio_led(struct gpio_led_data *led)
{
if (!gpio_is_valid(led->gpio))
return;
led_classdev_unregister(&led->cdev);
cancel_work_sync(&led->work);
}
......@@ -161,40 +164,47 @@ static inline int sizeof_gpio_leds_priv(int num_leds)
(sizeof(struct gpio_led_data) * num_leds);
}
/* Code to create from OpenFirmware platform devices */
#ifdef CONFIG_OF_GPIO
static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node, *child;
struct device *dev = &pdev->dev;
struct fwnode_handle *child;
struct gpio_leds_priv *priv;
int count, ret;
struct device_node *np;
/* count LEDs in this device, so we know how much to allocate */
count = of_get_available_child_count(np);
count = device_get_child_node_count(dev);
if (!count)
return ERR_PTR(-ENODEV);
for_each_available_child_of_node(np, child)
if (of_get_gpio(child, 0) == -EPROBE_DEFER)
return ERR_PTR(-EPROBE_DEFER);
priv = devm_kzalloc(&pdev->dev, sizeof_gpio_leds_priv(count),
GFP_KERNEL);
priv = devm_kzalloc(dev, sizeof_gpio_leds_priv(count), GFP_KERNEL);
if (!priv)
return ERR_PTR(-ENOMEM);
for_each_available_child_of_node(np, child) {
device_for_each_child_node(dev, child) {
struct gpio_led led = {};
enum of_gpio_flags flags;
const char *state;
led.gpio = of_get_gpio_flags(child, 0, &flags);
led.active_low = flags & OF_GPIO_ACTIVE_LOW;
led.name = of_get_property(child, "label", NULL) ? : child->name;
led.default_trigger =
of_get_property(child, "linux,default-trigger", NULL);
state = of_get_property(child, "default-state", NULL);
if (state) {
const char *state = NULL;
led.gpiod = devm_get_gpiod_from_child(dev, child);
if (IS_ERR(led.gpiod)) {
fwnode_handle_put(child);
goto err;
}
np = of_node(child);
if (fwnode_property_present(child, "label")) {
fwnode_property_read_string(child, "label", &led.name);
} else {
if (IS_ENABLED(CONFIG_OF) && !led.name && np)
led.name = np->name;
if (!led.name)
return ERR_PTR(-EINVAL);
}
fwnode_property_read_string(child, "linux,default-trigger",
&led.default_trigger);
if (!fwnode_property_read_string(child, "linux,default_state",
&state)) {
if (!strcmp(state, "keep"))
led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
else if (!strcmp(state, "on"))
......@@ -203,13 +213,13 @@ static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
led.default_state = LEDS_GPIO_DEFSTATE_OFF;
}
if (of_get_property(child, "retain-state-suspended", NULL))
if (fwnode_property_present(child, "retain-state-suspended"))
led.retain_state_suspended = 1;
ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],
&pdev->dev, NULL);
dev, NULL);
if (ret < 0) {
of_node_put(child);
fwnode_handle_put(child);
goto err;
}
}
......@@ -228,12 +238,6 @@ static const struct of_device_id of_gpio_leds_match[] = {
};
MODULE_DEVICE_TABLE(of, of_gpio_leds_match);
#else /* CONFIG_OF_GPIO */
static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
{
return ERR_PTR(-ENODEV);
}
#endif /* CONFIG_OF_GPIO */
static int gpio_led_probe(struct platform_device *pdev)
{
......@@ -261,7 +265,7 @@ static int gpio_led_probe(struct platform_device *pdev)
}
}
} else {
priv = gpio_leds_create_of(pdev);
priv = gpio_leds_create(pdev);
if (IS_ERR(priv))
return PTR_ERR(priv);
}
......@@ -288,7 +292,7 @@ static struct platform_driver gpio_led_driver = {
.driver = {
.name = "leds-gpio",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_gpio_leds_match),
.of_match_table = of_gpio_leds_match,
},
};
......
......@@ -18,7 +18,7 @@
#include <linux/spi/spi.h>
#include <linux/spi/eeprom.h>
#include <linux/of.h>
#include <linux/property.h>
/*
* NOTE: this is an *EEPROM* driver. The vagaries of product naming
......@@ -301,35 +301,33 @@ static ssize_t at25_mem_write(struct memory_accessor *mem, const char *buf,
/*-------------------------------------------------------------------------*/
static int at25_np_to_chip(struct device *dev,
struct device_node *np,
struct spi_eeprom *chip)
static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip)
{
u32 val;
memset(chip, 0, sizeof(*chip));
strncpy(chip->name, np->name, sizeof(chip->name));
strncpy(chip->name, "at25", sizeof(chip->name));
if (of_property_read_u32(np, "size", &val) == 0 ||
of_property_read_u32(np, "at25,byte-len", &val) == 0) {
if (device_property_read_u32(dev, "size", &val) == 0 ||
device_property_read_u32(dev, "at25,byte-len", &val) == 0) {
chip->byte_len = val;
} else {
dev_err(dev, "Error: missing \"size\" property\n");
return -ENODEV;
}
if (of_property_read_u32(np, "pagesize", &val) == 0 ||
of_property_read_u32(np, "at25,page-size", &val) == 0) {
if (device_property_read_u32(dev, "pagesize", &val) == 0 ||
device_property_read_u32(dev, "at25,page-size", &val) == 0) {
chip->page_size = (u16)val;
} else {
dev_err(dev, "Error: missing \"pagesize\" property\n");
return -ENODEV;
}
if (of_property_read_u32(np, "at25,addr-mode", &val) == 0) {
if (device_property_read_u32(dev, "at25,addr-mode", &val) == 0) {
chip->flags = (u16)val;
} else {
if (of_property_read_u32(np, "address-width", &val)) {
if (device_property_read_u32(dev, "address-width", &val)) {
dev_err(dev,
"Error: missing \"address-width\" property\n");
return -ENODEV;
......@@ -350,7 +348,7 @@ static int at25_np_to_chip(struct device *dev,
val);
return -ENODEV;
}
if (of_find_property(np, "read-only", NULL))
if (device_property_present(dev, "read-only"))
chip->flags |= EE_READONLY;
}
return 0;
......@@ -360,21 +358,15 @@ static int at25_probe(struct spi_device *spi)
{
struct at25_data *at25 = NULL;
struct spi_eeprom chip;
struct device_node *np = spi->dev.of_node;
int err;
int sr;
int addrlen;
/* Chip description */
if (!spi->dev.platform_data) {
if (np) {
err = at25_np_to_chip(&spi->dev, np, &chip);
if (err)
return err;
} else {
dev_err(&spi->dev, "Error: no chip description\n");
return -ENODEV;
}
err = at25_fw_to_chip(&spi->dev, &chip);
if (err)
return err;
} else
chip = *(struct spi_eeprom *)spi->dev.platform_data;
......
......@@ -1249,6 +1249,39 @@ int of_property_read_u64(const struct device_node *np, const char *propname,
}
EXPORT_SYMBOL_GPL(of_property_read_u64);
/**
* of_property_read_u64_array - Find and read an array of 64 bit integers
* from a property.
*
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_values: pointer to return value, modified only if return value is 0.
* @sz: number of array elements to read
*
* Search for a property in a device node and read 64-bit value(s) from
* it. Returns 0 on success, -EINVAL if the property does not exist,
* -ENODATA if property does not have a value, and -EOVERFLOW if the
* property data isn't large enough.
*
* The out_values is modified only if a valid u64 value can be decoded.
*/
int of_property_read_u64_array(const struct device_node *np,
const char *propname, u64 *out_values,
size_t sz)
{
const __be32 *val = of_find_property_value_of_size(np, propname,
(sz * sizeof(*out_values)));
if (IS_ERR(val))
return PTR_ERR(val);
while (sz--) {
*out_values++ = of_read_number(val, 2);
val += 2;
}
return 0;
}
/**
* of_property_read_string - Find and read a string from a property
* @np: device node from which the property value is to be read.
......
......@@ -27,6 +27,7 @@
#define __ACPI_BUS_H__
#include <linux/device.h>
#include <linux/property.h>
/* TBD: Make dynamic */
#define ACPI_MAX_HANDLES 10
......@@ -337,10 +338,20 @@ struct acpi_device_physical_node {
bool put_online:1;
};
/* ACPI Device Specific Data (_DSD) */
struct acpi_device_data {
const union acpi_object *pointer;
const union acpi_object *properties;
const union acpi_object *of_compatible;
};
struct acpi_gpio_mapping;
/* Device */
struct acpi_device {
int device_type;
acpi_handle handle; /* no handle for fixed hardware */
struct fwnode_handle fwnode;
struct acpi_device *parent;
struct list_head children;
struct list_head node;
......@@ -353,9 +364,11 @@ struct acpi_device {
struct acpi_device_wakeup wakeup;
struct acpi_device_perf performance;
struct acpi_device_dir dir;
struct acpi_device_data data;
struct acpi_scan_handler *handler;
struct acpi_hotplug_context *hp;
struct acpi_driver *driver;
const struct acpi_gpio_mapping *driver_gpios;
void *driver_data;
struct device dev;
unsigned int physical_node_count;
......@@ -364,6 +377,21 @@ struct acpi_device {
void (*remove)(struct acpi_device *);
};
static inline bool is_acpi_node(struct fwnode_handle *fwnode)
{
return fwnode && fwnode->type == FWNODE_ACPI;
}
static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
{
return fwnode ? container_of(fwnode, struct acpi_device, fwnode) : NULL;
}
static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev)
{
return &adev->fwnode;
}
static inline void *acpi_driver_data(struct acpi_device *d)
{
return d->driver_data;
......
......@@ -28,6 +28,7 @@
#include <linux/errno.h>
#include <linux/ioport.h> /* for struct resource */
#include <linux/device.h>
#include <linux/property.h>
#ifndef _LINUX
#define _LINUX
......@@ -423,12 +424,8 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
const struct device *dev);
static inline bool acpi_driver_match_device(struct device *dev,
const struct device_driver *drv)
{
return !!acpi_match_device(drv->acpi_match_table, dev);
}
extern bool acpi_driver_match_device(struct device *dev,
const struct device_driver *drv);
int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *);
int acpi_device_modalias(struct device *, char *, int);
......@@ -443,6 +440,23 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *);
#define ACPI_COMPANION_SET(dev, adev) do { } while (0)
#define ACPI_HANDLE(dev) (NULL)
struct fwnode_handle;
static inline bool is_acpi_node(struct fwnode_handle *fwnode)
{
return false;
}
static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
{
return NULL;
}
static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev)
{
return NULL;
}
static inline const char *acpi_dev_name(struct acpi_device *adev)
{
return NULL;
......@@ -659,4 +673,114 @@ do { \
#endif
#endif
struct acpi_gpio_params {
unsigned int crs_entry_index;
unsigned int line_index;
bool active_low;
};
struct acpi_gpio_mapping {
const char *name;
const struct acpi_gpio_params *data;
unsigned int size;
};
#if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB)
int acpi_dev_add_driver_gpios(struct acpi_device *adev,
const struct acpi_gpio_mapping *gpios);
static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev)
{
if (adev)
adev->driver_gpios = NULL;
}
#else
static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
const struct acpi_gpio_mapping *gpios)
{
return -ENXIO;
}
static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) {}
#endif
/* Device properties */
#define MAX_ACPI_REFERENCE_ARGS 8
struct acpi_reference_args {
struct acpi_device *adev;
size_t nargs;
u64 args[MAX_ACPI_REFERENCE_ARGS];
};
#ifdef CONFIG_ACPI
int acpi_dev_get_property(struct acpi_device *adev, const char *name,
acpi_object_type type, const union acpi_object **obj);
int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
acpi_object_type type,
const union acpi_object **obj);
int acpi_dev_get_property_reference(struct acpi_device *adev,
const char *name, size_t index,
struct acpi_reference_args *args);
int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,
void **valptr);
int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
enum dev_prop_type proptype, void *val);
int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
enum dev_prop_type proptype, void *val, size_t nval);
struct acpi_device *acpi_get_next_child(struct device *dev,
struct acpi_device *child);
#else
static inline int acpi_dev_get_property(struct acpi_device *adev,
const char *name, acpi_object_type type,
const union acpi_object **obj)
{
return -ENXIO;
}
static inline int acpi_dev_get_property_array(struct acpi_device *adev,
const char *name,
acpi_object_type type,
const union acpi_object **obj)
{
return -ENXIO;
}
static inline int acpi_dev_get_property_reference(struct acpi_device *adev,
const char *name, const char *cells_name,
size_t index, struct acpi_reference_args *args)
{
return -ENXIO;
}
static inline int acpi_dev_prop_get(struct acpi_device *adev,
const char *propname,
void **valptr)
{
return -ENXIO;
}
static inline int acpi_dev_prop_read_single(struct acpi_device *adev,
const char *propname,
enum dev_prop_type proptype,
void *val)
{
return -ENXIO;
}
static inline int acpi_dev_prop_read(struct acpi_device *adev,
const char *propname,
enum dev_prop_type proptype,
void *val, size_t nval)
{
return -ENXIO;
}
static inline struct acpi_device *acpi_get_next_child(struct device *dev,
struct acpi_device *child)
{
return NULL;
}
#endif
#endif /*_LINUX_ACPI_H*/
......@@ -94,6 +94,13 @@ int gpiod_to_irq(const struct gpio_desc *desc);
struct gpio_desc *gpio_to_desc(unsigned gpio);
int desc_to_gpio(const struct gpio_desc *desc);
/* Child properties interface */
struct fwnode_handle;
struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
const char *propname);
struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
struct fwnode_handle *child);
#else /* CONFIG_GPIOLIB */
static inline struct gpio_desc *__must_check __gpiod_get(struct device *dev,
......
......@@ -2,6 +2,7 @@
#define _GPIO_KEYS_H
struct device;
struct gpio_desc;
/**
* struct gpio_keys_button - configuration parameters
......@@ -17,6 +18,7 @@ struct device;
* disable button via sysfs
* @value: axis value for %EV_ABS
* @irq: Irq number in case of interrupt keys
* @gpiod: GPIO descriptor
*/
struct gpio_keys_button {
unsigned int code;
......@@ -29,6 +31,7 @@ struct gpio_keys_button {
bool can_disable;
int value;
unsigned int irq;
struct gpio_desc *gpiod;
};
/**
......
......@@ -261,6 +261,7 @@ struct gpio_led {
unsigned retain_state_suspended : 1;
unsigned default_state : 2;
/* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */
struct gpio_desc *gpiod;
};
#define LEDS_GPIO_DEFSTATE_OFF 0
#define LEDS_GPIO_DEFSTATE_ON 1
......@@ -273,7 +274,7 @@ struct gpio_led_platform_data {
#define GPIO_LED_NO_BLINK_LOW 0 /* No blink GPIO state low */
#define GPIO_LED_NO_BLINK_HIGH 1 /* No blink GPIO state high */
#define GPIO_LED_BLINK 2 /* Please, blink */
int (*gpio_blink_set)(unsigned gpio, int state,
int (*gpio_blink_set)(struct gpio_desc *desc, int state,
unsigned long *delay_on,
unsigned long *delay_off);
};
......
......@@ -23,6 +23,7 @@
#include <linux/spinlock.h>
#include <linux/topology.h>
#include <linux/notifier.h>
#include <linux/property.h>
#include <asm/byteorder.h>
#include <asm/errno.h>
......@@ -49,6 +50,7 @@ struct device_node {
const char *type;
phandle phandle;
const char *full_name;
struct fwnode_handle fwnode;
struct property *properties;
struct property *deadprops; /* removed properties */
......@@ -79,6 +81,7 @@ extern struct kobj_type of_node_ktype;
static inline void of_node_init(struct device_node *node)
{
kobject_init(&node->kobj, &of_node_ktype);
node->fwnode.type = FWNODE_OF;
}
/* true when node is initialized */
......@@ -114,6 +117,16 @@ extern struct device_node *of_aliases;
extern struct device_node *of_stdout;
extern raw_spinlock_t devtree_lock;
static inline bool is_of_node(struct fwnode_handle *fwnode)
{
return fwnode && fwnode->type == FWNODE_OF;
}
static inline struct device_node *of_node(struct fwnode_handle *fwnode)
{
return fwnode ? container_of(fwnode, struct device_node, fwnode) : NULL;
}
static inline bool of_have_populated_dt(void)
{
return of_allnodes != NULL;
......@@ -263,6 +276,10 @@ extern int of_property_read_u32_array(const struct device_node *np,
size_t sz);
extern int of_property_read_u64(const struct device_node *np,
const char *propname, u64 *out_value);
extern int of_property_read_u64_array(const struct device_node *np,
const char *propname,
u64 *out_values,
size_t sz);
extern int of_property_read_string(struct device_node *np,
const char *propname,
......@@ -355,6 +372,16 @@ bool of_console_check(struct device_node *dn, char *name, int index);
#else /* CONFIG_OF */
static inline bool is_of_node(struct fwnode_handle *fwnode)
{
return false;
}
static inline struct device_node *of_node(struct fwnode_handle *fwnode)
{
return NULL;
}
static inline const char* of_node_full_name(const struct device_node *np)
{
return "<no-node>";
......@@ -477,6 +504,13 @@ static inline int of_property_read_u32_array(const struct device_node *np,
return -ENOSYS;
}
static inline int of_property_read_u64_array(const struct device_node *np,
const char *propname,
u64 *out_values, size_t sz)
{
return -ENOSYS;
}
static inline int of_property_read_string(struct device_node *np,
const char *propname,
const char **out_string)
......
/*
* property.h - Unified device property interface.
*
* Copyright (C) 2014, Intel Corporation
* Authors: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
* Mika Westerberg <mika.westerberg@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _LINUX_PROPERTY_H_
#define _LINUX_PROPERTY_H_
#include <linux/types.h>
struct device;
enum dev_prop_type {
DEV_PROP_U8,
DEV_PROP_U16,
DEV_PROP_U32,
DEV_PROP_U64,
DEV_PROP_STRING,
DEV_PROP_MAX,
};
bool device_property_present(struct device *dev, const char *propname);
int device_property_read_u8_array(struct device *dev, const char *propname,
u8 *val, size_t nval);
int device_property_read_u16_array(struct device *dev, const char *propname,
u16 *val, size_t nval);
int device_property_read_u32_array(struct device *dev, const char *propname,
u32 *val, size_t nval);
int device_property_read_u64_array(struct device *dev, const char *propname,
u64 *val, size_t nval);
int device_property_read_string_array(struct device *dev, const char *propname,
const char **val, size_t nval);
int device_property_read_string(struct device *dev, const char *propname,
const char **val);
enum fwnode_type {
FWNODE_INVALID = 0,
FWNODE_OF,
FWNODE_ACPI,
};
struct fwnode_handle {
enum fwnode_type type;
};
bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname);
int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
const char *propname, u8 *val,
size_t nval);
int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
const char *propname, u16 *val,
size_t nval);
int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
const char *propname, u32 *val,
size_t nval);
int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
const char *propname, u64 *val,
size_t nval);
int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
const char *propname, const char **val,
size_t nval);
int fwnode_property_read_string(struct fwnode_handle *fwnode,
const char *propname, const char **val);
struct fwnode_handle *device_get_next_child_node(struct device *dev,
struct fwnode_handle *child);
#define device_for_each_child_node(dev, child) \
for (child = device_get_next_child_node(dev, NULL); child; \
child = device_get_next_child_node(dev, child))
void fwnode_handle_put(struct fwnode_handle *fwnode);
unsigned int device_get_child_node_count(struct device *dev);
static inline bool device_property_read_bool(struct device *dev,
const char *propname)
{
return device_property_present(dev, propname);
}
static inline int device_property_read_u8(struct device *dev,
const char *propname, u8 *val)
{
return device_property_read_u8_array(dev, propname, val, 1);
}
static inline int device_property_read_u16(struct device *dev,
const char *propname, u16 *val)
{
return device_property_read_u16_array(dev, propname, val, 1);
}
static inline int device_property_read_u32(struct device *dev,
const char *propname, u32 *val)
{
return device_property_read_u32_array(dev, propname, val, 1);
}
static inline int device_property_read_u64(struct device *dev,
const char *propname, u64 *val)
{
return device_property_read_u64_array(dev, propname, val, 1);
}
static inline bool fwnode_property_read_bool(struct fwnode_handle *fwnode,
const char *propname)
{
return fwnode_property_present(fwnode, propname);
}
static inline int fwnode_property_read_u8(struct fwnode_handle *fwnode,
const char *propname, u8 *val)
{
return fwnode_property_read_u8_array(fwnode, propname, val, 1);
}
static inline int fwnode_property_read_u16(struct fwnode_handle *fwnode,
const char *propname, u16 *val)
{
return fwnode_property_read_u16_array(fwnode, propname, val, 1);
}
static inline int fwnode_property_read_u32(struct fwnode_handle *fwnode,
const char *propname, u32 *val)
{
return fwnode_property_read_u32_array(fwnode, propname, val, 1);
}
static inline int fwnode_property_read_u64(struct fwnode_handle *fwnode,
const char *propname, u64 *val)
{
return fwnode_property_read_u64_array(fwnode, propname, val, 1);
}
#endif /* _LINUX_PROPERTY_H_ */
......@@ -63,6 +63,15 @@ static const struct rfkill_ops rfkill_gpio_ops = {
.set_block = rfkill_gpio_set_power,
};
static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
static const struct acpi_gpio_params shutdown_gpios = { 1, 0, false };
static const struct acpi_gpio_mapping acpi_rfkill_default_gpios[] = {
{ "reset-gpios", &reset_gpios, 1 },
{ "shutdown-gpios", &shutdown_gpios, 1 },
{ },
};
static int rfkill_gpio_acpi_probe(struct device *dev,
struct rfkill_gpio_data *rfkill)
{
......@@ -75,7 +84,8 @@ static int rfkill_gpio_acpi_probe(struct device *dev,
rfkill->name = dev_name(dev);
rfkill->type = (unsigned)id->driver_data;
return 0;
return acpi_dev_add_driver_gpios(ACPI_COMPANION(dev),
acpi_rfkill_default_gpios);
}
static int rfkill_gpio_probe(struct platform_device *pdev)
......@@ -102,7 +112,7 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
rfkill->clk = devm_clk_get(&pdev->dev, NULL);
gpio = devm_gpiod_get_index(&pdev->dev, "reset", 0);
gpio = devm_gpiod_get(&pdev->dev, "reset");
if (!IS_ERR(gpio)) {
ret = gpiod_direction_output(gpio, 0);
if (ret)
......@@ -110,7 +120,7 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
rfkill->reset_gpio = gpio;
}
gpio = devm_gpiod_get_index(&pdev->dev, "shutdown", 1);
gpio = devm_gpiod_get(&pdev->dev, "shutdown");
if (!IS_ERR(gpio)) {
ret = gpiod_direction_output(gpio, 0);
if (ret)
......@@ -150,6 +160,8 @@ static int rfkill_gpio_remove(struct platform_device *pdev)
rfkill_unregister(rfkill->rfkill_dev);
rfkill_destroy(rfkill->rfkill_dev);
acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pdev->dev));
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment