blob: ba6074cac574c230b52f38c672ca022f64a9e047 [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(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 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;
int i;
/* Initialize the data structure */
strlcpy(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));
if (count != event_count || count != name_count) {
pr_err("Count of irq-gpios-* is not match\n");
return -EINVAL;
}
gpios = lwis_gpio_list_get(dev, "irq");
if (IS_ERR(gpios)) {
pr_err("Error parsing irq GPIO list (%ld)\n", PTR_ERR(gpios));
return PTR_ERR(gpios);
}
lwis_dev->irq_gpios_info.gpios = 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;
}
strlcpy(irq_gpios_names + i * LWIS_MAX_NAME_STRING_LEN, name,
LWIS_MAX_NAME_STRING_LEN);
}
ret = lwis_gpio_list_to_irqs(lwis_dev, &lwis_dev->irq_gpios_info, irq_gpios_names);
if (ret) {
pr_err("Error get GPIO irq list (%d)\n", ret);
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;
}
}
kfree(irq_gpios_names);
kfree(irq_gpios_events);
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 (irq_gpios_names) {
kfree(irq_gpios_names);
}
if (irq_gpios_events) {
kfree(irq_gpios_events);
}
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(lwis_dev->regulators)) {
pr_err("Cannot allocate regulator list\n");
return PTR_ERR(lwis_dev->regulators);
}
/* 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;
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(lwis_dev->clocks)) {
pr_err("Cannot allocate clocks list\n");
return PTR_ERR(lwis_dev->clocks);
}
/* 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;
#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(pc)) {
pr_err("Cannot allocate pinctrl\n");
return PTR_ERR(pc);
}
pinctrl_state = pinctrl_lookup_state(pc, expected_state);
if (IS_ERR(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_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(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;
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(lwis_dev->irqs)) {
pr_err("Failed to allocate IRQ list\n");
return PTR_ERR(lwis_dev->irqs);
}
for (i = 0; i < count; ++i) {
of_property_read_string_index(dev_node, "interrupt-names", i, &name);
ret = lwis_interrupt_get(lwis_dev->irqs, i, (char *)name, plat_dev);
if (ret) {
pr_err("Cannot set 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;
bool irq_mask_reg_toggle;
u64 irq_src_reg;
u64 irq_reset_reg;
u64 irq_mask_reg;
int irq_events_num;
int int_reg_bits_num;
int critical_events_num = 0;
u64 *irq_events;
u32 *int_reg_bits;
u64 *critical_events = NULL;
int irq_reg_bid = -1;
int irq_reg_bid_count;
/* To match default value of reg-addr/value-bitwidth. */
u32 irq_reg_bitwidth = 32;
int j;
struct device_node *event_info = of_node_get(it.node);
irq_events_num = of_property_count_elems_of_size(event_info, "irq-events", 8);
if (irq_events_num <= 0) {
pr_err("Error getting irq-events: %d\n", irq_events_num);
ret = -EINVAL;
goto error_event_infos;
}
int_reg_bits_num = of_property_count_elems_of_size(event_info, "int-reg-bits", 4);
if (irq_events_num != int_reg_bits_num || int_reg_bits_num <= 0) {
pr_err("Error getting int-reg-bits: %d\n", int_reg_bits_num);
ret = -EINVAL;
goto error_event_infos;
}
irq_events = kmalloc(sizeof(u64) * irq_events_num, GFP_KERNEL);
if (IS_ERR_OR_NULL(irq_events)) {
ret = -ENOMEM;
goto error_event_infos;
}
int_reg_bits = kmalloc(sizeof(u32) * int_reg_bits_num, GFP_KERNEL);
if (IS_ERR_OR_NULL(int_reg_bits)) {
ret = -ENOMEM;
kfree(irq_events);
goto error_event_infos;
}
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;
kfree(irq_events);
kfree(int_reg_bits);
goto error_event_infos;
}
int_reg_bits_num =
of_property_read_variable_u32_array(event_info, "int-reg-bits",
int_reg_bits, int_reg_bits_num,
int_reg_bits_num);
if (irq_events_num != int_reg_bits_num) {
pr_err("Error getting int-reg-bits: %d\n", int_reg_bits_num);
ret = int_reg_bits_num;
kfree(irq_events);
kfree(int_reg_bits);
goto error_event_infos;
}
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);
kfree(irq_events);
kfree(int_reg_bits);
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);
kfree(irq_events);
kfree(int_reg_bits);
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);
kfree(irq_events);
kfree(int_reg_bits);
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);
kfree(irq_events);
kfree(int_reg_bits);
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);
kfree(irq_events);
kfree(int_reg_bits);
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);
kfree(irq_events);
kfree(int_reg_bits);
goto error_event_infos;
}
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);
critical_events_num = parse_critical_irq_events(event_info, &critical_events);
ret = lwis_interrupt_set_event_info(
lwis_dev->irqs, i, irq_reg_space, irq_reg_bid, (int64_t *)irq_events,
irq_events_num, int_reg_bits, int_reg_bits_num, irq_src_reg, irq_reset_reg,
irq_mask_reg, irq_mask_reg_toggle, irq_reg_bitwidth,
(int64_t *)critical_events, critical_events_num);
if (ret) {
pr_err("Error setting event info for interrupt %d %d\n", i, ret);
if (critical_events) {
kfree(critical_events);
}
kfree(irq_events);
kfree(int_reg_bits);
goto error_event_infos;
}
of_node_put(event_info);
i++;
if (critical_events) {
kfree(critical_events);
}
kfree(irq_events);
kfree(int_reg_bits);
}
#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(lwis_dev->phys)) {
pr_err("Failed to allocate PHY list\n");
return PTR_ERR(lwis_dev->phys);
}
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)
{
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%s: %d\n", ret ? " default" : "", addr_bitwidth);
#endif
of_property_read_u32(dev_node, "reg-value-bitwidth", &value_bitwidth);
#ifdef LWIS_DT_DEBUG
pr_info("Value bitwidth set to%s: %d\n", ret ? " default" : "", value_bitwidth);
#endif
lwis_dev->native_addr_bitwidth = addr_bitwidth;
lwis_dev->native_value_bitwidth = value_bitwidth;
}
static int parse_power_up_seqs(struct lwis_device *lwis_dev)
{
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;
dev = &lwis_dev->plat_dev->dev;
dev_node = dev->of_node;
lwis_dev->power_up_seqs_present = false;
lwis_dev->power_up_sequence = NULL;
lwis_dev->gpios_list = NULL;
power_seq_count = of_property_count_strings(dev_node, "power-up-seqs");
power_seq_type_count = of_property_count_strings(dev_node, "power-up-seq-types");
power_seq_delay_count =
of_property_count_elems_of_size(dev_node, "power-up-seq-delays-us", sizeof(u32));
/* No power-up-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-up-seqs-* are not match\n");
return -EINVAL;
}
lwis_dev->power_up_sequence = lwis_dev_power_seq_list_alloc(power_seq_count);
if (IS_ERR(lwis_dev->power_up_sequence)) {
pr_err("Failed to allocate power sequence list\n");
return PTR_ERR(lwis_dev->power_up_sequence);
}
for (i = 0; i < power_seq_count; ++i) {
ret = of_property_read_string_index(dev_node, "power-up-seqs", i, &name);
if (ret < 0) {
pr_err("Error adding power sequence[%d]\n", i);
goto error_parse_power_up_seqs;
}
strlcpy(lwis_dev->power_up_sequence->seq_info[i].name, name,
LWIS_MAX_NAME_STRING_LEN);
ret = of_property_read_string_index(dev_node, "power-up-seq-types", i, &type);
if (ret < 0) {
pr_err("Error adding power sequence type[%d]\n", i);
goto error_parse_power_up_seqs;
}
strlcpy(lwis_dev->power_up_sequence->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, "power-up-seq-delays-us", i, &delay_us);
if (ret < 0) {
pr_err("Error adding power sequence delay[%d]\n", i);
goto error_parse_power_up_seqs;
}
lwis_dev->power_up_sequence->seq_info[i].delay_us = delay_us;
}
#ifdef LWIS_DT_DEBUG
lwis_dev_power_seq_list_print(lwis_dev->power_up_sequence);
#endif
lwis_dev->power_up_seqs_present = true;
if (type_gpio_count > 0) {
lwis_dev->gpios_list = lwis_gpios_list_alloc(type_gpio_count);
if (IS_ERR(lwis_dev->gpios_list)) {
pr_err("Failed to allocate gpios list\n");
ret = PTR_ERR(lwis_dev->gpios_list);
goto error_parse_power_up_seqs;
}
type_gpio_count = 0;
for (i = 0; i < power_seq_count; ++i) {
struct lwis_gpios_info *gpios_info;
char *seq_item_name;
if (strcmp(lwis_dev->power_up_sequence->seq_info[i].type, "gpio") != 0) {
continue;
}
gpios_info = &lwis_dev->gpios_list->gpios_info[type_gpio_count];
seq_item_name = lwis_dev->power_up_sequence->seq_info[i].name;
gpios_info->gpios = NULL;
gpios_info->irq_list = NULL;
strlcpy(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 = lwis_regulator_list_alloc(type_regulator_count);
if (IS_ERR(lwis_dev->regulators)) {
pr_err("Failed to allocate regulator list\n");
ret = PTR_ERR(lwis_dev->regulators);
goto error_parse_power_up_seqs;
}
for (i = 0; i < power_seq_count; ++i) {
struct device *dev;
char *seq_item_name;
if (strcmp(lwis_dev->power_up_sequence->seq_info[i].type,
"regulator") != 0) {
continue;
}
dev = &lwis_dev->plat_dev->dev;
seq_item_name = lwis_dev->power_up_sequence->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_up_seqs;
}
}
}
return 0;
error_parse_power_up_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(lwis_dev->power_up_sequence);
lwis_dev->power_up_sequence = NULL;
return ret;
}
static int parse_power_down_seqs(struct lwis_device *lwis_dev)
{
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;
dev = &lwis_dev->plat_dev->dev;
dev_node = dev->of_node;
lwis_dev->power_down_seqs_present = false;
lwis_dev->power_down_sequence = NULL;
power_seq_count = of_property_count_strings(dev_node, "power-down-seqs");
power_seq_type_count = of_property_count_strings(dev_node, "power-down-seq-types");
power_seq_delay_count =
of_property_count_elems_of_size(dev_node, "power-down-seq-delays-us", sizeof(u32));
/* No power-down-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-down-seqs-* are not match\n");
return -EINVAL;
}
lwis_dev->power_down_sequence = lwis_dev_power_seq_list_alloc(power_seq_count);
if (IS_ERR(lwis_dev->power_down_sequence)) {
pr_err("Failed to allocate power sequence list\n");
return PTR_ERR(lwis_dev->power_down_sequence);
}
for (i = 0; i < power_seq_count; ++i) {
ret = of_property_read_string_index(dev_node, "power-down-seqs", i, &name);
if (ret < 0) {
pr_err("Error adding power sequence[%d]\n", i);
goto error_parse_power_down_seqs;
}
strlcpy(lwis_dev->power_down_sequence->seq_info[i].name, name,
LWIS_MAX_NAME_STRING_LEN);
ret = of_property_read_string_index(dev_node, "power-down-seq-types", i, &type);
if (ret < 0) {
pr_err("Error adding power sequence type[%d]\n", i);
goto error_parse_power_down_seqs;
}
strlcpy(lwis_dev->power_down_sequence->seq_info[i].type, type,
LWIS_MAX_NAME_STRING_LEN);
ret = of_property_read_u32_index(dev_node, "power-down-seq-delays-us", i,
&delay_us);
if (ret < 0) {
pr_err("Error adding power sequence delay[%d]\n", i);
goto error_parse_power_down_seqs;
}
lwis_dev->power_down_sequence->seq_info[i].delay_us = delay_us;
}
#ifdef LWIS_DT_DEBUG
lwis_dev_power_seq_list_print(lwis_dev->power_down_sequence);
#endif
lwis_dev->power_down_seqs_present = true;
return 0;
error_parse_power_down_seqs:
lwis_dev_power_seq_list_free(lwis_dev->power_down_sequence);
lwis_dev->power_down_sequence = NULL;
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;
lwis_dev->periodic_io_thread_priority = 0;
of_property_read_u32(dev_node, "transaction-thread-priority",
&lwis_dev->transaction_thread_priority);
of_property_read_u32(dev_node, "periodic-io-thread-priority",
&lwis_dev->periodic_io_thread_priority);
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;
}
strlcpy(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_power_up_seqs(lwis_dev);
if (ret) {
pr_err("Error parsing power-up-seqs\n");
return ret;
}
ret = parse_power_down_seqs(lwis_dev);
if (ret) {
pr_err("Error parsing power-down-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");
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;
}
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;
}