#include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include /* * Reads the GPIO config from an "avm,avm_gpio_generic" compatible node and * copies the data into the given struct _avm_hw_config */ static int read_avm_gpio_generic(struct device_node *gpio_node, struct _avm_hw_config *hw_cfg) { const uint32_t *prop __maybe_unused; uint32_t prop_found, tmp, numElems __maybe_unused; int i; pr_debug("[%s] Called. gpio_node: %p hw_cfg: %p\n", __func__, gpio_node, hw_cfg); // clear target hw_cfg memset(hw_cfg, 0x0, sizeof(*hw_cfg)); //read the name hw_cfg->name = (char *) of_get_property(gpio_node, "name", &i); pr_debug("[DTB] read gpio %s\n", hw_cfg->name); if (!(hw_cfg->name)) { //couldn't read name return -ENOMSG; } //read the value prop_found = of_property_read_u32(gpio_node, "value", &tmp); if (!prop_found) { hw_cfg->value = tmp; } //read the param prop_found = of_property_read_u32(gpio_node, "param", &tmp); if (!prop_found) { hw_cfg->param = tmp; } else { hw_cfg->param = avm_hw_param_no_param; } #if defined(CONFIG_AVM_PWM) if (hw_cfg->param == avm_hw_param_gpio_out_rgb || hw_cfg->param == avm_hw_param_gpio_out_rgb_active_low) { prop_found = of_property_read_u32(gpio_node, "red", &tmp); if (!prop_found) { hw_cfg->rgb_gpio_red = tmp; } prop_found = of_property_read_u32(gpio_node, "green", &tmp); if (!prop_found) { hw_cfg->rgb_gpio_green = tmp; } prop_found = of_property_read_u32(gpio_node, "blue", &tmp); if (!prop_found) { hw_cfg->rgb_gpio_blue = tmp; } } prop_found = of_property_read_u32(gpio_node, "value_overwrite", &tmp); if (!prop_found) { hw_cfg->value_overwrite = tmp; } else { hw_cfg->value_overwrite = -1; } #endif return 0; } /* * Finds all AVM GPIO Entries in the device tree and generates the hw_config_table from it */ int avm_generate_hw_config_table_from_device_tree(void) { struct device_node *node; uint8_t populated; int gpio_cnt, result; const char *of_compatible = "avm,avm_gpio_generic"; struct device_node *gpio_node; pr_err("Creating Config Table\n"); //loop through device tree, find all avm gpios, count them, allocate memory populated = of_have_populated_dt(); if (!populated) { pr_err("[DTB] No populated device tree found\n"); mdelay(10); panic("[DTB] No populated device tree found\n"); } gpio_cnt = 0; //loop over all compatible nodes, check there module_id and increment gpio_cnt if the module_id is greater than zero node = NULL; while (NULL != (node = of_find_compatible_node(node, NULL, of_compatible))) { gpio_cnt += of_get_child_count(node); } pr_debug("[%s] gpio_cnt: %d\n", __func__, gpio_cnt); // allocate one more GPIO than actually needed to have an end of config marker in the // config table, where the name is NULL avm_current_hw_config = kzalloc((gpio_cnt + 1) * sizeof(struct _avm_hw_config), GFP_KERNEL); if (!avm_current_hw_config) { panic("[DTB] Error allocating mem for config table\n"); } // copy device tree data to hw_config if (gpio_cnt > 0) { gpio_cnt = 0; node = NULL; while (NULL != (node = of_find_compatible_node(node, NULL, of_compatible))) { for_each_child_of_node(node, gpio_node) { result = read_avm_gpio_generic(gpio_node, &(avm_current_hw_config[gpio_cnt])); if (result != 0) { pr_err("[DTB] Error reading GPIO from device tree\n"); return -ENOMSG; } gpio_cnt++; } } } pr_debug("[DTB] Found %i compatible gpios 'avm,avm_gpio_generic' with module_id>0\n", gpio_cnt); pr_debug("[DTB] Device Table generated\n"); init_gpio_config(); pr_debug("[DTB] GPIOs configurated.\n"); return 0; } postcore_initcall(avm_generate_hw_config_table_from_device_tree); /* * Reads Interrupt Information from the Device Tree * Finds the Interrupt specified by irq_name and stores the information in cpu_used, cpu_mask and int_num * @param int_name: the name of the interrupt to find * @param cpu_used: pointer to store the cpu_used information * @param cpu_mask: pointer to store the cpu_mask information * @param int_num: pointer to store the int_num information */ int get_interrupt_info_from_device_tree(const char *int_name, int32_t *cpu_used, int32_t *cpu_mask, int32_t *int_num) { struct device_node *node, *child; uint8_t populated; uint32_t prop_found; int len, result; char *namecmp; const char *of_compatible = "avm,avm_interrupt"; result = -ENOENT; populated = of_have_populated_dt(); if (!populated) { pr_debug("[%s]Device Tree not populated, cannot read interrupt information\n", __func__); result = -ENOMSG; goto err_out; } node = NULL; while (NULL != (node = of_find_compatible_node(node, NULL, of_compatible)) && result != 0) { for_each_child_of_node(node, child) { namecmp = (char *) of_get_property(child, "name", &len); if (namecmp == NULL) { continue; } if (strcmp(namecmp, int_name)) { continue; } //names match, read info if (cpu_used) { prop_found = of_property_read_u32(child, "cpu_used", cpu_used); if (prop_found) { pr_debug("[DTB] Couldn't read cpu_used property!\n"); result = -ENOMSG; goto err_out; } } if (cpu_mask) { prop_found = of_property_read_u32(child, "cpu_mask", cpu_mask); if (prop_found) { pr_debug("[DTB] Couldn't read cpu_mask property!\n"); result = -ENOMSG; goto err_out; } } if (int_num) { prop_found = of_property_read_u32(child, "int_num", int_num); if (prop_found) { pr_debug("[DTB] Couldn't read int_num property!\n"); result = -ENOMSG; goto err_out; } } result = 0; } } err_out: return result; }