/* * sound\soc\sunxi\snd_sunxi_common.c * (C) Copyright 2021-2025 * AllWinner Technology Co., Ltd. * Dby * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "snd_sunxi_log.h" #include "snd_sunxi_common.h" #define HLOG "COMMON" /* for regmap */ int snd_sunxi_mem_init(struct platform_device *pdev, struct sunxi_mem *mem) { int ret = 0; struct device_node *np = pdev->dev.of_node; SND_LOG_DEBUG(HLOG, "\n"); ret = of_address_to_resource(np, 0, mem->res); if (ret) { SND_LOG_ERR(HLOG, "parse device node resource failed\n"); ret = -EINVAL; goto err_of_addr_to_resource; } mem->memregion = devm_request_mem_region(&pdev->dev, mem->res->start, resource_size(mem->res), mem->dev_name); if (IS_ERR_OR_NULL(mem->memregion)) { SND_LOG_ERR(HLOG, "memory region already claimed\n"); ret = -EBUSY; goto err_devm_request_region; } mem->membase = devm_ioremap(&pdev->dev, mem->memregion->start, resource_size(mem->memregion)); if (IS_ERR_OR_NULL(mem->membase)) { SND_LOG_ERR(HLOG, "ioremap failed\n"); ret = -EBUSY; goto err_devm_ioremap; } mem->regmap = devm_regmap_init_mmio(&pdev->dev, mem->membase, mem->regmap_config); if (IS_ERR_OR_NULL(mem->regmap)) { SND_LOG_ERR(HLOG, "regmap init failed\n"); ret = -EINVAL; goto err_devm_regmap_init; } return 0; err_devm_regmap_init: devm_iounmap(&pdev->dev, mem->membase); err_devm_ioremap: devm_release_mem_region(&pdev->dev, mem->memregion->start, resource_size(mem->memregion)); err_devm_request_region: err_of_addr_to_resource: return ret; } void snd_sunxi_mem_exit(struct platform_device *pdev, struct sunxi_mem *mem) { SND_LOG_DEBUG(HLOG, "\n"); devm_iounmap(&pdev->dev, mem->membase); devm_release_mem_region(&pdev->dev, mem->memregion->start, resource_size(mem->memregion)); } /* for REG LABEL */ int snd_sunxi_save_reg(struct regmap *regmap, struct reg_label *reg_labels) { int i = 0; SND_LOG_DEBUG(HLOG, "\n"); while (reg_labels[i].name != NULL) { regmap_read(regmap, reg_labels[i].address, &(reg_labels[i].value)); i++; } return i; } int snd_sunxi_echo_reg(struct regmap *regmap, struct reg_label *reg_labels) { int i = 0; SND_LOG_DEBUG(HLOG, "\n"); while (reg_labels[i].name != NULL) { regmap_write(regmap, reg_labels[i].address, reg_labels[i].value); i++; } return i; } /* for pa config */ struct pa_config *snd_sunxi_pa_pin_init(struct platform_device *pdev, u32 *pa_pin_max) { int ret, i; u32 pin_max; u32 gpio_tmp; u32 temp_val; char str[20] = {0}; struct pa_config *pa_cfg; struct device_node *np = pdev->dev.of_node; SND_LOG_DEBUG(HLOG, "\n"); *pa_pin_max = 0; ret = of_property_read_u32(np, "pa-pin-max", &temp_val); if (ret < 0) { SND_LOG_WARN(HLOG, "pa-pin-max get failed, default 0\n"); return NULL; } else { pin_max = temp_val; } pa_cfg = kzalloc(sizeof(struct pa_config) * pin_max, GFP_KERNEL); if (!pa_cfg) { SND_LOG_ERR(HLOG, "can't pa_config memory\n"); return NULL; } for (i = 0; i < pin_max; i++) { sprintf(str, "pa-pin-%d", i); ret = of_get_named_gpio(np, str, 0); if (ret < 0) { SND_LOG_ERR(HLOG, "pa-pin-%u get failed\n", i); pa_cfg[i].used = 0; continue; } gpio_tmp = ret; if (!gpio_is_valid(gpio_tmp)) { SND_LOG_ERR(HLOG, "pa-pin-%u (%u) is invalid\n", i, gpio_tmp); pa_cfg[i].used = 0; continue; } ret = devm_gpio_request(&pdev->dev, gpio_tmp, str); if (ret) { SND_LOG_ERR(HLOG, "pa-pin-%u (%u) request failed\n", i, gpio_tmp); pa_cfg[i].used = 0; continue; } pa_cfg[i].used = 1; pa_cfg[i].pin = gpio_tmp; sprintf(str, "pa-pin-level-%d", i); ret = of_property_read_u32(np, str, &temp_val); if (ret < 0) { SND_LOG_WARN(HLOG, "%s get failed, default low\n", str); pa_cfg[i].level = 0; } else { if (temp_val > 0) pa_cfg[i].level = 1; } sprintf(str, "pa-pin-msleep-%d", i); ret = of_property_read_u32(np, str, &temp_val); if (ret < 0) { SND_LOG_WARN(HLOG, "%s get failed, default 0\n", str); pa_cfg[i].msleep = 0; } else { pa_cfg[i].msleep = temp_val; } } *pa_pin_max = pin_max; snd_sunxi_pa_pin_disable(pa_cfg, pin_max); return pa_cfg; } void snd_sunxi_pa_pin_exit(struct platform_device *pdev, struct pa_config *pa_cfg, u32 pa_pin_max) { int i; SND_LOG_DEBUG(HLOG, "\n"); snd_sunxi_pa_pin_disable(pa_cfg, pa_pin_max); for (i = 0; i < pa_pin_max; i++) { if (!pa_cfg[i].used) continue; devm_gpio_free(&pdev->dev, pa_cfg[i].pin); } if (pa_cfg) kfree(pa_cfg); } int snd_sunxi_pa_pin_enable(struct pa_config *pa_cfg, u32 pa_pin_max) { int i; SND_LOG_DEBUG(HLOG, "\n"); if (pa_pin_max < 1) { SND_LOG_DEBUG(HLOG, "no pa pin config\n"); return 0; } msleep(pa_cfg[0].msleep); for (i = 0; i < pa_pin_max; i++) { if (!pa_cfg[i].used) continue; gpio_direction_output(pa_cfg[i].pin, 1); gpio_set_value(pa_cfg[i].pin, pa_cfg[i].level); } return 0; } int snd_sunxi_pa_pin_disable(struct pa_config *pa_cfg, u32 pa_pin_max) { int i; SND_LOG_DEBUG(HLOG, "\n"); if (pa_pin_max < 1) { SND_LOG_DEBUG(HLOG, "no pa pin config\n"); return 0; } for (i = 0; i < pa_pin_max; i++) { if (!pa_cfg[i].used) continue; gpio_direction_output(pa_cfg[i].pin, 1); gpio_set_value(pa_cfg[i].pin, !pa_cfg[i].level); } return 0; }