summaryrefslogtreecommitdiff
path: root/drivers/of
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/of')
-rw-r--r--drivers/of/Kconfig11
-rw-r--r--drivers/of/Makefile2
-rw-r--r--drivers/of/address.c32
-rw-r--r--drivers/of/fdt.c16
-rw-r--r--drivers/of/of_batterydata.c453
-rw-r--r--drivers/of/of_reserved_mem.c4
-rw-r--r--drivers/of/of_slimbus.c90
-rw-r--r--drivers/of/platform.c6
8 files changed, 602 insertions, 12 deletions
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index e2a48415d969..60efdd584d15 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -102,6 +102,12 @@ config OF_RESERVED_MEM
config OF_RESOLVE
bool
+config OF_SLIMBUS
+ def_tristate SLIMBUS
+ depends on SLIMBUS
+ help
+ OpenFirmware SLIMBUS accessors
+
config OF_OVERLAY
bool "Device Tree overlays"
select OF_DYNAMIC
@@ -112,4 +118,9 @@ config OF_OVERLAY
While this option is selected automatically when needed, you can
enable it manually to improve device tree unit test coverage.
+config OF_BATTERYDATA
+ def_bool y
+ help
+ OpenFirmware BatteryData accessors
+
endif # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index 156c072b3117..025229bd2d9f 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -14,5 +14,7 @@ obj-$(CONFIG_OF_MTD) += of_mtd.o
obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
obj-$(CONFIG_OF_RESOLVE) += resolver.o
obj-$(CONFIG_OF_OVERLAY) += overlay.o
+obj-$(CONFIG_OF_SLIMBUS) += of_slimbus.o
+obj-$(CONFIG_OF_BATTERYDATA) += of_batterydata.o
obj-$(CONFIG_OF_UNITTEST) += unittest-data/
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 9582c5703b3c..ec5eb17ae283 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -788,6 +788,22 @@ unsigned long __weak pci_address_to_pio(phys_addr_t address)
#endif
}
+const __be32 *of_get_address_by_name(struct device_node *dev, const char *name,
+ u64 *size, unsigned int *flags)
+{
+ int index;
+ if (!name)
+ return NULL;
+
+ /* Try to read "reg-names" property and get the index by name */
+ index = of_property_match_string(dev, "reg-names", name);
+ if (index < 0)
+ return NULL;
+
+ return of_get_address(dev, index, size, flags);
+}
+EXPORT_SYMBOL(of_get_address_by_name);
+
static int __of_address_to_resource(struct device_node *dev,
const __be32 *addrp, u64 size, unsigned int flags,
const char *name, struct resource *r)
@@ -1026,3 +1042,19 @@ bool of_dma_is_coherent(struct device_node *np)
return false;
}
EXPORT_SYMBOL_GPL(of_dma_is_coherent);
+
+void __iomem *of_iomap_by_name(struct device_node *np, const char *name)
+{
+ int index;
+
+ if (!name)
+ return NULL;
+
+ /* Try to read "reg-names" property and get the index by name */
+ index = of_property_match_string(np, "reg-names", name);
+ if (index < 0)
+ return NULL;
+
+ return of_iomap(np, index);
+}
+EXPORT_SYMBOL(of_iomap_by_name);
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index c6d196188bc9..0438512f4d69 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -496,7 +496,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
if (size &&
early_init_dt_reserve_memory_arch(base, size, nomap) == 0)
- pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n",
+ pr_info("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n",
uname, &base, (unsigned long)size / SZ_1M);
else
pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %ld MiB\n",
@@ -804,14 +804,13 @@ static inline void early_init_dt_check_for_initrd(unsigned long node)
#endif /* CONFIG_BLK_DEV_INITRD */
#ifdef CONFIG_SERIAL_EARLYCON
-extern struct of_device_id __earlycon_of_table[];
static int __init early_init_dt_scan_chosen_serial(void)
{
int offset;
const char *p;
int l;
- const struct of_device_id *match = __earlycon_of_table;
+ const struct earlycon_id *match;
const void *fdt = initial_boot_params;
offset = fdt_path_offset(fdt, "/chosen");
@@ -834,19 +833,20 @@ static int __init early_init_dt_scan_chosen_serial(void)
if (offset < 0)
return -ENODEV;
- while (match->compatible[0]) {
+ for (match = __earlycon_table; match < __earlycon_table_end; match++) {
u64 addr;
- if (fdt_node_check_compatible(fdt, offset, match->compatible)) {
- match++;
+ if (!match->compatible[0])
+ continue;
+
+ if (fdt_node_check_compatible(fdt, offset, match->compatible))
continue;
- }
addr = fdt_translate_address(fdt, offset);
if (addr == OF_BAD_ADDR)
return -ENXIO;
- of_setup_earlycon(addr, match->data);
+ of_setup_earlycon(addr, match->setup);
return 0;
}
return -ENODEV;
diff --git a/drivers/of/of_batterydata.c b/drivers/of/of_batterydata.c
new file mode 100644
index 000000000000..4410f270f557
--- /dev/null
+++ b/drivers/of/of_batterydata.c
@@ -0,0 +1,453 @@
+/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/batterydata-lib.h>
+#include <linux/power_supply.h>
+
+static int of_batterydata_read_lut(const struct device_node *np,
+ int max_cols, int max_rows, int *ncols, int *nrows,
+ int *col_legend_data, int *row_legend_data,
+ int *lut_data)
+{
+ struct property *prop;
+ const __be32 *data;
+ int cols, rows, size, i, j, *out_values;
+
+ prop = of_find_property(np, "qcom,lut-col-legend", NULL);
+ if (!prop) {
+ pr_err("%s: No col legend found\n", np->name);
+ return -EINVAL;
+ } else if (!prop->value) {
+ pr_err("%s: No col legend value found, np->name\n", np->name);
+ return -ENODATA;
+ } else if (prop->length > max_cols * sizeof(int)) {
+ pr_err("%s: Too many columns\n", np->name);
+ return -EINVAL;
+ }
+
+ cols = prop->length/sizeof(int);
+ *ncols = cols;
+ data = prop->value;
+ for (i = 0; i < cols; i++)
+ *col_legend_data++ = be32_to_cpup(data++);
+
+ prop = of_find_property(np, "qcom,lut-row-legend", NULL);
+ if (!prop || row_legend_data == NULL) {
+ /* single row lut */
+ rows = 1;
+ } else if (!prop->value) {
+ pr_err("%s: No row legend value found\n", np->name);
+ return -ENODATA;
+ } else if (prop->length > max_rows * sizeof(int)) {
+ pr_err("%s: Too many rows\n", np->name);
+ return -EINVAL;
+ } else {
+ rows = prop->length/sizeof(int);
+ *nrows = rows;
+ data = prop->value;
+ for (i = 0; i < rows; i++)
+ *row_legend_data++ = be32_to_cpup(data++);
+ }
+
+ prop = of_find_property(np, "qcom,lut-data", NULL);
+ if (!prop) {
+ pr_err("prop 'qcom,lut-data' not found\n");
+ return -EINVAL;
+ }
+ data = prop->value;
+ size = prop->length/sizeof(int);
+ if (size != cols * rows) {
+ pr_err("%s: data size mismatch, %dx%d != %d\n",
+ np->name, cols, rows, size);
+ return -EINVAL;
+ }
+ for (i = 0; i < rows; i++) {
+ out_values = lut_data + (max_cols * i);
+ for (j = 0; j < cols; j++) {
+ *out_values++ = be32_to_cpup(data++);
+ pr_debug("Value = %d\n", *(out_values-1));
+ }
+ }
+
+ return 0;
+}
+
+static int of_batterydata_read_sf_lut(struct device_node *data_node,
+ const char *name, struct sf_lut *lut)
+{
+ struct device_node *node = of_find_node_by_name(data_node, name);
+ int rc;
+
+ if (!lut) {
+ pr_debug("No lut provided, skipping\n");
+ return 0;
+ } else if (!node) {
+ pr_err("Couldn't find %s node.\n", name);
+ return -EINVAL;
+ }
+
+ rc = of_batterydata_read_lut(node, PC_CC_COLS, PC_CC_ROWS,
+ &lut->cols, &lut->rows, lut->row_entries,
+ lut->percent, *lut->sf);
+ if (rc) {
+ pr_err("Failed to read %s node.\n", name);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int of_batterydata_read_pc_temp_ocv_lut(struct device_node *data_node,
+ const char *name, struct pc_temp_ocv_lut *lut)
+{
+ struct device_node *node = of_find_node_by_name(data_node, name);
+ int rc;
+
+ if (!lut) {
+ pr_debug("No lut provided, skipping\n");
+ return 0;
+ } else if (!node) {
+ pr_err("Couldn't find %s node.\n", name);
+ return -EINVAL;
+ }
+ rc = of_batterydata_read_lut(node, PC_TEMP_COLS, PC_TEMP_ROWS,
+ &lut->cols, &lut->rows, lut->temp, lut->percent,
+ *lut->ocv);
+ if (rc) {
+ pr_err("Failed to read %s node.\n", name);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int of_batterydata_read_ibat_temp_acc_lut(struct device_node *data_node,
+ const char *name, struct ibat_temp_acc_lut *lut)
+{
+ struct device_node *node = of_find_node_by_name(data_node, name);
+ int rc;
+
+ if (!lut) {
+ pr_debug("No lut provided, skipping\n");
+ return 0;
+ } else if (!node) {
+ pr_debug("Couldn't find %s node.\n", name);
+ return 0;
+ }
+ rc = of_batterydata_read_lut(node, ACC_TEMP_COLS, ACC_IBAT_ROWS,
+ &lut->cols, &lut->rows, lut->temp, lut->ibat,
+ *lut->acc);
+ if (rc) {
+ pr_err("Failed to read %s node.\n", name);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int of_batterydata_read_single_row_lut(struct device_node *data_node,
+ const char *name, struct single_row_lut *lut)
+{
+ struct device_node *node = of_find_node_by_name(data_node, name);
+ int rc;
+
+ if (!lut) {
+ pr_debug("No lut provided, skipping\n");
+ return 0;
+ } else if (!node) {
+ pr_err("Couldn't find %s node.\n", name);
+ return -EINVAL;
+ }
+
+ rc = of_batterydata_read_lut(node, MAX_SINGLE_LUT_COLS, 1,
+ &lut->cols, NULL, lut->x, NULL, lut->y);
+ if (rc) {
+ pr_err("Failed to read %s node.\n", name);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int of_batterydata_read_batt_id_kohm(const struct device_node *np,
+ const char *propname, struct batt_ids *batt_ids)
+{
+ struct property *prop;
+ const __be32 *data;
+ int num, i, *id_kohm = batt_ids->kohm;
+
+ prop = of_find_property(np, "qcom,batt-id-kohm", NULL);
+ if (!prop) {
+ pr_err("%s: No battery id resistor found\n", np->name);
+ return -EINVAL;
+ } else if (!prop->value) {
+ pr_err("%s: No battery id resistor value found, np->name\n",
+ np->name);
+ return -ENODATA;
+ } else if (prop->length > MAX_BATT_ID_NUM * sizeof(__be32)) {
+ pr_err("%s: Too many battery id resistors\n", np->name);
+ return -EINVAL;
+ }
+
+ num = prop->length/sizeof(__be32);
+ batt_ids->num = num;
+ data = prop->value;
+ for (i = 0; i < num; i++)
+ *id_kohm++ = be32_to_cpup(data++);
+
+ return 0;
+}
+
+#define OF_PROP_READ(property, qpnp_dt_property, node, rc, optional) \
+do { \
+ if (rc) \
+ break; \
+ rc = of_property_read_u32(node, "qcom," qpnp_dt_property, \
+ &property); \
+ \
+ if ((rc == -EINVAL) && optional) { \
+ property = -EINVAL; \
+ rc = 0; \
+ } else if (rc) { \
+ pr_err("Error reading " #qpnp_dt_property \
+ " property rc = %d\n", rc); \
+ } \
+} while (0)
+
+static int of_batterydata_load_battery_data(struct device_node *node,
+ int best_id_kohm,
+ struct bms_battery_data *batt_data)
+{
+ int rc;
+
+ rc = of_batterydata_read_single_row_lut(node, "qcom,fcc-temp-lut",
+ batt_data->fcc_temp_lut);
+ if (rc)
+ return rc;
+
+ rc = of_batterydata_read_pc_temp_ocv_lut(node,
+ "qcom,pc-temp-ocv-lut",
+ batt_data->pc_temp_ocv_lut);
+ if (rc)
+ return rc;
+
+ rc = of_batterydata_read_sf_lut(node, "qcom,rbatt-sf-lut",
+ batt_data->rbatt_sf_lut);
+ if (rc)
+ return rc;
+
+ rc = of_batterydata_read_ibat_temp_acc_lut(node, "qcom,ibat-acc-lut",
+ batt_data->ibat_acc_lut);
+ if (rc)
+ return rc;
+
+ rc = of_property_read_string(node, "qcom,battery-type",
+ &batt_data->battery_type);
+ if (rc) {
+ pr_err("Error reading qcom,battery-type property rc=%d\n", rc);
+ batt_data->battery_type = NULL;
+ return rc;
+ }
+
+ OF_PROP_READ(batt_data->fcc, "fcc-mah", node, rc, false);
+ OF_PROP_READ(batt_data->default_rbatt_mohm,
+ "default-rbatt-mohm", node, rc, false);
+ OF_PROP_READ(batt_data->rbatt_capacitive_mohm,
+ "rbatt-capacitive-mohm", node, rc, false);
+ OF_PROP_READ(batt_data->flat_ocv_threshold_uv,
+ "flat-ocv-threshold-uv", node, rc, true);
+ OF_PROP_READ(batt_data->max_voltage_uv,
+ "max-voltage-uv", node, rc, true);
+ OF_PROP_READ(batt_data->cutoff_uv, "v-cutoff-uv", node, rc, true);
+ OF_PROP_READ(batt_data->iterm_ua, "chg-term-ua", node, rc, true);
+ OF_PROP_READ(batt_data->fastchg_current_ma,
+ "fastchg-current-ma", node, rc, true);
+ OF_PROP_READ(batt_data->fg_cc_cv_threshold_mv,
+ "fg-cc-cv-threshold-mv", node, rc, true);
+
+ batt_data->batt_id_kohm = best_id_kohm;
+
+ return rc;
+}
+
+static int64_t of_batterydata_convert_battery_id_kohm(int batt_id_uv,
+ int rpull_up, int vadc_vdd)
+{
+ int64_t resistor_value_kohm, denom;
+
+ if (batt_id_uv == 0) {
+ /* vadc not correct or batt id line grounded, report 0 kohms */
+ return 0;
+ }
+ /* calculate the battery id resistance reported via ADC */
+ denom = div64_s64(vadc_vdd * 1000000LL, batt_id_uv) - 1000000LL;
+
+ if (denom == 0) {
+ /* batt id connector might be open, return 0 kohms */
+ return 0;
+ }
+ resistor_value_kohm = div64_s64(rpull_up * 1000000LL + denom/2, denom);
+
+ pr_debug("batt id voltage = %d, resistor value = %lld\n",
+ batt_id_uv, resistor_value_kohm);
+
+ return resistor_value_kohm;
+}
+
+struct device_node *of_batterydata_get_best_profile(
+ const struct device_node *batterydata_container_node,
+ int batt_id_kohm, const char *batt_type)
+{
+ struct batt_ids batt_ids;
+ struct device_node *node, *best_node = NULL;
+ const char *battery_type = NULL;
+ int delta = 0, best_delta = 0, best_id_kohm = 0, id_range_pct,
+ i = 0, rc = 0, limit = 0;
+ bool in_range = false;
+
+ /* read battery id range percentage for best profile */
+ rc = of_property_read_u32(batterydata_container_node,
+ "qcom,batt-id-range-pct", &id_range_pct);
+
+ if (rc) {
+ if (rc == -EINVAL) {
+ id_range_pct = 0;
+ } else {
+ pr_err("failed to read battery id range\n");
+ return ERR_PTR(-ENXIO);
+ }
+ }
+
+ /*
+ * Find the battery data with a battery id resistor closest to this one
+ */
+ for_each_child_of_node(batterydata_container_node, node) {
+ if (batt_type != NULL) {
+ rc = of_property_read_string(node, "qcom,battery-type",
+ &battery_type);
+ if (!rc && strcmp(battery_type, batt_type) == 0) {
+ best_node = node;
+ best_id_kohm = batt_id_kohm;
+ break;
+ }
+ } else {
+ rc = of_batterydata_read_batt_id_kohm(node,
+ "qcom,batt-id-kohm",
+ &batt_ids);
+ if (rc)
+ continue;
+ for (i = 0; i < batt_ids.num; i++) {
+ delta = abs(batt_ids.kohm[i] - batt_id_kohm);
+ limit = (batt_ids.kohm[i] * id_range_pct) / 100;
+ in_range = (delta <= limit);
+ /*
+ * Check if the delta is the lowest one
+ * and also if the limits are in range
+ * before selecting the best node.
+ */
+ if ((delta < best_delta || !best_node)
+ && in_range) {
+ best_node = node;
+ best_delta = delta;
+ best_id_kohm = batt_ids.kohm[i];
+ }
+ }
+ }
+ }
+
+ if (best_node == NULL) {
+ pr_err("No battery data found\n");
+ return best_node;
+ }
+
+ /* check that profile id is in range of the measured batt_id */
+ if (abs(best_id_kohm - batt_id_kohm) >
+ ((best_id_kohm * id_range_pct) / 100)) {
+ pr_err("out of range: profile id %d batt id %d pct %d",
+ best_id_kohm, batt_id_kohm, id_range_pct);
+ return NULL;
+ }
+
+ rc = of_property_read_string(best_node, "qcom,battery-type",
+ &battery_type);
+ if (!rc)
+ pr_info("%s found\n", battery_type);
+ else
+ pr_info("%s found\n", best_node->name);
+
+ return best_node;
+}
+
+int of_batterydata_read_data(struct device_node *batterydata_container_node,
+ struct bms_battery_data *batt_data,
+ int batt_id_uv)
+{
+ struct device_node *node, *best_node;
+ struct batt_ids batt_ids;
+ const char *battery_type = NULL;
+ int delta, best_delta, batt_id_kohm, rpull_up_kohm,
+ vadc_vdd_uv, best_id_kohm, i, rc = 0;
+
+ node = batterydata_container_node;
+ OF_PROP_READ(rpull_up_kohm, "rpull-up-kohm", node, rc, false);
+ OF_PROP_READ(vadc_vdd_uv, "vref-batt-therm", node, rc, false);
+ if (rc)
+ return rc;
+
+ batt_id_kohm = of_batterydata_convert_battery_id_kohm(batt_id_uv,
+ rpull_up_kohm, vadc_vdd_uv);
+ best_node = NULL;
+ best_delta = 0;
+ best_id_kohm = 0;
+
+ /*
+ * Find the battery data with a battery id resistor closest to this one
+ */
+ for_each_child_of_node(batterydata_container_node, node) {
+ rc = of_batterydata_read_batt_id_kohm(node,
+ "qcom,batt-id-kohm",
+ &batt_ids);
+ if (rc)
+ continue;
+ for (i = 0; i < batt_ids.num; i++) {
+ delta = abs(batt_ids.kohm[i] - batt_id_kohm);
+ if (delta < best_delta || !best_node) {
+ best_node = node;
+ best_delta = delta;
+ best_id_kohm = batt_ids.kohm[i];
+ }
+ }
+ }
+
+ if (best_node == NULL) {
+ pr_err("No battery data found\n");
+ return -ENODATA;
+ }
+ rc = of_property_read_string(best_node, "qcom,battery-type",
+ &battery_type);
+ if (!rc)
+ pr_info("%s loaded\n", battery_type);
+ else
+ pr_info("%s loaded\n", best_node->name);
+
+ return of_batterydata_load_battery_data(best_node,
+ best_id_kohm, batt_data);
+}
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index ed01c0172e4a..cffd4d31d3c1 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -149,7 +149,7 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
ret = early_init_dt_alloc_reserved_memory_arch(size,
align, start, end, nomap, &base);
if (ret == 0) {
- pr_debug("Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n",
+ pr_info("Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n",
uname, &base,
(unsigned long)size / SZ_1M);
break;
@@ -161,7 +161,7 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
ret = early_init_dt_alloc_reserved_memory_arch(size, align,
0, 0, nomap, &base);
if (ret == 0)
- pr_debug("Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n",
+ pr_info("Reserved memory: allocated memory for '%s' node: base %pa, size %ld MiB\n",
uname, &base, (unsigned long)size / SZ_1M);
}
diff --git a/drivers/of/of_slimbus.c b/drivers/of/of_slimbus.c
new file mode 100644
index 000000000000..234a5eb77db0
--- /dev/null
+++ b/drivers/of/of_slimbus.c
@@ -0,0 +1,90 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/* OF helpers for SLIMbus */
+#include <linux/slimbus/slimbus.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_slimbus.h>
+
+int of_register_slim_devices(struct slim_controller *ctrl)
+{
+ struct device_node *node;
+ struct slim_boardinfo *binfo = NULL;
+ struct slim_boardinfo *temp;
+ int n = 0;
+ int ret = 0;
+
+ if (!ctrl->dev.of_node)
+ return -EINVAL;
+
+ for_each_child_of_node(ctrl->dev.of_node, node) {
+ struct property *prop;
+ struct slim_device *slim;
+ char *name;
+ prop = of_find_property(node, "elemental-addr", NULL);
+ if (!prop || prop->length != 6) {
+ dev_err(&ctrl->dev, "of_slim: invalid E-addr");
+ continue;
+ }
+ name = kzalloc(SLIMBUS_NAME_SIZE, GFP_KERNEL);
+ if (!name) {
+ dev_err(&ctrl->dev, "of_slim: out of memory");
+ ret = -ENOMEM;
+ goto of_slim_err;
+ }
+ if (of_modalias_node(node, name, SLIMBUS_NAME_SIZE) < 0) {
+ dev_err(&ctrl->dev, "of_slim: modalias failure on %s\n",
+ node->full_name);
+ kfree(name);
+ continue;
+ }
+ slim = kzalloc(sizeof(struct slim_device), GFP_KERNEL);
+ if (!slim) {
+ dev_err(&ctrl->dev, "of_slim: out of memory");
+ ret = -ENOMEM;
+ kfree(name);
+ goto of_slim_err;
+ }
+ memcpy(slim->e_addr, prop->value, 6);
+
+ temp = krealloc(binfo, (n + 1) * sizeof(struct slim_boardinfo),
+ GFP_KERNEL);
+ if (!temp) {
+ dev_err(&ctrl->dev, "out of memory");
+ kfree(name);
+ kfree(slim);
+ ret = -ENOMEM;
+ goto of_slim_err;
+ }
+ binfo = temp;
+
+ slim->dev.of_node = of_node_get(node);
+ slim->name = (const char *)name;
+ binfo[n].bus_num = ctrl->nr;
+ binfo[n].slim_slave = slim;
+ n++;
+ }
+ ret = slim_register_board_info(binfo, n);
+ if (!ret)
+ goto of_slim_ret;
+of_slim_err:
+ while (n-- > 0) {
+ kfree(binfo[n].slim_slave->name);
+ kfree(binfo[n].slim_slave);
+ }
+of_slim_ret:
+ kfree(binfo);
+ return ret;
+}
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index af98343614d8..2924c8141f16 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -21,6 +21,7 @@
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
const struct of_device_id of_default_bus_match_table[] = {
@@ -139,7 +140,7 @@ struct platform_device *of_device_alloc(struct device_node *np,
}
dev->dev.of_node = of_node_get(np);
- dev->dev.parent = parent ? : &platform_bus;
+ dev->dev.parent = parent;
if (bus_id)
dev_set_name(&dev->dev, "%s", bus_id);
@@ -185,6 +186,7 @@ static struct platform_device *of_platform_device_create_pdata(
dev->dev.platform_data = platform_data;
of_dma_configure(&dev->dev, dev->dev.of_node);
of_msi_configure(&dev->dev, dev->dev.of_node);
+ of_reserved_mem_device_init(&dev->dev);
if (of_device_add(dev) != 0) {
of_dma_deconfigure(&dev->dev);
@@ -241,7 +243,7 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
/* setup generic device info */
dev->dev.of_node = of_node_get(node);
- dev->dev.parent = parent ? : &platform_bus;
+ dev->dev.parent = parent;
dev->dev.platform_data = platform_data;
if (bus_id)
dev_set_name(&dev->dev, "%s", bus_id);