From c761f28171e3c70660c05fce0297562802476ae2 Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Thu, 10 Oct 2019 01:07:44 +0800 Subject: 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 Change-Id: I9550b9890ce2cae787f4f17779a5ade77f619171 Reviewed-on: https://review.coreboot.org/c/coreboot/+/36029 Tested-by: build bot (Jenkins) Reviewed-by: Furquan Shaikh --- src/drivers/i2c/rt1011/Kconfig | 4 ++ src/drivers/i2c/rt1011/Makefile.inc | 1 + src/drivers/i2c/rt1011/chip.h | 31 +++++++++ src/drivers/i2c/rt1011/rt1011.c | 123 ++++++++++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+) create mode 100644 src/drivers/i2c/rt1011/Kconfig create mode 100644 src/drivers/i2c/rt1011/Makefile.inc create mode 100644 src/drivers/i2c/rt1011/chip.h create mode 100644 src/drivers/i2c/rt1011/rt1011.c (limited to 'src') diff --git a/src/drivers/i2c/rt1011/Kconfig b/src/drivers/i2c/rt1011/Kconfig new file mode 100644 index 0000000000..f7951966f0 --- /dev/null +++ b/src/drivers/i2c/rt1011/Kconfig @@ -0,0 +1,4 @@ +config DRIVERS_I2C_RT1011 + bool + default n + depends on HAVE_ACPI_TABLES diff --git a/src/drivers/i2c/rt1011/Makefile.inc b/src/drivers/i2c/rt1011/Makefile.inc new file mode 100644 index 0000000000..a8b8283f3f --- /dev/null +++ b/src/drivers/i2c/rt1011/Makefile.inc @@ -0,0 +1 @@ +ramstage-$(CONFIG_DRIVERS_I2C_RT1011) += rt1011.c diff --git a/src/drivers/i2c/rt1011/chip.h b/src/drivers/i2c/rt1011/chip.h new file mode 100644 index 0000000000..6bbddac3fd --- /dev/null +++ b/src/drivers/i2c/rt1011/chip.h @@ -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 + +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; +}; diff --git a/src/drivers/i2c/rt1011/rt1011.c b/src/drivers/i2c/rt1011/rt1011.c new file mode 100644 index 0000000000..792992e355 --- /dev/null +++ b/src/drivers/i2c/rt1011/rt1011.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 +}; -- cgit v1.2.3