blob: 30d5a53c17b0f1d94cae93d2011bf5f70edf67af [file] [log] [blame]
/*
* Google LWIS Device Tree Parser
*
* Copyright (c) 2018 Google, LLC
*
* 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME "-dt: " fmt
#include "lwis_dt.h"
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/slab.h>
#include "lwis_clock.h"
#include "lwis_device_dpm.h"
#include "lwis_gpio.h"
#include "lwis_i2c.h"
#include "lwis_ioreg.h"
#include "lwis_regulator.h"
#define SHARED_STRING "shared-"
#define PULSE_STRING "pulse-"
/* Uncomment this to help debug device tree parsing. */
// #define LWIS_DT_DEBUG
static int parse_gpios(struct lwis_device *lwis_dev, char *name, bool *is_present)
{
int count;
struct device *dev;
struct gpio_descs *list;
*is_present = false;
dev = &lwis_dev->plat_dev->dev;
count = gpiod_count(dev, name);
/* No GPIO pins found, just return */
if (count <= 0) {
return 0;
}
list = lwis_gpio_list_get(dev, name);
if (IS_ERR_OR_NULL(list)) {
pr_err("Error parsing GPIO list %s (%ld)\n", name, PTR_ERR(list));
return PTR_ERR(list);
}
/* The GPIO pins are valid, release the list as we do not need to hold
on to the pins yet */
lwis_gpio_list_put(list, dev);
*is_present = true;
return 0;
}
static int parse_irq_gpios(struct lwis_device *lwis_dev)
{
int count;
int name_count;
int event_count;
int type_count;
int ret;
struct device *dev;
struct device_node *dev_node;
struct gpio_descs *gpios;
const char *name;
char *irq_gpios_names = NULL;
u64 *irq_gpios_events = NULL;
u32 *irq_gpios_types = NULL;
int i;
/* Initialize the data structure */
strscpy(lwis_dev->irq_gpios_info.name, "irq", LWIS_MAX_NAME_STRING_LEN);
lwis_dev->irq_gpios_info.gpios = NULL;
lwis_dev->irq_gpios_info.irq_list = NULL;
lwis_dev->irq_gpios_info.is_shared = false;
lwis_dev->irq_gpios_info.is_pulse = false;
dev = &lwis_dev->plat_dev->dev;
count = gpiod_count(dev, "irq");
/* No irq GPIO pins found, just return */
if (count <= 0) {
return 0;
}
dev_node = dev->of_node;
name_count = of_property_count_strings(dev_node, "irq-gpios-names");
event_count = of_property_count_elems_of_size(dev_node, "irq-gpios-events", sizeof(u64));
type_count = of_property_count_elems_of_size(dev_node, "irq-gpios-types", sizeof(u32));
if (count != event_count || count != name_count || count != type_count) {
pr_err("Count of irq-gpios-* is not match\n");
return -EINVAL;
}
gpios = lwis_gpio_list_get(dev, "irq");
if (IS_ERR_OR_NULL(gpios)) {
pr_err("Error parsing irq GPIO list (%ld)\n", PTR_ERR(gpios));
return PTR_ERR(gpios);
}
lwis_dev->irq_gpios_info.gpios = gpios;
lwis_dev->irq_gpios_info.irq_list = lwis_interrupt_list_alloc(lwis_dev, gpios->ndescs);
if (IS_ERR_OR_NULL(lwis_dev->irq_gpios_info.irq_list)) {
ret = -ENOMEM;
lwis_dev->irq_gpios_info.irq_list = NULL;
pr_err("Failed to allocate irq list\n");
goto error_parse_irq_gpios;
}
irq_gpios_names = kmalloc(LWIS_MAX_NAME_STRING_LEN * name_count, GFP_KERNEL);
if (IS_ERR_OR_NULL(irq_gpios_names)) {
pr_err("Allocating event list failed\n");
ret = -ENOMEM;
goto error_parse_irq_gpios;
}
for (i = 0; i < name_count; ++i) {
ret = of_property_read_string_index(dev_node, "irq-gpios-names", i, &name);
if (ret < 0) {
pr_err("Error get GPIO irq name list (%d)\n", ret);
goto error_parse_irq_gpios;
}
strscpy(irq_gpios_names + i * LWIS_MAX_NAME_STRING_LEN, name,
LWIS_MAX_NAME_STRING_LEN);
}
irq_gpios_types = kmalloc(sizeof(u32) * type_count, GFP_KERNEL);
if (IS_ERR_OR_NULL(irq_gpios_types)) {
pr_err("Allocating irq_gpios_types list failed\n");
ret = -ENOMEM;
goto error_parse_irq_gpios;
}
type_count = of_property_read_variable_u32_array(dev_node, "irq-gpios-types",
irq_gpios_types, type_count, type_count);
if (type_count != count) {
pr_err("Error getting irq-gpios-types: %d\n", type_count);
ret = type_count;
goto error_parse_irq_gpios;
}
irq_gpios_events = kmalloc(sizeof(u64) * event_count, GFP_KERNEL);
if (IS_ERR_OR_NULL(irq_gpios_events)) {
pr_err("Allocating event list failed\n");
ret = -ENOMEM;
goto error_parse_irq_gpios;
}
event_count = of_property_read_variable_u64_array(
dev_node, "irq-gpios-events", irq_gpios_events, event_count, event_count);
if (event_count != count) {
pr_err("Error getting irq-gpios-events: %d\n", event_count);
ret = event_count;
goto error_parse_irq_gpios;
}
for (i = 0; i < event_count; ++i) {
ret = lwis_interrupt_set_gpios_event_info(lwis_dev->irq_gpios_info.irq_list, i,
irq_gpios_events[i]);
if (ret) {
pr_err("Error setting event info for gpios interrupt %d %d\n", i, ret);
goto error_parse_irq_gpios;
}
}
for (i = 0; i < gpios->ndescs; ++i) {
char *name;
int irq;
irq = gpiod_to_irq(gpios->desc[i]);
if (irq < 0) {
pr_err("gpio to irq failed (%d)\n", irq);
lwis_interrupt_list_free(lwis_dev->irq_gpios_info.irq_list);
return irq;
}
name = irq_gpios_names + i * LWIS_MAX_NAME_STRING_LEN;
lwis_interrupt_get_gpio_irq(lwis_dev->irq_gpios_info.irq_list, i, name, irq,
irq_gpios_types[i]);
}
kfree(irq_gpios_names);
kfree(irq_gpios_events);
kfree(irq_gpios_types);
return 0;
error_parse_irq_gpios:
if (lwis_dev->irq_gpios_info.gpios) {
lwis_gpio_list_put(lwis_dev->irq_gpios_info.gpios, dev);
lwis_dev->irq_gpios_info.gpios = NULL;
}
if (lwis_dev->irq_gpios_info.irq_list) {
lwis_interrupt_list_free(lwis_dev->irq_gpios_info.irq_list);
lwis_dev->irq_gpios_info.irq_list = NULL;
}
kfree(irq_gpios_names);
kfree(irq_gpios_events);
kfree(irq_gpios_types);
return ret;
}
static int parse_settle_time(struct lwis_device *lwis_dev)
{
struct device_node *dev_node;
struct device *dev;
dev = &lwis_dev->plat_dev->dev;
dev_node = dev->of_node;
lwis_dev->enable_gpios_settle_time = 0;
of_property_read_u32(dev_node, "enable-gpios-settle-time",
&lwis_dev->enable_gpios_settle_time);
return 0;
}
static int parse_regulators(struct lwis_device *lwis_dev)
{
int i;
int ret;
int count;
struct device_node *dev_node;
struct device_node *dev_node_reg;
const char *name;
struct device *dev;
int voltage;
int voltage_count;
dev = &lwis_dev->plat_dev->dev;
dev_node = dev->of_node;
count = of_property_count_elems_of_size(dev_node, "regulators", sizeof(u32));
/* No regulators found, or entry does not exist, just return */
if (count <= 0) {
lwis_dev->regulators = NULL;
return 0;
}
/* Voltage count is allowed to be less than regulator count,
regulator_set_voltage will not be called for the ones with
unspecified voltage */
voltage_count =
of_property_count_elems_of_size(dev_node, "regulator-voltages", sizeof(u32));
lwis_dev->regulators = lwis_regulator_list_alloc(count);
if (IS_ERR_OR_NULL(lwis_dev->regulators)) {
pr_err("Cannot allocate regulator list\n");
ret = PTR_ERR(lwis_dev->regulators);
lwis_dev->regulators = NULL;
return ret;
}
/* Parse regulator list and acquire the regulator pointers */
for (i = 0; i < count; ++i) {
dev_node_reg = of_parse_phandle(dev_node, "regulators", i);
of_property_read_string(dev_node_reg, "regulator-name", &name);
voltage = 0;
if (i < voltage_count) {
of_property_read_u32_index(dev_node, "regulator-voltages", i, &voltage);
}
ret = lwis_regulator_get(lwis_dev->regulators, (char *)name, voltage, dev);
if (ret < 0) {
pr_err("Cannot find regulator: %s\n", name);
goto error_parse_reg;
}
}
#ifdef LWIS_DT_DEBUG
lwis_regulator_print(lwis_dev->regulators);
#endif
return 0;
error_parse_reg:
/* In case of error, free all the other regulators that were alloc'ed */
lwis_regulator_put_all(lwis_dev->regulators);
lwis_regulator_list_free(lwis_dev->regulators);
lwis_dev->regulators = NULL;
return ret;
}
static int parse_clocks(struct lwis_device *lwis_dev)
{
int i;
int ret = 0;
int count;
int __maybe_unused bts_count;
struct device *dev;
struct device_node *dev_node;
const char *name;
u32 rate;
int clock_family;
dev = &lwis_dev->plat_dev->dev;
dev_node = dev->of_node;
count = of_property_count_strings(dev_node, "clock-names");
/* No clocks found, just return */
if (count <= 0) {
lwis_dev->clocks = NULL;
return 0;
}
lwis_dev->clocks = lwis_clock_list_alloc(count);
if (IS_ERR_OR_NULL(lwis_dev->clocks)) {
pr_err("Cannot allocate clocks list\n");
ret = PTR_ERR(lwis_dev->clocks);
lwis_dev->clocks = NULL;
return ret;
}
/* Parse and acquire clock pointers and frequencies, if applicable */
for (i = 0; i < count; ++i) {
of_property_read_string_index(dev_node, "clock-names", i, &name);
/* It is allowed to omit clock rates for some of the clocks */
ret = of_property_read_u32_index(dev_node, "clock-rates", i, &rate);
rate = (ret == 0) ? rate : 0;
ret = lwis_clock_get(lwis_dev->clocks, (char *)name, dev, rate);
if (ret < 0) {
pr_err("Cannot find clock: %s\n", name);
goto error_parse_clk;
}
}
/* It is allowed to omit clock rates for some of the clocks */
ret = of_property_read_u32(dev_node, "clock-family", &clock_family);
lwis_dev->clock_family = (ret == 0) ? clock_family : CLOCK_FAMILY_INVALID;
/* Parse the BTS block names */
bts_count = of_property_count_strings(dev_node, "bts-block-names");
if (bts_count > 0) {
lwis_dev->bts_block_num = bts_count;
for (i = 0; i < bts_count; ++i) {
of_property_read_string_index(dev_node, "bts-block-names", i, &name);
lwis_dev->bts_block_names[i] = (const char *)name;
}
} else {
lwis_dev->bts_block_num = 1;
lwis_dev->bts_block_names[0] = lwis_dev->name;
}
/* Initialize all the BTS indexes */
for (i = 0; i < MAX_BTS_BLOCK_NUM; ++i) {
lwis_dev->bts_indexes[i] = BTS_UNSUPPORTED;
}
#ifdef LWIS_DT_DEBUG
pr_info("%s: clock family %d", lwis_dev->name, lwis_dev->clock_family);
lwis_clock_print(lwis_dev->clocks);
#endif
return 0;
error_parse_clk:
/* Put back the clock instances for the ones that were alloc'ed */
for (i = 0; i < count; ++i) {
lwis_clock_put_by_idx(lwis_dev->clocks, i, dev);
}
lwis_clock_list_free(lwis_dev->clocks);
lwis_dev->clocks = NULL;
return ret;
}
static int parse_pinctrls(struct lwis_device *lwis_dev, char *expected_state)
{
int count;
struct device *dev;
struct device_node *dev_node;
struct pinctrl *pc;
struct pinctrl_state *pinctrl_state;
dev = &lwis_dev->plat_dev->dev;
dev_node = dev->of_node;
lwis_dev->mclk_present = false;
lwis_dev->shared_pinctrl = 0;
count = of_property_count_strings(dev_node, "pinctrl-names");
/* No pinctrl found, just return */
if (count <= 0)
return 0;
/* Set up pinctrl */
pc = devm_pinctrl_get(dev);
if (IS_ERR_OR_NULL(pc)) {
pr_err("Cannot allocate pinctrl\n");
return PTR_ERR(pc);
}
pinctrl_state = pinctrl_lookup_state(pc, expected_state);
if (IS_ERR_OR_NULL(pinctrl_state)) {
pr_err("Cannot find pinctrl state %s\n", expected_state);
devm_pinctrl_put(pc);
return PTR_ERR(pinctrl_state);
}
/* Indicate if the pinctrl shared with other devices */
of_property_read_u32(dev_node, "shared-pinctrl", &lwis_dev->shared_pinctrl);
/* The pinctrl is valid, release it as we do not need to hold on to
the pins yet */
devm_pinctrl_put(pc);
lwis_dev->mclk_present = true;
return 0;
}
static int parse_irq_reg_bits(struct device_node *info, int *bits_num_result, u32 **reg_bits_result)
{
int int_reg_bits_num;
u32 *int_reg_bits;
int_reg_bits_num = of_property_count_elems_of_size(info, "int-reg-bits", 4);
if (int_reg_bits_num <= 0) {
pr_err("Error getting int-reg-bits: %d\n", int_reg_bits_num);
return -EINVAL;
}
int_reg_bits = kmalloc(sizeof(u32) * int_reg_bits_num, GFP_KERNEL);
if (IS_ERR_OR_NULL(int_reg_bits)) {
pr_err("Failed to allocate memory for irq regiater bits\n");
return -ENOMEM;
}
*bits_num_result = int_reg_bits_num;
int_reg_bits_num = of_property_read_variable_u32_array(info, "int-reg-bits", int_reg_bits,
int_reg_bits_num, int_reg_bits_num);
if (*bits_num_result != int_reg_bits_num) {
pr_err("Error getting int-reg-bits: %d\n", int_reg_bits_num);
kfree(int_reg_bits);
return int_reg_bits_num;
}
*reg_bits_result = int_reg_bits;
return 0;
}
static int parse_critical_irq_events(struct device_node *event_info, u64 **irq_events)
{
int ret;
int critical_irq_events_num;
u64 critical_irq_events;
int i;
critical_irq_events_num =
of_property_count_elems_of_size(event_info, "critical-irq-events", 8);
/* No Critical IRQ event found, just return */
if (critical_irq_events_num <= 0) {
return 0;
}
*irq_events = kmalloc(sizeof(u64) * critical_irq_events_num, GFP_KERNEL);
if (*irq_events == NULL) {
pr_err("Failed to allocate memory for critical events\n");
return 0;
}
for (i = 0; i < critical_irq_events_num; ++i) {
ret = of_property_read_u64_index(event_info, "critical-irq-events", i,
&critical_irq_events);
if (ret < 0) {
pr_err("Error adding critical irq events[%d]\n", i);
kfree(*irq_events);
*irq_events = NULL;
return 0;
}
*irq_events[i] = critical_irq_events;
}
return critical_irq_events_num;
}
static int parse_interrupts_event_info(struct lwis_interrupt_list *list, int index,
struct device_node *event_info)
{
int irq_events_num;
int int_reg_bits_num = 0;
int critical_events_num = 0;
u64 *irq_events = NULL;
u32 *int_reg_bits = NULL;
u64 *critical_events = NULL;
int ret = 0;
ret = parse_irq_reg_bits(event_info, &int_reg_bits_num, &int_reg_bits);
if (ret) {
return ret;
}
irq_events_num = of_property_count_elems_of_size(event_info, "irq-events", 8);
if (irq_events_num != int_reg_bits_num || irq_events_num <= 0) {
pr_err("Error getting irq-events: %d\n", irq_events_num);
ret = -EINVAL;
goto event_info_exit;
}
irq_events = kmalloc(sizeof(u64) * irq_events_num, GFP_KERNEL);
if (IS_ERR_OR_NULL(irq_events)) {
ret = -ENOMEM;
goto event_info_exit;
}
irq_events_num = of_property_read_variable_u64_array(event_info, "irq-events", irq_events,
irq_events_num, irq_events_num);
if (irq_events_num != int_reg_bits_num) {
pr_err("Error getting irq-events: %d\n", irq_events_num);
ret = irq_events_num;
goto event_info_exit;
}
critical_events_num = parse_critical_irq_events(event_info, &critical_events);
ret = lwis_interrupt_set_event_info(list, index, (int64_t *)irq_events, irq_events_num,
int_reg_bits, int_reg_bits_num,
(int64_t *)critical_events, critical_events_num);
if (ret) {
pr_err("Error setting event info for interrupt %d %d\n", index, ret);
goto event_info_exit;
}
event_info_exit:
kfree(critical_events);
kfree(irq_events);
kfree(int_reg_bits);
return ret;
}
static int find_irq_index_by_name(struct lwis_interrupt_list *list, const char *irq_name)
{
int i;
for (i = 0; i < list->count; ++i) {
if (strncmp(irq_name, list->irq[i].name, IRQ_FULL_NAME_LENGTH - 1) == 0) {
return i;
}
}
return -ENOENT;
}
static int parse_interrupt_leaf_nodes(struct lwis_interrupt_list *list, int index,
struct device_node *leaf_info)
{
int irq_leaves_num;
int int_reg_bits_num;
u32 *int_reg_bits = NULL;
struct of_phandle_iterator it;
int i = 0, ret = 0;
ret = parse_irq_reg_bits(leaf_info, &int_reg_bits_num, &int_reg_bits);
if (ret) {
return ret;
}
irq_leaves_num = of_property_count_elems_of_size(leaf_info, "irq-leaf-nodes", 4);
if (irq_leaves_num != int_reg_bits_num || irq_leaves_num <= 0) {
pr_err("Error getting irq-leaf-nodes: %d\n", irq_leaves_num);
ret = -EINVAL;
kfree(int_reg_bits);
return ret;
}
i = 0;
of_for_each_phandle (&it, ret, leaf_info, "irq-leaf-nodes", 0, 0) {
struct device_node *irq_group_node = of_node_get(it.node);
int leaf_interrupts_count;
const char *leaf_interrupt_name;
int32_t *leaf_indexes = NULL;
int j = 0;
leaf_interrupts_count =
of_property_count_strings(irq_group_node, "leaf-interrupt-names");
if (leaf_interrupts_count == -ENODATA) {
/* Does not have a value means no leaf interrupt is configured for this */
/* leaf node */
continue;
} else if (leaf_interrupts_count < 0) {
pr_err("Error counting leaf-interrupt-names for : %d\n",
leaf_interrupts_count);
ret = -EINVAL;
goto leaf_error;
}
leaf_indexes = kmalloc(sizeof(int32_t) * leaf_interrupts_count, GFP_KERNEL);
if (IS_ERR_OR_NULL(leaf_indexes)) {
ret = -ENOMEM;
goto leaf_error;
}
for (j = 0; j < leaf_interrupts_count; ++j) {
of_property_read_string_index(irq_group_node, "leaf-interrupt-names", j,
&leaf_interrupt_name);
leaf_indexes[j] = find_irq_index_by_name(list, leaf_interrupt_name);
if (leaf_indexes[j] < 0) {
ret = leaf_indexes[j];
pr_err("Cannot find leaf irq %s\n", leaf_interrupt_name);
kfree(leaf_indexes);
goto leaf_error;
}
}
ret = lwis_interrupt_add_leaf(list, index, int_reg_bits[i], leaf_interrupts_count,
leaf_indexes);
if (ret) {
pr_err("Error setting event info for interrupt %d %d\n", index, ret);
kfree(leaf_indexes);
goto leaf_error;
}
i++;
}
return 0;
leaf_error:
lwis_interrupt_free_leaves(&list->irq[index]);
kfree(int_reg_bits);
return ret;
}
static int parse_interrupts(struct lwis_device *lwis_dev)
{
int i;
int ret;
int count, event_infos_count;
const char *name;
struct device_node *dev_node;
struct platform_device *plat_dev;
struct of_phandle_iterator it;
plat_dev = lwis_dev->plat_dev;
dev_node = plat_dev->dev.of_node;
/* Test device type DEVICE_TYPE_TEST used for test, platform independent. */
if (lwis_dev->type == DEVICE_TYPE_TEST) {
count = TEST_DEVICE_IRQ_CNT;
} else {
count = platform_irq_count(plat_dev);
}
/* No interrupts found, just return */
if (count <= 0) {
lwis_dev->irqs = NULL;
return 0;
}
lwis_dev->irqs = lwis_interrupt_list_alloc(lwis_dev, count);
if (IS_ERR_OR_NULL(lwis_dev->irqs)) {
if (lwis_dev->type == DEVICE_TYPE_TEST) {
pr_err("Failed to allocate injection\n");
} else {
pr_err("Failed to allocate IRQ list\n");
}
ret = PTR_ERR(lwis_dev->irqs);
lwis_dev->irqs = NULL;
return ret;
}
for (i = 0; i < count; ++i) {
of_property_read_string_index(dev_node, "interrupt-names", i, &name);
ret = lwis_interrupt_init(lwis_dev->irqs, i, (char *)name);
if (ret) {
pr_err("Cannot initialize irq %s\n", name);
goto error_get_irq;
}
}
event_infos_count = of_property_count_elems_of_size(dev_node, "interrupt-event-infos", 4);
if (count != event_infos_count) {
pr_err("DT numbers of irqs: %d != event infos: %d in DT\n", count,
event_infos_count);
ret = -EINVAL;
goto error_get_irq;
}
/* Get event infos */
i = 0;
of_for_each_phandle (&it, ret, dev_node, "interrupt-event-infos", 0, 0) {
const char *irq_reg_space = NULL, *irq_type_str = NULL;
bool irq_mask_reg_toggle;
u64 irq_src_reg;
u64 irq_reset_reg;
u64 irq_mask_reg;
u64 irq_overflow_reg = 0;
int irq_reg_bid = -1;
int irq_reg_bid_count;
/* To match default value of reg-addr/value-bitwidth. */
u32 irq_reg_bitwidth = 32;
int32_t irq_type = REGULAR_INTERRUPT;
int j;
struct device_node *event_info = of_node_get(it.node);
ret = of_property_read_string(event_info, "irq-reg-space", &irq_reg_space);
if (ret) {
pr_err("Error getting irq-reg-space from dt: %d\n", ret);
goto error_event_infos;
}
irq_reg_bid_count = of_property_count_strings(dev_node, "reg-names");
if (irq_reg_bid_count <= 0) {
pr_err("Error getting reg-names from dt: %d\n", irq_reg_bid_count);
goto error_event_infos;
}
for (j = 0; j < irq_reg_bid_count; j++) {
const char *bid_name;
ret = of_property_read_string_index(dev_node, "reg-names", j, &bid_name);
if (ret) {
break;
}
if (!strcmp(bid_name, irq_reg_space)) {
irq_reg_bid = j;
break;
}
}
if (irq_reg_bid < 0) {
pr_err("Could not find a reg bid for %s\n", irq_reg_space);
goto error_event_infos;
}
ret = of_property_read_u64(event_info, "irq-src-reg", &irq_src_reg);
if (ret) {
pr_err("Error getting irq-src-reg from dt: %d\n", ret);
goto error_event_infos;
}
ret = of_property_read_u64(event_info, "irq-reset-reg", &irq_reset_reg);
if (ret) {
pr_err("Error getting irq-reset-reg from dt: %d\n", ret);
goto error_event_infos;
}
ret = of_property_read_u64(event_info, "irq-mask-reg", &irq_mask_reg);
if (ret) {
pr_err("Error getting irq-mask-reg from dt: %d\n", ret);
goto error_event_infos;
}
of_property_read_u64(event_info, "irq-overflow-reg", &irq_overflow_reg);
irq_mask_reg_toggle = of_property_read_bool(event_info, "irq-mask-reg-toggle");
of_property_read_u32(event_info, "irq-reg-bitwidth", &irq_reg_bitwidth);
ret = of_property_read_string(event_info, "irq-type", &irq_type_str);
if (ret && ret != -EINVAL) {
pr_err("Error getting irq-type from dt: %d\n", ret);
goto error_event_infos;
} else if (ret && ret == -EINVAL) {
/* The property does not exist, which means regular*/
irq_type = REGULAR_INTERRUPT;
} else {
if (strcmp(irq_type_str, "regular") == 0) {
irq_type = REGULAR_INTERRUPT;
} else if (strcmp(irq_type_str, "aggregate") == 0) {
irq_type = AGGREGATE_INTERRUPT;
} else if (strcmp(irq_type_str, "leaf") == 0) {
irq_type = LEAF_INTERRUPT;
} else if (strcmp(irq_type_str, "injection") == 0) {
irq_type = FAKEEVENT_INTERRUPT;
} else {
pr_err("Invalid irq-type from dt: %s\n", irq_type_str);
goto error_event_infos;
}
}
lwis_interrupt_set_basic_info(lwis_dev->irqs, i, irq_reg_space, irq_reg_bid,
irq_src_reg, irq_reset_reg, irq_mask_reg,
irq_overflow_reg, irq_mask_reg_toggle,
irq_reg_bitwidth, irq_type);
/* Register IRQ handler only for aggregate and regular interrupts */
if (irq_type == AGGREGATE_INTERRUPT || irq_type == REGULAR_INTERRUPT) {
ret = lwis_interrupt_get(lwis_dev->irqs, i, plat_dev);
if (ret) {
pr_err("Cannot set irq %s\n", name);
goto error_event_infos;
}
} else if (irq_type == FAKEEVENT_INTERRUPT) {
/*
* Hardcode the fake injection irq number to
* TEST_DEVICE_FAKE_INJECTION_IRQ
*/
lwis_dev->irqs->irq[i].irq = TEST_DEVICE_FAKE_INJECTION_IRQ;
}
/* Parse event info */
ret = parse_interrupts_event_info(lwis_dev->irqs, i, event_info);
if (ret) {
pr_err("Cannot set event info %s\n", name);
goto error_event_infos;
}
/* Parse leaf nodes if it's an aggregate interrupt */
if (irq_type == AGGREGATE_INTERRUPT) {
ret = parse_interrupt_leaf_nodes(lwis_dev->irqs, i, event_info);
if (ret) {
pr_err("Error setting leaf nodes for interrupt %d %d\n", i, ret);
goto error_event_infos;
}
}
of_node_put(event_info);
i++;
}
#ifdef LWIS_DT_DEBUG
lwis_interrupt_print(lwis_dev->irqs);
#endif
return 0;
error_event_infos:
for (i = 0; i < count; ++i) {
// TODO(yromanenko): lwis_interrupt_put
}
error_get_irq:
lwis_interrupt_list_free(lwis_dev->irqs);
lwis_dev->irqs = NULL;
return ret;
}
static int parse_phys(struct lwis_device *lwis_dev)
{
struct device *dev;
struct device_node *dev_node;
int i;
int ret;
int count;
const char *name;
dev = &(lwis_dev->plat_dev->dev);
dev_node = dev->of_node;
count = of_count_phandle_with_args(dev_node, "phys", "#phy-cells");
/* No PHY found, just return */
if (count <= 0) {
lwis_dev->phys = NULL;
return 0;
}
lwis_dev->phys = lwis_phy_list_alloc(count);
if (IS_ERR_OR_NULL(lwis_dev->phys)) {
pr_err("Failed to allocate PHY list\n");
ret = PTR_ERR(lwis_dev->phys);
lwis_dev->phys = NULL;
return ret;
}
for (i = 0; i < count; ++i) {
of_property_read_string_index(dev_node, "phy-names", i, &name);
ret = lwis_phy_get(lwis_dev->phys, (char *)name, dev);
if (ret < 0) {
pr_err("Error adding PHY[%d]\n", i);
goto error_parse_phy;
}
}
#ifdef LWIS_DT_DEBUG
lwis_phy_print(lwis_dev->phys);
#endif
return 0;
error_parse_phy:
for (i = 0; i < count; ++i) {
lwis_phy_put_by_idx(lwis_dev->phys, i, dev);
}
lwis_phy_list_free(lwis_dev->phys);
lwis_dev->phys = NULL;
return ret;
}
static void parse_bitwidths(struct lwis_device *lwis_dev)
{
int __maybe_unused ret;
struct device *dev;
struct device_node *dev_node;
u32 addr_bitwidth = 32;
u32 value_bitwidth = 32;
dev = &(lwis_dev->plat_dev->dev);
dev_node = dev->of_node;
of_property_read_u32(dev_node, "reg-addr-bitwidth", &addr_bitwidth);
#ifdef LWIS_DT_DEBUG
pr_info("Addr bitwidth set to: %d\n", addr_bitwidth);
#endif
of_property_read_u32(dev_node, "reg-value-bitwidth", &value_bitwidth);
#ifdef LWIS_DT_DEBUG
pr_info("Value bitwidth set to: %d\n", value_bitwidth);
#endif
lwis_dev->native_addr_bitwidth = addr_bitwidth;
lwis_dev->native_value_bitwidth = value_bitwidth;
}
static int parse_power_seqs(struct lwis_device *lwis_dev, const char *seq_name,
struct lwis_device_power_sequence_list **list,
struct device_node *dev_node_seq)
{
char str_seq_name[LWIS_MAX_NAME_STRING_LEN];
char str_seq_type[LWIS_MAX_NAME_STRING_LEN];
char str_seq_delay[LWIS_MAX_NAME_STRING_LEN];
struct device *dev;
struct device_node *dev_node;
int power_seq_count;
int power_seq_type_count;
int power_seq_delay_count;
int i;
int ret;
const char *name;
const char *type;
int delay_us;
int type_gpio_count = 0;
int type_regulator_count = 0;
scnprintf(str_seq_name, LWIS_MAX_NAME_STRING_LEN, "%s-seqs", seq_name);
scnprintf(str_seq_type, LWIS_MAX_NAME_STRING_LEN, "%s-seq-types", seq_name);
scnprintf(str_seq_delay, LWIS_MAX_NAME_STRING_LEN, "%s-seq-delays-us", seq_name);
dev = &lwis_dev->plat_dev->dev;
dev_node = dev->of_node;
*list = NULL;
if (dev_node_seq) {
dev_node = dev_node_seq;
}
power_seq_count = of_property_count_strings(dev_node, str_seq_name);
power_seq_type_count = of_property_count_strings(dev_node, str_seq_type);
power_seq_delay_count =
of_property_count_elems_of_size(dev_node, str_seq_delay, sizeof(u32));
/* No power-seqs found, just return */
if (power_seq_count <= 0) {
return 0;
}
if (power_seq_count != power_seq_type_count || power_seq_count != power_seq_delay_count) {
pr_err("Count of power sequence %s is not match\n", str_seq_name);
return -EINVAL;
}
*list = lwis_dev_power_seq_list_alloc(power_seq_count);
if (IS_ERR_OR_NULL(*list)) {
pr_err("Failed to allocate power sequence list\n");
ret = PTR_ERR(*list);
*list = NULL;
return ret;
}
for (i = 0; i < power_seq_count; ++i) {
ret = of_property_read_string_index(dev_node, str_seq_name, i, &name);
if (ret < 0) {
pr_err("Error adding power sequence[%d]\n", i);
goto error_parse_power_seqs;
}
strscpy((*list)->seq_info[i].name, name, LWIS_MAX_NAME_STRING_LEN);
ret = of_property_read_string_index(dev_node, str_seq_type, i, &type);
if (ret < 0) {
pr_err("Error adding power sequence type[%d]\n", i);
goto error_parse_power_seqs;
}
strscpy((*list)->seq_info[i].type, type, LWIS_MAX_NAME_STRING_LEN);
if (strcmp(type, "gpio") == 0) {
type_gpio_count++;
} else if (strcmp(type, "regulator") == 0) {
type_regulator_count++;
}
ret = of_property_read_u32_index(dev_node, str_seq_delay, i, &delay_us);
if (ret < 0) {
pr_err("Error adding power sequence delay[%d]\n", i);
goto error_parse_power_seqs;
}
(*list)->seq_info[i].delay_us = delay_us;
}
#ifdef LWIS_DT_DEBUG
lwis_dev_power_seq_list_print(*list);
#endif
if (type_gpio_count > 0 && lwis_dev->gpios_list == NULL) {
lwis_dev->gpios_list = lwis_gpios_list_alloc(type_gpio_count);
if (IS_ERR_OR_NULL(lwis_dev->gpios_list)) {
pr_err("Failed to allocate gpios list\n");
ret = PTR_ERR(lwis_dev->gpios_list);
goto error_parse_power_seqs;
}
type_gpio_count = 0;
for (i = 0; i < power_seq_count; ++i) {
struct lwis_gpios_info *gpios_info;
char *seq_item_name;
struct device *dev;
struct gpio_descs *descs;
if (strcmp((*list)->seq_info[i].type, "gpio") != 0) {
continue;
}
gpios_info = &lwis_dev->gpios_list->gpios_info[type_gpio_count];
seq_item_name = (*list)->seq_info[i].name;
dev = &lwis_dev->plat_dev->dev;
descs = lwis_gpio_list_get(dev, seq_item_name);
if (IS_ERR_OR_NULL(descs)) {
pr_err("Error parsing GPIO list %s (%ld)\n", seq_item_name,
PTR_ERR(descs));
ret = PTR_ERR(descs);
goto error_parse_power_seqs;
}
gpios_info->id = desc_to_gpio(descs->desc[0]);
gpios_info->hold_dev = dev;
/*
* The GPIO pins are valid, release the list as we do not need to hold
* on to the pins yet
*/
lwis_gpio_list_put(descs, dev);
gpios_info->gpios = NULL;
gpios_info->irq_list = NULL;
strscpy(gpios_info->name, seq_item_name, LWIS_MAX_NAME_STRING_LEN);
if (strncmp(SHARED_STRING, seq_item_name, strlen(SHARED_STRING)) == 0) {
gpios_info->is_shared = true;
} else {
gpios_info->is_shared = false;
}
if (strncmp(PULSE_STRING, seq_item_name, strlen(PULSE_STRING)) == 0) {
gpios_info->is_pulse = true;
} else {
gpios_info->is_pulse = false;
}
type_gpio_count++;
}
}
if (type_regulator_count > 0 && lwis_dev->regulators == NULL) {
lwis_dev->regulators = lwis_regulator_list_alloc(type_regulator_count);
if (IS_ERR_OR_NULL(lwis_dev->regulators)) {
pr_err("Failed to allocate regulator list\n");
ret = PTR_ERR(lwis_dev->regulators);
goto error_parse_power_seqs;
}
for (i = 0; i < power_seq_count; ++i) {
struct device *dev;
char *seq_item_name;
if (strcmp((*list)->seq_info[i].type, "regulator") != 0) {
continue;
}
dev = &lwis_dev->plat_dev->dev;
seq_item_name = (*list)->seq_info[i].name;
ret = lwis_regulator_get(lwis_dev->regulators, seq_item_name,
/*voltage=*/0, dev);
if (ret < 0) {
pr_err("Cannot find regulator: %s\n", seq_item_name);
goto error_parse_power_seqs;
}
}
}
return 0;
error_parse_power_seqs:
if (lwis_dev->regulators) {
lwis_regulator_put_all(lwis_dev->regulators);
lwis_regulator_list_free(lwis_dev->regulators);
lwis_dev->regulators = NULL;
}
lwis_gpios_list_free(lwis_dev->gpios_list);
lwis_dev->gpios_list = NULL;
lwis_dev_power_seq_list_free(*list);
*list = NULL;
return ret;
}
static int parse_unified_power_seqs(struct lwis_device *lwis_dev)
{
struct device *dev;
struct device_node *dev_node;
struct device_node *dev_node_seq;
int count;
int ret = 0;
dev = &lwis_dev->plat_dev->dev;
dev_node = dev->of_node;
count = of_property_count_elems_of_size(dev_node, "power-seq", sizeof(u32));
/* No power-seq found, or entry does not exist, just return */
if (count <= 0) {
lwis_dev->power_seq_handler = NULL;
return 0;
}
dev_node_seq = of_parse_phandle(dev_node, "power-seq", 0);
if (!dev_node_seq) {
pr_err("Can't get power-seq node\n");
return -EINVAL;
}
ret = parse_power_seqs(lwis_dev, "power-up", &lwis_dev->power_up_sequence, dev_node_seq);
if (ret) {
pr_err("Error parsing power-up-seqs\n");
return ret;
}
ret = parse_power_seqs(lwis_dev, "power-down", &lwis_dev->power_down_sequence,
dev_node_seq);
if (ret) {
pr_err("Error parsing power-down-seqs\n");
return ret;
}
lwis_dev->power_seq_handler = dev_node_seq;
return ret;
}
static int parse_pm_hibernation(struct lwis_device *lwis_dev)
{
struct device_node *dev_node;
dev_node = lwis_dev->plat_dev->dev.of_node;
lwis_dev->pm_hibernation = 1;
of_property_read_u32(dev_node, "pm-hibernation", &lwis_dev->pm_hibernation);
return 0;
}
static int parse_access_mode(struct lwis_device *lwis_dev)
{
struct device_node *dev_node;
dev_node = lwis_dev->plat_dev->dev.of_node;
lwis_dev->is_read_only = of_property_read_bool(dev_node, "lwis,read-only");
return 0;
}
static int parse_thread_priority(struct lwis_device *lwis_dev)
{
struct device_node *dev_node;
dev_node = lwis_dev->plat_dev->dev.of_node;
lwis_dev->transaction_thread_priority = 0;
of_property_read_u32(dev_node, "transaction-thread-priority",
&lwis_dev->transaction_thread_priority);
return 0;
}
static int parse_i2c_lock_group_id(struct lwis_i2c_device *i2c_dev)
{
struct device_node *dev_node;
int ret;
dev_node = i2c_dev->base_dev.plat_dev->dev.of_node;
/* Set i2c_lock_group_id value to default */
i2c_dev->i2c_lock_group_id = MAX_I2C_LOCK_NUM - 1;
ret = of_property_read_u32(dev_node, "i2c-lock-group-id", &i2c_dev->i2c_lock_group_id);
/* If no property in device tree, just return to use default */
if (ret == -EINVAL) {
return 0;
}
if (ret) {
pr_err("i2c-lock-group-id value wrong\n");
return ret;
}
if (i2c_dev->i2c_lock_group_id >= MAX_I2C_LOCK_NUM - 1) {
pr_err("i2c-lock-group-id need smaller than MAX_I2C_LOCK_NUM - 1\n");
return -EOVERFLOW;
}
return 0;
}
int lwis_base_parse_dt(struct lwis_device *lwis_dev)
{
struct device *dev;
struct device_node *dev_node;
const char *name_str;
int ret = 0;
dev = &(lwis_dev->plat_dev->dev);
dev_node = dev->of_node;
if (!dev_node) {
pr_err("Cannot find device node\n");
return -ENODEV;
}
ret = of_property_read_string(dev_node, "node-name", &name_str);
if (ret) {
pr_err("Error parsing node name\n");
return -EINVAL;
}
strscpy(lwis_dev->name, name_str, LWIS_MAX_NAME_STRING_LEN);
pr_debug("Device tree entry [%s] - begin\n", lwis_dev->name);
ret = parse_gpios(lwis_dev, "shared-enable", &lwis_dev->shared_enable_gpios_present);
if (ret) {
pr_err("Error parsing shared-enable-gpios\n");
return ret;
}
ret = parse_gpios(lwis_dev, "enable", &lwis_dev->enable_gpios_present);
if (ret) {
pr_err("Error parsing enable-gpios\n");
return ret;
}
ret = parse_gpios(lwis_dev, "reset", &lwis_dev->reset_gpios_present);
if (ret) {
pr_err("Error parsing reset-gpios\n");
return ret;
}
ret = parse_irq_gpios(lwis_dev);
if (ret) {
pr_err("Error parsing irq-gpios\n");
return ret;
}
ret = parse_unified_power_seqs(lwis_dev);
if (ret) {
pr_err("Error parse_unified_power_seqs\n");
return ret;
}
if (lwis_dev->power_up_sequence == NULL) {
ret = parse_power_seqs(lwis_dev, "power-up", &lwis_dev->power_up_sequence, NULL);
if (ret) {
pr_err("Error parsing power-up-seqs\n");
return ret;
}
}
if (lwis_dev->power_down_sequence == NULL) {
ret = parse_power_seqs(lwis_dev, "power-down", &lwis_dev->power_down_sequence,
NULL);
if (ret) {
pr_err("Error parsing power-down-seqs\n");
return ret;
}
}
ret = parse_power_seqs(lwis_dev, "suspend", &lwis_dev->suspend_sequence, NULL);
if (ret) {
pr_err("Error parsing suspend-seqs\n");
return ret;
}
ret = parse_power_seqs(lwis_dev, "resume", &lwis_dev->resume_sequence, NULL);
if (ret) {
pr_err("Error parsing resume-seqs\n");
return ret;
}
ret = parse_settle_time(lwis_dev);
if (ret) {
pr_err("Error parsing settle-time\n");
return ret;
}
if (lwis_dev->regulators == NULL) {
ret = parse_regulators(lwis_dev);
if (ret) {
pr_err("Error parsing regulators\n");
return ret;
}
}
ret = parse_clocks(lwis_dev);
if (ret) {
pr_err("Error parsing clocks\n");
return ret;
}
ret = parse_pinctrls(lwis_dev, "mclk_on");
if (ret) {
pr_err("Error parsing mclk pinctrls\n");
return ret;
}
ret = parse_interrupts(lwis_dev);
if (ret) {
pr_err("Error parsing interrupts\n");
return ret;
}
ret = parse_phys(lwis_dev);
if (ret) {
pr_err("Error parsing phy's\n");
return ret;
}
ret = parse_pm_hibernation(lwis_dev);
if (ret) {
pr_err("Error parsing pm hibernation\n");
return ret;
}
parse_access_mode(lwis_dev);
parse_thread_priority(lwis_dev);
parse_bitwidths(lwis_dev);
lwis_dev->bts_scenario_name = NULL;
of_property_read_string(dev_node, "bts-scenario", &lwis_dev->bts_scenario_name);
dev_node->data = lwis_dev;
pr_debug("Device tree entry [%s] - end\n", lwis_dev->name);
return ret;
}
int lwis_i2c_device_parse_dt(struct lwis_i2c_device *i2c_dev)
{
struct device_node *dev_node;
struct device_node *dev_node_i2c;
int ret;
dev_node = i2c_dev->base_dev.plat_dev->dev.of_node;
dev_node_i2c = of_parse_phandle(dev_node, "i2c-bus", 0);
if (!dev_node_i2c) {
dev_err(i2c_dev->base_dev.dev, "Cannot find i2c-bus node\n");
return -ENODEV;
}
i2c_dev->adapter = of_find_i2c_adapter_by_node(dev_node_i2c);
if (!i2c_dev->adapter) {
dev_err(i2c_dev->base_dev.dev, "Cannot find i2c adapter\n");
return -ENODEV;
}
ret = of_property_read_u32(dev_node, "i2c-addr", (u32 *)&i2c_dev->address);
if (ret) {
dev_err(i2c_dev->base_dev.dev, "Failed to read i2c-addr\n");
return ret;
}
ret = parse_i2c_lock_group_id(i2c_dev);
if (ret) {
dev_err(i2c_dev->base_dev.dev, "Error parsing i2c lock group id\n");
return ret;
}
return 0;
}
int lwis_ioreg_device_parse_dt(struct lwis_ioreg_device *ioreg_dev)
{
struct device_node *dev_node;
int i;
int ret;
int blocks;
int reg_tuple_size;
const char *name;
dev_node = ioreg_dev->base_dev.plat_dev->dev.of_node;
reg_tuple_size = of_n_addr_cells(dev_node) + of_n_size_cells(dev_node);
blocks = of_property_count_elems_of_size(dev_node, "reg", reg_tuple_size * sizeof(u32));
if (blocks <= 0) {
dev_err(ioreg_dev->base_dev.dev, "No register space found\n");
return -EINVAL;
}
ret = lwis_ioreg_list_alloc(ioreg_dev, blocks);
if (ret) {
dev_err(ioreg_dev->base_dev.dev, "Failed to allocate ioreg list\n");
return ret;
}
for (i = 0; i < blocks; ++i) {
of_property_read_string_index(dev_node, "reg-names", i, &name);
ret = lwis_ioreg_get(ioreg_dev, i, (char *)name);
if (ret) {
dev_err(ioreg_dev->base_dev.dev, "Cannot set ioreg info for %s\n", name);
goto error_ioreg;
}
}
return 0;
error_ioreg:
for (i = 0; i < blocks; ++i) {
lwis_ioreg_put_by_idx(ioreg_dev, i);
}
lwis_ioreg_list_free(ioreg_dev);
return ret;
}
int lwis_top_device_parse_dt(struct lwis_top_device *top_dev)
{
/* To be implemented */
return 0;
}
int lwis_test_device_parse_dt(struct lwis_test_device *test_dev)
{
/* To be implemented */
return 0;
}