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

Merge branch 'device-properties'

* device-properties:
  device property: avoid allocations of 0 length
  device property: the secondary fwnode needs to depend on the primary
  device property: add spaces to PROPERTY_ENTRY_STRING macro
  include/linux/property.h: fix build issues with gcc-4.4.4
  i2c: designware: Convert to use unified device property API
  mfd: intel-lpss: Pass HSUART configuration via properties
  mfd: intel-lpss: Pass SDA hold time to I2C host controller driver
  mfd: intel-lpss: Add support for passing device properties
  mfd: core: propagate device properties to sub devices drivers
  driver core: Do not overwrite secondary fwnode with NULL if it is set
  driver core: platform: Add support for built-in device properties
  device property: Take a copy of the property set
  device property: Fallback to secondary fwnode if primary misses the property
  device property: return -EINVAL when property isn't found in ACPI
  device property: improve readability of macros
  device property: helper macros for property entry creation
  device property: keep single value inplace
  device property: refactor built-in properties support
  device property: rename helper functions
  device property: always check for fwnode type
parents afd2ff9b f6740c18
......@@ -346,7 +346,7 @@ void acpi_free_properties(struct acpi_device *adev)
*
* Return: %0 if property with @name has been found (success),
* %-EINVAL if the arguments are invalid,
* %-ENODATA if the property doesn't exist,
* %-EINVAL if the property doesn't exist,
* %-EPROTO if the property value type doesn't match @type.
*/
static int acpi_data_get_property(struct acpi_device_data *data,
......@@ -360,7 +360,7 @@ static int acpi_data_get_property(struct acpi_device_data *data,
return -EINVAL;
if (!data->pointer || !data->properties)
return -ENODATA;
return -EINVAL;
properties = data->properties;
for (i = 0; i < properties->package.count; i++) {
......@@ -375,13 +375,13 @@ static int acpi_data_get_property(struct acpi_device_data *data,
if (!strcmp(name, propname->string.pointer)) {
if (type != ACPI_TYPE_ANY && propvalue->type != type)
return -EPROTO;
else if (obj)
if (obj)
*obj = propvalue;
return 0;
}
}
return -ENODATA;
return -EINVAL;
}
/**
......@@ -439,7 +439,7 @@ int acpi_node_prop_get(struct fwnode_handle *fwnode, const char *propname,
*
* Return: %0 if array property (package) with @name has been found (success),
* %-EINVAL if the arguments are invalid,
* %-ENODATA if the property doesn't exist,
* %-EINVAL if the property doesn't exist,
* %-EPROTO if the property is not a package or the type of its elements
* doesn't match @type.
*/
......
......@@ -2261,7 +2261,10 @@ void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode)
if (fwnode_is_primary(fn))
fn = fn->secondary;
if (fn) {
WARN_ON(fwnode->secondary);
fwnode->secondary = fn;
}
dev->fwnode = fwnode;
} else {
dev->fwnode = fwnode_is_primary(dev->fwnode) ?
......
......@@ -26,6 +26,7 @@
#include <linux/acpi.h>
#include <linux/clk/clk-conf.h>
#include <linux/limits.h>
#include <linux/property.h>
#include "base.h"
#include "power/power.h"
......@@ -298,6 +299,22 @@ int platform_device_add_data(struct platform_device *pdev, const void *data,
}
EXPORT_SYMBOL_GPL(platform_device_add_data);
/**
* platform_device_add_properties - add built-in properties to a platform device
* @pdev: platform device to add properties to
* @pset: properties to add
*
* The function will take deep copy of the properties in @pset and attach
* the copy to the platform device. The memory associated with properties
* will be freed when the platform device is released.
*/
int platform_device_add_properties(struct platform_device *pdev,
const struct property_set *pset)
{
return device_add_property_set(&pdev->dev, pset);
}
EXPORT_SYMBOL_GPL(platform_device_add_properties);
/**
* platform_device_add - add a platform device to device hierarchy
* @pdev: platform device we're adding
......@@ -409,6 +426,8 @@ void platform_device_del(struct platform_device *pdev)
if (r->parent)
release_resource(r);
}
device_remove_property_set(&pdev->dev);
}
}
EXPORT_SYMBOL_GPL(platform_device_del);
......@@ -487,6 +506,12 @@ struct platform_device *platform_device_register_full(
if (ret)
goto err;
if (pdevinfo->pset) {
ret = platform_device_add_properties(pdev, pdevinfo->pset);
if (ret)
goto err;
}
ret = platform_device_add(pdev);
if (ret) {
err:
......
This diff is collapsed.
......@@ -36,6 +36,7 @@
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/acpi.h>
......@@ -134,10 +135,10 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
static int dw_i2c_plat_probe(struct platform_device *pdev)
{
struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct dw_i2c_dev *dev;
struct i2c_adapter *adap;
struct resource *mem;
struct dw_i2c_platform_data *pdata;
int irq, r;
u32 clk_freq, ht = 0;
......@@ -161,34 +162,29 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
/* fast mode by default because of legacy reasons */
clk_freq = 400000;
if (has_acpi_companion(&pdev->dev)) {
dw_i2c_acpi_configure(pdev);
} else if (pdev->dev.of_node) {
of_property_read_u32(pdev->dev.of_node,
"i2c-sda-hold-time-ns", &ht);
of_property_read_u32(pdev->dev.of_node,
"i2c-sda-falling-time-ns",
if (pdata) {
clk_freq = pdata->i2c_scl_freq;
} else {
device_property_read_u32(&pdev->dev, "i2c-sda-hold-time-ns",
&ht);
device_property_read_u32(&pdev->dev, "i2c-sda-falling-time-ns",
&dev->sda_falling_time);
of_property_read_u32(pdev->dev.of_node,
"i2c-scl-falling-time-ns",
device_property_read_u32(&pdev->dev, "i2c-scl-falling-time-ns",
&dev->scl_falling_time);
of_property_read_u32(pdev->dev.of_node, "clock-frequency",
device_property_read_u32(&pdev->dev, "clock-frequency",
&clk_freq);
}
/* Only standard mode at 100kHz and fast mode at 400kHz
* are supported.
if (has_acpi_companion(&pdev->dev))
dw_i2c_acpi_configure(pdev);
/*
* Only standard mode at 100kHz and fast mode at 400kHz are supported.
*/
if (clk_freq != 100000 && clk_freq != 400000) {
dev_err(&pdev->dev, "Only 100kHz and 400kHz supported");
return -EINVAL;
}
} else {
pdata = dev_get_platdata(&pdev->dev);
if (pdata)
clk_freq = pdata->i2c_scl_freq;
}
r = i2c_dw_eval_lock_support(dev);
if (r)
......
......@@ -18,6 +18,7 @@
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include "intel-lpss.h"
......@@ -25,6 +26,20 @@ static const struct intel_lpss_platform_info spt_info = {
.clk_rate = 120000000,
};
static struct property_entry spt_i2c_properties[] = {
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230),
{ },
};
static struct property_set spt_i2c_pset = {
.properties = spt_i2c_properties,
};
static const struct intel_lpss_platform_info spt_i2c_info = {
.clk_rate = 120000000,
.pset = &spt_i2c_pset,
};
static const struct intel_lpss_platform_info bxt_info = {
.clk_rate = 100000000,
};
......@@ -35,8 +50,8 @@ static const struct intel_lpss_platform_info bxt_i2c_info = {
static const struct acpi_device_id intel_lpss_acpi_ids[] = {
/* SPT */
{ "INT3446", (kernel_ulong_t)&spt_info },
{ "INT3447", (kernel_ulong_t)&spt_info },
{ "INT3446", (kernel_ulong_t)&spt_i2c_info },
{ "INT3447", (kernel_ulong_t)&spt_i2c_info },
/* BXT */
{ "80860AAC", (kernel_ulong_t)&bxt_i2c_info },
{ "80860ABC", (kernel_ulong_t)&bxt_info },
......
......@@ -17,6 +17,7 @@
#include <linux/pci.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include "intel-lpss.h"
......@@ -65,9 +66,35 @@ static const struct intel_lpss_platform_info spt_info = {
.clk_rate = 120000000,
};
static struct property_entry spt_i2c_properties[] = {
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230),
{ },
};
static struct property_set spt_i2c_pset = {
.properties = spt_i2c_properties,
};
static const struct intel_lpss_platform_info spt_i2c_info = {
.clk_rate = 120000000,
.pset = &spt_i2c_pset,
};
static struct property_entry uart_properties[] = {
PROPERTY_ENTRY_U32("reg-io-width", 4),
PROPERTY_ENTRY_U32("reg-shift", 2),
PROPERTY_ENTRY_BOOL("snps,uart-16550-compatible"),
{ },
};
static struct property_set uart_pset = {
.properties = uart_properties,
};
static const struct intel_lpss_platform_info spt_uart_info = {
.clk_rate = 120000000,
.clk_con_id = "baudclk",
.pset = &uart_pset,
};
static const struct intel_lpss_platform_info bxt_info = {
......@@ -77,6 +104,7 @@ static const struct intel_lpss_platform_info bxt_info = {
static const struct intel_lpss_platform_info bxt_uart_info = {
.clk_rate = 100000000,
.clk_con_id = "baudclk",
.pset = &uart_pset,
};
static const struct intel_lpss_platform_info bxt_i2c_info = {
......@@ -121,20 +149,20 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x9d28), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0x9d29), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x9d2a), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x9d60), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x9d61), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x9d62), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x9d63), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x9d64), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x9d65), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x9d60), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x9d61), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x9d62), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x9d63), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x9d64), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x9d65), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x9d66), (kernel_ulong_t)&spt_uart_info },
/* SPT-H */
{ PCI_VDEVICE(INTEL, 0xa127), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0xa128), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0xa129), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0xa12a), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0xa160), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0xa161), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0xa160), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0xa161), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0xa166), (kernel_ulong_t)&spt_uart_info },
{ }
};
......
......@@ -24,6 +24,7 @@
#include <linux/mfd/core.h>
#include <linux/pm_qos.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/seq_file.h>
#include <linux/io-64-nonatomic-lo-hi.h>
......@@ -72,7 +73,7 @@ struct intel_lpss {
enum intel_lpss_dev_type type;
struct clk *clk;
struct clk_lookup *clock;
const struct mfd_cell *cell;
struct mfd_cell *cell;
struct device *dev;
void __iomem *priv;
int devid;
......@@ -217,6 +218,7 @@ static void intel_lpss_ltr_hide(struct intel_lpss *lpss)
static int intel_lpss_assign_devs(struct intel_lpss *lpss)
{
const struct mfd_cell *cell;
unsigned int type;
type = lpss->caps & LPSS_PRIV_CAPS_TYPE_MASK;
......@@ -224,18 +226,22 @@ static int intel_lpss_assign_devs(struct intel_lpss *lpss)
switch (type) {
case LPSS_DEV_I2C:
lpss->cell = &intel_lpss_i2c_cell;
cell = &intel_lpss_i2c_cell;
break;
case LPSS_DEV_UART:
lpss->cell = &intel_lpss_uart_cell;
cell = &intel_lpss_uart_cell;
break;
case LPSS_DEV_SPI:
lpss->cell = &intel_lpss_spi_cell;
cell = &intel_lpss_spi_cell;
break;
default:
return -ENODEV;
}
lpss->cell = devm_kmemdup(lpss->dev, cell, sizeof(*cell), GFP_KERNEL);
if (!lpss->cell)
return -ENOMEM;
lpss->type = type;
return 0;
......@@ -401,6 +407,8 @@ int intel_lpss_probe(struct device *dev,
if (ret)
return ret;
lpss->cell->pset = info->pset;
intel_lpss_init_dev(lpss);
lpss->devid = ida_simple_get(&intel_lpss_devid_ida, 0, 0, GFP_KERNEL);
......
......@@ -16,12 +16,14 @@
struct device;
struct resource;
struct property_set;
struct intel_lpss_platform_info {
struct resource *mem;
int irq;
unsigned long clk_rate;
const char *clk_con_id;
struct property_set *pset;
};
int intel_lpss_probe(struct device *dev,
......
......@@ -14,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/property.h>
#include <linux/mfd/core.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
......@@ -192,6 +193,12 @@ static int mfd_add_device(struct device *parent, int id,
goto fail_alias;
}
if (cell->pset) {
ret = platform_device_add_properties(pdev, cell->pset);
if (ret)
goto fail_alias;
}
ret = mfd_platform_add_cell(pdev, cell, usage_count);
if (ret)
goto fail_alias;
......
......@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
struct irq_domain;
struct property_set;
/* Matches ACPI PNP id, either _HID or _CID, or ACPI _ADR */
struct mfd_cell_acpi_match {
......@@ -44,6 +45,10 @@ struct mfd_cell {
/* platform data passed to the sub devices drivers */
void *platform_data;
size_t pdata_size;
/* device properties passed to the sub devices drivers */
const struct property_set *pset;
/*
* Device Tree compatible string
* See: Documentation/devicetree/usage-model.txt Chapter 2.2 for details
......
......@@ -18,6 +18,7 @@
#define PLATFORM_DEVID_AUTO (-2)
struct mfd_cell;
struct property_set;
struct platform_device {
const char *name;
......@@ -70,6 +71,8 @@ struct platform_device_info {
const void *data;
size_t size_data;
u64 dma_mask;
const struct property_set *pset;
};
extern struct platform_device *platform_device_register_full(
const struct platform_device_info *pdevinfo);
......@@ -167,6 +170,8 @@ extern int platform_device_add_resources(struct platform_device *pdev,
unsigned int num);
extern int platform_device_add_data(struct platform_device *pdev,
const void *data, size_t size);
extern int platform_device_add_properties(struct platform_device *pdev,
const struct property_set *pset);
extern int platform_device_add(struct platform_device *pdev);
extern void platform_device_del(struct platform_device *pdev);
extern void platform_device_put(struct platform_device *pdev);
......
......@@ -144,14 +144,18 @@ static inline int fwnode_property_read_u64(struct fwnode_handle *fwnode,
/**
* struct property_entry - "Built-in" device property representation.
* @name: Name of the property.
* @type: Type of the property.
* @nval: Number of items of type @type making up the value.
* @value: Value of the property (an array of @nval items of type @type).
* @length: Length of data making up the value.
* @is_array: True when the property is an array.
* @is_string: True when property is a string.
* @pointer: Pointer to the property (an array of items of the given type).
* @value: Value of the property (when it is a single item of the given type).
*/
struct property_entry {
const char *name;
enum dev_prop_type type;
size_t nval;
size_t length;
bool is_array;
bool is_string;
union {
union {
void *raw_data;
u8 *u8_data;
......@@ -159,9 +163,81 @@ struct property_entry {
u32 *u32_data;
u64 *u64_data;
const char **str;
} pointer;
union {
unsigned long long raw_data;
u8 u8_data;
u16 u16_data;
u32 u32_data;
u64 u64_data;
const char *str;
} value;
};
};
/*
* Note: the below four initializers for the anonymous union are carefully
* crafted to avoid gcc-4.4.4's problems with initialization of anon unions
* and structs.
*/
#define PROPERTY_ENTRY_INTEGER_ARRAY(_name_, _type_, _val_) \
{ \
.name = _name_, \
.length = ARRAY_SIZE(_val_) * sizeof(_type_), \
.is_array = true, \
.is_string = false, \
{ .pointer = { _type_##_data = _val_ } }, \
}
#define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u8, _val_)
#define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_) \
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u16, _val_)
#define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_) \
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u32, _val_)
#define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_) \
PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u64, _val_)
#define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_) \
{ \
.name = _name_, \
.length = ARRAY_SIZE(_val_) * sizeof(const char *), \
.is_array = true, \
.is_string = true, \
{ .pointer = { .str = _val_ } }, \
}
#define PROPERTY_ENTRY_INTEGER(_name_, _type_, _val_) \
{ \
.name = _name_, \
.length = sizeof(_type_), \
.is_string = false, \
{ .value = { ._type_##_data = _val_ } }, \
}
#define PROPERTY_ENTRY_U8(_name_, _val_) \
PROPERTY_ENTRY_INTEGER(_name_, u8, _val_)
#define PROPERTY_ENTRY_U16(_name_, _val_) \
PROPERTY_ENTRY_INTEGER(_name_, u16, _val_)
#define PROPERTY_ENTRY_U32(_name_, _val_) \
PROPERTY_ENTRY_INTEGER(_name_, u32, _val_)
#define PROPERTY_ENTRY_U64(_name_, _val_) \
PROPERTY_ENTRY_INTEGER(_name_, u64, _val_)
#define PROPERTY_ENTRY_STRING(_name_, _val_) \
{ \
.name = _name_, \
.length = sizeof(_val_), \
.is_string = true, \
{ .value = { .str = _val_ } }, \
}
#define PROPERTY_ENTRY_BOOL(_name_) \
{ \
.name = _name_, \
}
/**
* struct property_set - Collection of "built-in" device properties.
* @fwnode: Handle to be pointed to by the fwnode field of struct device.
......@@ -172,7 +248,8 @@ struct property_set {
struct property_entry *properties;
};
void device_add_property_set(struct device *dev, struct property_set *pset);
int device_add_property_set(struct device *dev, const struct property_set *pset);
void device_remove_property_set(struct device *dev);
bool device_dma_supported(struct device *dev);
......
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