#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; } #if defined(CONFIG_MACH_FUSIV) prop_found = of_property_read_u32(gpio_node, "mode", &tmp); if(!prop_found){ hw_cfg->manufactor_hw_config.manufactor_ikanos_gpio_config.mode = tmp; } prop_found = of_property_read_u32(gpio_node, "dir", &tmp); if(!prop_found){ hw_cfg->manufactor_hw_config.manufactor_ikanos_gpio_config.dir = tmp; } prop_found = of_property_read_u32(gpio_node, "func_sel", &tmp); if(!prop_found){ hw_cfg->manufactor_hw_config.manufactor_ikanos_gpio_config.func_sel = tmp; } prop_found = of_property_read_u32(gpio_node, "func_val", &tmp); if(!prop_found){ hw_cfg->manufactor_hw_config.manufactor_ikanos_gpio_config.func_val = tmp; } #else //read config numElems = 0; prop = of_get_property(gpio_node, "config", &numElems); numElems /= sizeof(uint32_t); //combine the GPIO config by bitwise OR for (i = 0; i < numElems; i++){ hw_cfg->manufactor_hw_config.manufactor_lantiq_gpio_config.config |= *(prop++); } //read module_id numElems = 0; prop = of_get_property(gpio_node, "module_id", &numElems); numElems /= sizeof(uint32_t); //combine the GPIO config by bitwise OR for (i = 0; i < numElems; i++){ hw_cfg->manufactor_hw_config.manufactor_lantiq_gpio_config.module_id |= *(prop++); } pr_debug("[DTB] read gpio %s pin %d config 0x%08x module id 0x%x\n", hw_cfg->name, hw_cfg->value, hw_cfg->manufactor_hw_config.manufactor_lantiq_gpio_config.config , hw_cfg->manufactor_hw_config.manufactor_lantiq_gpio_config.module_id); #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_err("[%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; } core_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; }