drivers/i2c/rt1011: Add a driver for RT1011

RT1011 is a smart amplifier. It needs to know speaker related parameters
including speaker resistor value and temperature when the calibration is
done in order to run Dynamic Speaker Management (DSM) algorithm on chip.
The purpose of DSM is to protect speaker when the volume is large.

The calibration data of speaker is stored in VPD in factory.
This driver is needed to read data from VPD and write to ACPI _DSD when
config CHROMEOS_DSM_CALIB is turned on.

Kernel rt1011 codec driver will read these device properties to set up
codec accordingly on boot.

The reason to prepare these parameters in coreboot is because kernel
codec driver expects to read per-device parameters directly from device
properties. Another benefit is that other OS can also take these
parameters through ACPI _DSD table and take benefit of DSM on RT1011.

The kernel driver device properties of RT1011 are documented at
linux/Documentation/devicetree/bindings/sound/rt1011.txt
It is currently in ASoC maintainer's tree at
https://kernel.googlesource.com/pub/scm/linux/kernel/git/broonie/sound/+/for-next/
and hopefully should be merged to mainline kernel in the next merge window.

BUG=b:140397934
BRANCH=none
TEST=On Helios, with patch series, check realtek,r0_calib and
realtek,temperature_calib are available to rt1011 codec driver.

Signed-off-by: Cheng-Yi Chiang <cychiang@chromium.org>
Change-Id: I9550b9890ce2cae787f4f17779a5ade77f619171
Reviewed-on: https://review.coreboot.org/c/coreboot/+/36029
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Furquan Shaikh <furquan@google.com>
This commit is contained in:
Cheng-Yi Chiang 2019-10-10 01:07:44 +08:00 committed by Patrick Georgi
parent cfde82c1d7
commit c761f28171
4 changed files with 159 additions and 0 deletions

View File

@ -0,0 +1,4 @@
config DRIVERS_I2C_RT1011
bool
default n
depends on HAVE_ACPI_TABLES

View File

@ -0,0 +1 @@
ramstage-$(CONFIG_DRIVERS_I2C_RT1011) += rt1011.c

View File

@ -0,0 +1,31 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2019 Google Inc.
*
* 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; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/*
* Realtek RT1011 audio codec devicetree bindings
*/
#include <stdint.h>
struct drivers_i2c_rt1011_config {
const char *name; /* ACPI Device Name */
const char *desc; /* Device Description */
unsigned int uid; /* ACPI _UID */
/* The VPD key of calibrated speaker resistance. */
const char *r0_calib_key;
/* The VPD key of temperature during speaker calibration. */
const char *temperature_calib_key;
};

View File

@ -0,0 +1,123 @@
/*
* This file is part of the coreboot project.
*
* Copyright 2019 Google Inc.
*
* 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; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <arch/acpi.h>
#include <arch/acpi_device.h>
#include <arch/acpigen.h>
#include <console/console.h>
#include <device/i2c.h>
#include <device/device.h>
#include <device/path.h>
#include <stdint.h>
#include <vendorcode/google/chromeos/chromeos.h>
#include "chip.h"
#define RT1011_ACPI_HID "10EC1011"
#define RT1011_DP_INT(key, val) acpi_dp_add_integer(dp, "realtek," key, (val))
static void rt1011_fill_ssdt(struct device *dev)
{
struct drivers_i2c_rt1011_config *config = dev->chip_info;
const char *scope = acpi_device_scope(dev);
struct acpi_i2c i2c = {
.address = dev->path.i2c.device,
.mode_10bit = dev->path.i2c.mode_10bit,
.speed = I2C_SPEED_FAST,
.resource = scope,
};
struct acpi_dp *dp;
uint64_t r0_value, temp_value;
if (!dev->enabled || !scope)
return;
/* Device */
acpigen_write_scope(scope);
acpigen_write_device(acpi_device_name(dev));
acpigen_write_name_string("_HID", RT1011_ACPI_HID);
acpigen_write_name_integer("_UID", config->uid);
acpigen_write_name_string("_DDN", config->desc);
acpigen_write_STA(acpi_device_status(dev));
/* Resources */
acpigen_write_name("_CRS");
acpigen_write_resourcetemplate_header();
acpi_device_write_i2c(&i2c);
acpigen_write_resourcetemplate_footer();
/* Device Properties */
if (CONFIG(CHROMEOS_DSM_CALIB)) {
if (get_dsm_calibration_from_key(config->r0_calib_key, &r0_value)
|| get_dsm_calibration_from_key(config->temperature_calib_key,
&temp_value)) {
printk(BIOS_ERR,
"Failed to get dsm_calib parameters from VPD"
" with key %s and %s\n",
config->r0_calib_key, config->temperature_calib_key);
} else {
dp = acpi_dp_new_table("_DSD");
RT1011_DP_INT("r0_calib", r0_value);
RT1011_DP_INT("temperature_calib", temp_value);
acpi_dp_write(dp);
printk(BIOS_INFO, "set dsm_calib properties\n");
}
}
acpigen_pop_len(); /* Device */
acpigen_pop_len(); /* Scope */
printk(BIOS_INFO, "%s: %s address 0%xh\n", acpi_device_path(dev), dev->chip_ops->name,
dev->path.i2c.device);
}
static const char *rt1011_acpi_name(const struct device *dev)
{
struct drivers_i2c_rt1011_config *config = dev->chip_info;
static char name[5];
if (config->name)
return config->name;
snprintf(name, sizeof(name), "D%03.3X", dev->path.i2c.device);
return name;
}
static struct device_operations rt1011_ops = {
.read_resources = DEVICE_NOOP,
.set_resources = DEVICE_NOOP,
.enable_resources = DEVICE_NOOP,
.acpi_name = rt1011_acpi_name,
.acpi_fill_ssdt_generator = rt1011_fill_ssdt,
};
static void rt1011_enable(struct device *dev)
{
struct drivers_i2c_rt1011_config *config = dev->chip_info;
if (!config)
return;
dev->ops = &rt1011_ops;
/* Name the device as per description provided in devicetree */
if (config->desc)
dev->name = config->desc;
}
struct chip_operations drivers_i2c_rt1011_ops = {
CHIP_NAME("Realtek RT1011 Codec")
.enable_dev = rt1011_enable
};