sdk-hwV1.3/lichee/linux-4.9/sound/soc/sunxi_v2/snd_sunxi_common.c

262 lines
5.8 KiB
C

/*
* sound\soc\sunxi\snd_sunxi_common.c
* (C) Copyright 2021-2025
* AllWinner Technology Co., Ltd. <www.allwinnertech.com>
* Dby <dby@allwinnertech.com>
*
* 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 <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <linux/of.h>
#include <linux/clk.h>
#include <linux/reset.h>
#include <linux/device.h>
#include <linux/ioport.h>
#include <linux/regmap.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#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;
}