diff options
author | aszlig <aszlig@redmoonstudios.org> | 2017-06-23 11:05:29 +0200 |
---|---|---|
committer | aszlig <aszlig@redmoonstudios.org> | 2017-06-23 11:08:52 +0200 |
commit | 358a4d445986945efea85b1949fd07e56122f7bd (patch) | |
tree | 6acfce1c194a2c5c2824279c349b474e76fefada /modules | |
parent | 2c708510d5be18a2776c4fa79c13e8a3c1a73805 (diff) |
hardware/t100ha: Update patches for kernel 4.12
We can now safely drop the sound, sdio and drm patches, because they all have been applied upstream already and after some testing the T100HA works quite nicely. One exception however is a small part from the drm patch, which is the PMIC hack which I originally introduced in e8861698f019eb218be451e444898a1cb5577d21 as a separate file which it's now again, but rebased against kernel 4.12-rc6. Signed-off-by: aszlig <aszlig@redmoonstudios.org>
Diffstat (limited to 'modules')
-rw-r--r-- | modules/hardware/t100ha/backlight.patch | 223 | ||||
-rw-r--r-- | modules/hardware/t100ha/default.nix | 12 | ||||
-rw-r--r-- | modules/hardware/t100ha/drm.patch | 733 | ||||
-rw-r--r-- | modules/hardware/t100ha/sdio.patch | 52 | ||||
-rw-r--r-- | modules/hardware/t100ha/sound.patch | 5620 |
5 files changed, 226 insertions, 6414 deletions
diff --git a/modules/hardware/t100ha/backlight.patch b/modules/hardware/t100ha/backlight.patch new file mode 100644 index 00000000..a83d6659 --- /dev/null +++ b/modules/hardware/t100ha/backlight.patch @@ -0,0 +1,223 @@ +diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c +index fc0ef492252a..f9bf7290a2bb 100644 +--- a/drivers/gpu/drm/i915/intel_dsi.c ++++ b/drivers/gpu/drm/i915/intel_dsi.c +@@ -644,6 +644,7 @@ static void intel_dsi_port_enable(struct intel_encoder *encoder) + struct drm_i915_private *dev_priv = to_i915(dev); + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); ++ struct intel_connector *intel_connector = intel_dsi->attached_connector; + enum port port; + + if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) { +@@ -665,6 +666,8 @@ static void intel_dsi_port_enable(struct intel_encoder *encoder) + } + } + ++ intel_panel_disable_backlight(intel_connector); ++ + for_each_dsi_port(port, intel_dsi->ports) { + i915_reg_t port_ctrl = IS_GEN9_LP(dev_priv) ? + BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port); +@@ -1635,6 +1638,7 @@ static void intel_dsi_connector_destroy(struct drm_connector *connector) + + DRM_DEBUG_KMS("\n"); + intel_panel_fini(&intel_connector->panel); ++ intel_panel_destroy_backlight(connector); + drm_connector_cleanup(connector); + kfree(connector); + } +diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c +index cb50c527401f..0dae84db6303 100644 +--- a/drivers/gpu/drm/i915/intel_panel.c ++++ b/drivers/gpu/drm/i915/intel_panel.c +@@ -32,6 +32,7 @@ + + #include <linux/kernel.h> + #include <linux/moduleparam.h> ++#include <linux/mfd/intel_soc_pmic.h> + #include <linux/pwm.h> + #include "intel_drv.h" + +@@ -542,6 +543,11 @@ static u32 pwm_get_backlight(struct intel_connector *connector) + return DIV_ROUND_UP(duty_ns * 100, CRC_PMIC_PWM_PERIOD_NS); + } + ++static u32 vlv_pmic_get_backlight(struct intel_connector *connector) ++{ ++ return intel_soc_pmic_readb(0x4E); ++} ++ + static u32 intel_panel_get_backlight(struct intel_connector *connector) + { + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +@@ -633,6 +639,11 @@ static void pwm_set_backlight(struct intel_connector *connector, u32 level) + pwm_config(panel->backlight.pwm, duty_ns, CRC_PMIC_PWM_PERIOD_NS); + } + ++static void vlv_pmic_set_backlight(struct intel_connector *connector, u32 level) ++{ ++ intel_soc_pmic_writeb(0x4E, level); ++} ++ + static void + intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level) + { +@@ -806,6 +817,14 @@ static void pwm_disable_backlight(struct intel_connector *connector) + pwm_disable(panel->backlight.pwm); + } + ++static void vlv_pmic_disable_backlight(struct intel_connector *connector) ++{ ++ intel_panel_actually_set_backlight(connector, 0); ++ ++ intel_soc_pmic_writeb(0x51, 0x00); ++ intel_soc_pmic_writeb(0x4B, 0x7F); ++} ++ + void intel_panel_disable_backlight(struct intel_connector *connector) + { + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +@@ -1084,6 +1103,17 @@ static void pwm_enable_backlight(struct intel_connector *connector) + intel_panel_actually_set_backlight(connector, panel->backlight.level); + } + ++static void vlv_pmic_enable_backlight(struct intel_connector *connector) ++{ ++ struct intel_panel *panel = &connector->panel; ++ ++ intel_soc_pmic_writeb(0x4B, 0xFF); ++ intel_soc_pmic_writeb(0x4E, 0xFF); ++ intel_soc_pmic_writeb(0x51, 0x01); ++ ++ intel_panel_actually_set_backlight(connector, panel->backlight.level); ++} ++ + void intel_panel_enable_backlight(struct intel_connector *connector) + { + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); +@@ -1673,6 +1703,20 @@ static int pwm_setup_backlight(struct intel_connector *connector, + return 0; + } + ++static int vlv_pmic_setup_backlight(struct intel_connector *connector, ++ enum pipe unused) ++{ ++ struct intel_panel *panel = &connector->panel; ++ ++ panel->backlight.present = 1; ++ panel->backlight.min = 0x00; ++ panel->backlight.max = 0xFF; ++ panel->backlight.level = 0x5A; ++ panel->backlight.enabled = 1; ++ ++ return 0; ++} ++ + int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe) + { + struct drm_i915_private *dev_priv = to_i915(connector->dev); +@@ -1680,6 +1724,8 @@ int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe) + struct intel_panel *panel = &intel_connector->panel; + int ret; + ++ intel_backlight_device_register(intel_connector); ++ + if (!dev_priv->vbt.backlight.present) { + if (dev_priv->quirks & QUIRK_BACKLIGHT_PRESENT) { + DRM_DEBUG_KMS("no backlight present per VBT, but present per quirk\n"); +@@ -1769,18 +1815,17 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel) + panel->backlight.hz_to_pwm = pch_hz_to_pwm; + } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { + if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI) { +- panel->backlight.setup = pwm_setup_backlight; +- panel->backlight.enable = pwm_enable_backlight; +- panel->backlight.disable = pwm_disable_backlight; +- panel->backlight.set = pwm_set_backlight; +- panel->backlight.get = pwm_get_backlight; ++ panel->backlight.setup = vlv_pmic_setup_backlight; ++ panel->backlight.enable = vlv_pmic_enable_backlight; ++ panel->backlight.disable = vlv_pmic_disable_backlight; ++ panel->backlight.set = vlv_pmic_set_backlight; ++ panel->backlight.get = vlv_pmic_get_backlight; + } else { + panel->backlight.setup = vlv_setup_backlight; + panel->backlight.enable = vlv_enable_backlight; + panel->backlight.disable = vlv_disable_backlight; + panel->backlight.set = vlv_set_backlight; + panel->backlight.get = vlv_get_backlight; +- panel->backlight.hz_to_pwm = vlv_hz_to_pwm; + } + } else if (IS_GEN4(dev_priv)) { + panel->backlight.setup = i965_setup_backlight; +diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c +index 13737be6df35..60880fdbdccf 100644 +--- a/drivers/mfd/intel_soc_pmic_core.c ++++ b/drivers/mfd/intel_soc_pmic_core.c +@@ -44,6 +44,8 @@ static struct pwm_lookup crc_pwm_lookup[] = { + PWM_LOOKUP("crystal_cove_pwm", 0, "0000:00:02.0", "pwm_backlight", 0, PWM_POLARITY_NORMAL), + }; + ++static struct intel_soc_pmic *pmic_hack = NULL; ++ + static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *i2c_id) + { +@@ -60,6 +62,7 @@ static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c, + config = (struct intel_soc_pmic_config *)id->driver_data; + + pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); ++ pmic_hack = pmic; + if (!pmic) + return -ENOMEM; + +@@ -147,6 +150,37 @@ static int intel_soc_pmic_resume(struct device *dev) + } + #endif + ++int intel_soc_pmic_readb(int reg) ++{ ++ int ret; ++ unsigned int val; ++ ++ if (!pmic_hack) { ++ ret = -EIO; ++ } else { ++ ret = regmap_read(pmic_hack->regmap, reg, &val); ++ if (!ret) { ++ ret = val; ++ } ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL(intel_soc_pmic_readb); ++ ++int intel_soc_pmic_writeb(int reg, u8 val) ++{ ++ int ret; ++ ++ if (!pmic_hack) { ++ ret = -EIO; ++ } else { ++ ret = regmap_write(pmic_hack->regmap, reg, val); ++ } ++ return ret; ++} ++EXPORT_SYMBOL(intel_soc_pmic_writeb); ++ + static SIMPLE_DEV_PM_OPS(intel_soc_pmic_pm_ops, intel_soc_pmic_suspend, + intel_soc_pmic_resume); + +diff --git a/include/linux/mfd/intel_soc_pmic.h b/include/linux/mfd/intel_soc_pmic.h +index 956caa0628f5..2adff16a60c3 100644 +--- a/include/linux/mfd/intel_soc_pmic.h ++++ b/include/linux/mfd/intel_soc_pmic.h +@@ -30,4 +30,7 @@ struct intel_soc_pmic { + struct device *dev; + }; + ++int intel_soc_pmic_readb(int reg); ++int intel_soc_pmic_writeb(int reg, u8 val); ++ + #endif /* __INTEL_SOC_PMIC_H__ */ diff --git a/modules/hardware/t100ha/default.nix b/modules/hardware/t100ha/default.nix index 70a9fc38..c8635dcf 100644 --- a/modules/hardware/t100ha/default.nix +++ b/modules/hardware/t100ha/default.nix @@ -20,23 +20,17 @@ in { ''); boot.kernelPatches = [ - { name = "drm"; - patch = ./drm.patch; + { name = "backlight"; + patch = ./backlight.patch; } { name = "meta-keys"; patch = ./meta-keys.patch; } - { name = "sdio"; - patch = ./sdio.patch; - } - { name = "sound"; - patch = ./sound.patch; - } ]; boot.kernelPackages = let nixpkgs = import ../../../nixpkgs-path.nix; - t100haKernel = pkgs.linux_4_9.override { + t100haKernel = pkgs.linux_testing.override { # Missing device drivers: # # 808622B8 -> Intel(R) Imaging Signal Processor 2401 diff --git a/modules/hardware/t100ha/drm.patch b/modules/hardware/t100ha/drm.patch deleted file mode 100644 index 167be86d..00000000 --- a/modules/hardware/t100ha/drm.patch +++ /dev/null @@ -1,733 +0,0 @@ -diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h -index 8405b5a367d7..7e3545f65257 100644 ---- a/drivers/gpu/drm/i915/intel_bios.h -+++ b/drivers/gpu/drm/i915/intel_bios.h -@@ -46,14 +46,20 @@ struct edp_power_seq { - u16 t11_t12; - } __packed; - --/* MIPI Sequence Block definitions */ -+/* -+ * MIPI Sequence Block definitions -+ * -+ * Note the VBT spec has AssertReset / DeassertReset swapped from their -+ * usual naming, we use the proper names here to avoid confusion when -+ * reading the code. -+ */ - enum mipi_seq { - MIPI_SEQ_END = 0, -- MIPI_SEQ_ASSERT_RESET, -+ MIPI_SEQ_DEASSERT_RESET, /* Spec says MipiAssertResetPin */ - MIPI_SEQ_INIT_OTP, - MIPI_SEQ_DISPLAY_ON, - MIPI_SEQ_DISPLAY_OFF, -- MIPI_SEQ_DEASSERT_RESET, -+ MIPI_SEQ_ASSERT_RESET, /* Spec says MipiDeassertResetPin */ - MIPI_SEQ_BACKLIGHT_ON, /* sequence block v2+ */ - MIPI_SEQ_BACKLIGHT_OFF, /* sequence block v2+ */ - MIPI_SEQ_TEAR_ON, /* sequence block v2+ */ -diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c -index c9e83f39ec0a..6a6ae51996d0 100644 ---- a/drivers/gpu/drm/i915/intel_display.c -+++ b/drivers/gpu/drm/i915/intel_display.c -@@ -13764,6 +13764,13 @@ static void update_scanline_offset(struct intel_crtc *crtc) - * type. For DP ports it behaves like most other platforms, but on HDMI - * there's an extra 1 line difference. So we need to add two instead of - * one to the value. -+ * -+ * On VLV/CHV DSI the scanline counter would appear to increment -+ * approx. 1/3 of a scanline before start of vblank. Unfortunately -+ * that we can't tell whether we're in vblank or not while we're -+ * on that particular line. We must set scanline_offset to 1 so -+ * that the vblank timestamps come out correct when we query -+ * the scanline counter from the vblank interrupt handler. - */ - if (IS_GEN2(dev)) { - const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; -diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c -index b2e3d3a334f7..c07ef5e9de95 100644 ---- a/drivers/gpu/drm/i915/intel_dsi.c -+++ b/drivers/gpu/drm/i915/intel_dsi.c -@@ -80,7 +80,7 @@ enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt) - } - } - --static void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi, enum port port) -+void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi, enum port port) - { - struct drm_encoder *encoder = &intel_dsi->base.base; - struct drm_device *dev = encoder->dev; -@@ -505,37 +505,83 @@ static void intel_dsi_port_disable(struct intel_encoder *encoder) - } - } - --static void intel_dsi_enable(struct intel_encoder *encoder) --{ -- struct drm_device *dev = encoder->base.dev; -- struct drm_i915_private *dev_priv = to_i915(dev); -- struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); -- enum port port; -- -- DRM_DEBUG_KMS("\n"); -- -- if (is_cmd_mode(intel_dsi)) { -- for_each_dsi_port(port, intel_dsi->ports) -- I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(port), 8 * 4); -- } else { -- msleep(20); /* XXX */ -- for_each_dsi_port(port, intel_dsi->ports) -- dpi_send_cmd(intel_dsi, TURN_ON, false, port); -- msleep(100); -- -- drm_panel_enable(intel_dsi->panel); -+static void intel_dsi_prepare(struct intel_encoder *intel_encoder, -+ struct intel_crtc_state *pipe_config); - -- for_each_dsi_port(port, intel_dsi->ports) -- wait_for_dsi_fifo_empty(intel_dsi, port); -+static void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec) -+{ -+ struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev); - -- intel_dsi_port_enable(encoder); -- } -+ /* For v3 VBTs in vid-mode the delays are part of the VBT sequences */ -+ if (is_vid_mode(intel_dsi) && dev_priv->vbt.dsi.seq_version >= 3) -+ return; - -- intel_panel_enable_backlight(intel_dsi->attached_connector); -+ msleep(msec); - } - --static void intel_dsi_prepare(struct intel_encoder *intel_encoder, -- struct intel_crtc_state *pipe_config); -+/* -+ * Panel enable/disable sequences from the spec: -+ * -+ * v2 sequence for video mode: -+ * - power on -+ * - wait t1+t2 -+ * - MIPIDeassertResetPin -+ * - clk/data lines to lp-11 -+ * - MIPISendInitialDcsCmds -+ * - turn on DPI -+ * - MIPIDisplayOn -+ * - wait t5 -+ * - backlight on -+ * ... -+ * - backlight off -+ * - wait t6 -+ * - MIPIDisplayOff -+ * - turn off DPI -+ * - clk/data lines to lp-00 -+ * - MIPIAssertResetPin -+ * - wait t3 -+ * - power off -+ * - wait t4 -+ * -+ * v3 sequence for video mode: -+ * - MIPIPanelPowerOn -+ * - MIPIDeassertResetPin -+ * - set clk/data lines to lp-11 -+ * - MIPISendInitialDcsCmds (LP) -+ * - turn on DPI -+ * - MIPITearOn (command mode only) + MIPIDisplayOn (LP and HS) -+ * - MIPIBacklightOn -+ * ... -+ * - MIPIBacklightOff -+ * - turn off DPI -+ * - MIPITearOff + MIPIDisplayOff (LP) -+ * - clk/data lines to lp-00 -+ * - MIPIAssertResetPin -+ * - MIPIPanelPowerOff -+ * -+ * sequence for command mode: -+ * - power on -+ * - wait t1+t2 -+ * - MIPIDeassertResetPin -+ * - clk/data lines to lp-11 -+ * - MIPISendInitialDcsCmds -+ * - MIPITearOn -+ * - MIPIDisplayOn -+ * - set pipe to dsr mode -+ * - wait t5 -+ * - backlight on -+ * ... issue write_mem_start/write_mem_continue commands ... -+ * - backlight off -+ * - wait t6 -+ * - disable pipe dsr mode -+ * - MIPITearOff -+ * - MIPIDisplayOff -+ * - clk/data lines to lp-00 -+ * - MIPIAssertResetPin -+ * - wait t3 -+ * - power off -+ * - wait t4 -+ */ - - static void intel_dsi_pre_enable(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, -@@ -554,14 +600,6 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder, - intel_disable_dsi_pll(encoder); - intel_enable_dsi_pll(encoder, pipe_config); - -- intel_dsi_prepare(encoder, pipe_config); -- -- /* Panel Enable over CRC PMIC */ -- if (intel_dsi->gpio_panel) -- gpiod_set_value_cansleep(intel_dsi->gpio_panel, 1); -- -- msleep(intel_dsi->panel_on_delay); -- - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { - u32 val; - -@@ -571,17 +609,44 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder, - I915_WRITE(DSPCLK_GATE_D, val); - } - -- /* put device in ready state */ -- intel_dsi_device_ready(encoder); -+ intel_dsi_prepare(encoder, pipe_config); -+ -+ /* Power on, try both CRC pmic gpio and VBT */ -+ if (intel_dsi->gpio_panel) -+ gpiod_set_value_cansleep(intel_dsi->gpio_panel, 1); -+ intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_POWER_ON); -+ intel_dsi_msleep(intel_dsi, intel_dsi->panel_on_delay); - -- drm_panel_prepare(intel_dsi->panel); -+ /* Deassert reset */ -+ intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET); - -- for_each_dsi_port(port, intel_dsi->ports) -- wait_for_dsi_fifo_empty(intel_dsi, port); -+ /* Put device in ready state (LP-11) */ -+ intel_dsi_device_ready(encoder); -+ -+ /* Send initialization commands in LP mode */ -+ intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_INIT_OTP); - - /* Enable port in pre-enable phase itself because as per hw team - * recommendation, port should be enabled befor plane & pipe */ -- intel_dsi_enable(encoder); -+ if (is_cmd_mode(intel_dsi)) { -+ for_each_dsi_port(port, intel_dsi->ports) -+ I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(port), 8 * 4); -+ intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_TEAR_ON); -+ intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON); -+ } else { -+ msleep(20); /* XXX */ -+ for_each_dsi_port(port, intel_dsi->ports) -+ dpi_send_cmd(intel_dsi, TURN_ON, false, port); -+ intel_dsi_msleep(intel_dsi, 100); -+ -+ intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON); -+ -+ intel_dsi_port_enable(encoder); -+ } -+ -+ /* Enable backlight, both pwm and VBT */ -+ intel_panel_enable_backlight(intel_dsi->attached_connector); -+ intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON); - } - - static void intel_dsi_enable_nop(struct intel_encoder *encoder, -@@ -605,8 +670,15 @@ static void intel_dsi_pre_disable(struct intel_encoder *encoder, - - DRM_DEBUG_KMS("\n"); - -+ /* Disable backlight, both VBT and pwm */ -+ intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_OFF); - intel_panel_disable_backlight(intel_dsi->attached_connector); - -+ /* -+ * XXX: According to the spec we should send SHUTDOWN before -+ * MIPI_SEQ_DISPLAY_OFF only for v3+ VBTs, but testing in the field -+ * has shown that we should do this for v2 VBTs too? -+ */ - if (is_vid_mode(intel_dsi)) { - /* Send Shutdown command to the panel in LP mode */ - for_each_dsi_port(port, intel_dsi->ports) -@@ -615,45 +687,6 @@ static void intel_dsi_pre_disable(struct intel_encoder *encoder, - } - } - --static void intel_dsi_disable(struct intel_encoder *encoder) --{ -- struct drm_device *dev = encoder->base.dev; -- struct drm_i915_private *dev_priv = to_i915(dev); -- struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); -- enum port port; -- u32 temp; -- -- DRM_DEBUG_KMS("\n"); -- -- if (is_vid_mode(intel_dsi)) { -- for_each_dsi_port(port, intel_dsi->ports) -- wait_for_dsi_fifo_empty(intel_dsi, port); -- -- intel_dsi_port_disable(encoder); -- msleep(2); -- } -- -- for_each_dsi_port(port, intel_dsi->ports) { -- /* Panel commands can be sent when clock is in LP11 */ -- I915_WRITE(MIPI_DEVICE_READY(port), 0x0); -- -- intel_dsi_reset_clocks(encoder, port); -- I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP); -- -- temp = I915_READ(MIPI_DSI_FUNC_PRG(port)); -- temp &= ~VID_MODE_FORMAT_MASK; -- I915_WRITE(MIPI_DSI_FUNC_PRG(port), temp); -- -- I915_WRITE(MIPI_DEVICE_READY(port), 0x1); -- } -- /* if disable packets are sent before sending shutdown packet then in -- * some next enable sequence send turn on packet error is observed */ -- drm_panel_disable(intel_dsi->panel); -- -- for_each_dsi_port(port, intel_dsi->ports) -- wait_for_dsi_fifo_empty(intel_dsi, port); --} -- - static void intel_dsi_clear_device_ready(struct intel_encoder *encoder) - { - struct drm_device *dev = encoder->base.dev; -@@ -696,8 +729,6 @@ static void intel_dsi_clear_device_ready(struct intel_encoder *encoder) - I915_WRITE(MIPI_DEVICE_READY(port), 0x00); - usleep_range(2000, 2500); - } -- -- intel_disable_dsi_pll(encoder); - } - - static void intel_dsi_post_disable(struct intel_encoder *encoder, -@@ -706,13 +737,50 @@ static void intel_dsi_post_disable(struct intel_encoder *encoder, - { - struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); -+ struct intel_connector *intel_connector = intel_dsi->attached_connector; -+ enum port port; -+ u32 temp; - - DRM_DEBUG_KMS("\n"); - -- intel_dsi_disable(encoder); -+ if (is_vid_mode(intel_dsi)) { -+ for_each_dsi_port(port, intel_dsi->ports) -+ wait_for_dsi_fifo_empty(intel_dsi, port); -+ -+ intel_dsi_port_disable(encoder); -+ usleep_range(2000, 5000); -+ } -+ -+ intel_panel_disable_backlight(intel_connector); -+ -+ for_each_dsi_port(port, intel_dsi->ports) { -+ /* Panel commands can be sent when clock is in LP11 */ -+ I915_WRITE(MIPI_DEVICE_READY(port), 0x0); - -+ intel_dsi_reset_clocks(encoder, port); -+ I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP); -+ -+ temp = I915_READ(MIPI_DSI_FUNC_PRG(port)); -+ temp &= ~VID_MODE_FORMAT_MASK; -+ I915_WRITE(MIPI_DSI_FUNC_PRG(port), temp); -+ -+ I915_WRITE(MIPI_DEVICE_READY(port), 0x1); -+ } -+ -+ /* -+ * if disable packets are sent before sending shutdown packet then in -+ * some next enable sequence send turn on packet error is observed -+ * XXX spec specifies SHUTDOWN before MIPI_SEQ_DISPLAY_OFF for -+ * v3 VBTs, but not for v2 VBTs? -+ */ -+ intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_TEAR_OFF); -+ intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_DISPLAY_OFF); -+ -+ /* Transition to LP-00 */ - intel_dsi_clear_device_ready(encoder); - -+ intel_disable_dsi_pll(encoder); -+ - if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { - u32 val; - -@@ -721,11 +789,12 @@ static void intel_dsi_post_disable(struct intel_encoder *encoder, - I915_WRITE(DSPCLK_GATE_D, val); - } - -- drm_panel_unprepare(intel_dsi->panel); -- -- msleep(intel_dsi->panel_off_delay); -+ /* Assert reset */ -+ intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_ASSERT_RESET); - -- /* Panel Disable over CRC PMIC */ -+ /* Power off, try both CRC pmic gpio and VBT */ -+ intel_dsi_msleep(intel_dsi, intel_dsi->panel_off_delay); -+ intel_dsi_exec_vbt_sequence(intel_dsi, MIPI_SEQ_POWER_OFF); - if (intel_dsi->gpio_panel) - gpiod_set_value_cansleep(intel_dsi->gpio_panel, 0); - -@@ -733,7 +802,7 @@ static void intel_dsi_post_disable(struct intel_encoder *encoder, - * FIXME As we do with eDP, just make a note of the time here - * and perform the wait before the next panel power on. - */ -- msleep(intel_dsi->panel_pwr_cycle_delay); -+ intel_dsi_msleep(intel_dsi, intel_dsi->panel_pwr_cycle_delay); - } - - static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, -@@ -1376,6 +1445,7 @@ static void intel_dsi_connector_destroy(struct drm_connector *connector) - - DRM_DEBUG_KMS("\n"); - intel_panel_fini(&intel_connector->panel); -+ intel_panel_destroy_backlight(connector); - drm_connector_cleanup(connector); - kfree(connector); - } -diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h -index 5967ea6d6045..548649158abd 100644 ---- a/drivers/gpu/drm/i915/intel_dsi.h -+++ b/drivers/gpu/drm/i915/intel_dsi.h -@@ -130,6 +130,11 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder) - return container_of(encoder, struct intel_dsi, base.base); - } - -+void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi, enum port port); -+ -+void intel_dsi_exec_vbt_sequence(struct intel_dsi *intel_dsi, -+ enum mipi_seq seq_id); -+ - bool intel_dsi_pll_is_enabled(struct drm_i915_private *dev_priv); - int intel_compute_dsi_pll(struct intel_encoder *encoder, - struct intel_crtc_state *config); -diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c -index 34601574fc6e..a4e3c642b39a 100644 ---- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c -+++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c -@@ -189,6 +189,8 @@ static const u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi, - break; - } - -+ wait_for_dsi_fifo_empty(intel_dsi, port); -+ - out: - data += len; - -@@ -353,11 +355,11 @@ static const fn_mipi_elem_exec exec_elem[] = { - */ - - static const char * const seq_name[] = { -- [MIPI_SEQ_ASSERT_RESET] = "MIPI_SEQ_ASSERT_RESET", -+ [MIPI_SEQ_DEASSERT_RESET] = "MIPI_SEQ_DEASSERT_RESET", - [MIPI_SEQ_INIT_OTP] = "MIPI_SEQ_INIT_OTP", - [MIPI_SEQ_DISPLAY_ON] = "MIPI_SEQ_DISPLAY_ON", - [MIPI_SEQ_DISPLAY_OFF] = "MIPI_SEQ_DISPLAY_OFF", -- [MIPI_SEQ_DEASSERT_RESET] = "MIPI_SEQ_DEASSERT_RESET", -+ [MIPI_SEQ_ASSERT_RESET] = "MIPI_SEQ_ASSERT_RESET", - [MIPI_SEQ_BACKLIGHT_ON] = "MIPI_SEQ_BACKLIGHT_ON", - [MIPI_SEQ_BACKLIGHT_OFF] = "MIPI_SEQ_BACKLIGHT_OFF", - [MIPI_SEQ_TEAR_ON] = "MIPI_SEQ_TEAR_ON", -@@ -374,10 +376,9 @@ static const char *sequence_name(enum mipi_seq seq_id) - return "(unknown)"; - } - --static void generic_exec_sequence(struct drm_panel *panel, enum mipi_seq seq_id) -+void intel_dsi_exec_vbt_sequence(struct intel_dsi *intel_dsi, -+ enum mipi_seq seq_id) - { -- struct vbt_panel *vbt_panel = to_vbt_panel(panel); -- struct intel_dsi *intel_dsi = vbt_panel->intel_dsi; - struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev); - const u8 *data; - fn_mipi_elem_exec mipi_elem_exec; -@@ -436,35 +437,6 @@ static void generic_exec_sequence(struct drm_panel *panel, enum mipi_seq seq_id) - } - } - --static int vbt_panel_prepare(struct drm_panel *panel) --{ -- generic_exec_sequence(panel, MIPI_SEQ_ASSERT_RESET); -- generic_exec_sequence(panel, MIPI_SEQ_INIT_OTP); -- -- return 0; --} -- --static int vbt_panel_unprepare(struct drm_panel *panel) --{ -- generic_exec_sequence(panel, MIPI_SEQ_DEASSERT_RESET); -- -- return 0; --} -- --static int vbt_panel_enable(struct drm_panel *panel) --{ -- generic_exec_sequence(panel, MIPI_SEQ_DISPLAY_ON); -- -- return 0; --} -- --static int vbt_panel_disable(struct drm_panel *panel) --{ -- generic_exec_sequence(panel, MIPI_SEQ_DISPLAY_OFF); -- -- return 0; --} -- - static int vbt_panel_get_modes(struct drm_panel *panel) - { - struct vbt_panel *vbt_panel = to_vbt_panel(panel); -@@ -488,10 +460,6 @@ static int vbt_panel_get_modes(struct drm_panel *panel) - } - - static const struct drm_panel_funcs vbt_panel_funcs = { -- .disable = vbt_panel_disable, -- .unprepare = vbt_panel_unprepare, -- .prepare = vbt_panel_prepare, -- .enable = vbt_panel_enable, - .get_modes = vbt_panel_get_modes, - }; - -diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c -index be4b4d546fd9..5aac10c3239f 100644 ---- a/drivers/gpu/drm/i915/intel_panel.c -+++ b/drivers/gpu/drm/i915/intel_panel.c -@@ -32,6 +32,7 @@ - - #include <linux/kernel.h> - #include <linux/moduleparam.h> -+#include <linux/mfd/intel_soc_pmic.h> - #include <linux/pwm.h> - #include "intel_drv.h" - -@@ -544,6 +545,11 @@ static u32 pwm_get_backlight(struct intel_connector *connector) - return DIV_ROUND_UP(duty_ns * 100, CRC_PMIC_PWM_PERIOD_NS); - } - -+static u32 vlv_pmic_get_backlight(struct intel_connector *connector) -+{ -+ return intel_soc_pmic_readb(0x4E); -+} -+ - static u32 intel_panel_get_backlight(struct intel_connector *connector) - { - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); -@@ -635,6 +641,11 @@ static void pwm_set_backlight(struct intel_connector *connector, u32 level) - pwm_config(panel->backlight.pwm, duty_ns, CRC_PMIC_PWM_PERIOD_NS); - } - -+static void vlv_pmic_set_backlight(struct intel_connector *connector, u32 level) -+{ -+ intel_soc_pmic_writeb(0x4E, level); -+} -+ - static void - intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level) - { -@@ -808,6 +819,14 @@ static void pwm_disable_backlight(struct intel_connector *connector) - pwm_disable(panel->backlight.pwm); - } - -+static void vlv_pmic_disable_backlight(struct intel_connector *connector) -+{ -+ intel_panel_actually_set_backlight(connector, 0); -+ -+ intel_soc_pmic_writeb(0x51, 0x00); -+ intel_soc_pmic_writeb(0x4B, 0x7F); -+} -+ - void intel_panel_disable_backlight(struct intel_connector *connector) - { - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); -@@ -1089,6 +1108,17 @@ static void pwm_enable_backlight(struct intel_connector *connector) - intel_panel_actually_set_backlight(connector, panel->backlight.level); - } - -+static void vlv_pmic_enable_backlight(struct intel_connector *connector) -+{ -+ struct intel_panel *panel = &connector->panel; -+ -+ intel_soc_pmic_writeb(0x4B, 0xFF); -+ intel_soc_pmic_writeb(0x4E, 0xFF); -+ intel_soc_pmic_writeb(0x51, 0x01); -+ -+ intel_panel_actually_set_backlight(connector, panel->backlight.level); -+} -+ - void intel_panel_enable_backlight(struct intel_connector *connector) - { - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); -@@ -1687,6 +1717,20 @@ static int pwm_setup_backlight(struct intel_connector *connector, - return 0; - } - -+static int vlv_pmic_setup_backlight(struct intel_connector *connector, -+ enum pipe unused) -+{ -+ struct intel_panel *panel = &connector->panel; -+ -+ panel->backlight.present = 1; -+ panel->backlight.min = 0x00; -+ panel->backlight.max = 0xFF; -+ panel->backlight.level = 0x5A; -+ panel->backlight.enabled = 1; -+ -+ return 0; -+} -+ - int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe) - { - struct drm_i915_private *dev_priv = to_i915(connector->dev); -@@ -1694,6 +1738,8 @@ int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe) - struct intel_panel *panel = &intel_connector->panel; - int ret; - -+ intel_backlight_device_register(intel_connector); -+ - if (!dev_priv->vbt.backlight.present) { - if (dev_priv->quirks & QUIRK_BACKLIGHT_PRESENT) { - DRM_DEBUG_KMS("no backlight present per VBT, but present per quirk\n"); -@@ -1783,18 +1829,17 @@ intel_panel_init_backlight_funcs(struct intel_panel *panel) - panel->backlight.hz_to_pwm = pch_hz_to_pwm; - } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { - if (connector->base.connector_type == DRM_MODE_CONNECTOR_DSI) { -- panel->backlight.setup = pwm_setup_backlight; -- panel->backlight.enable = pwm_enable_backlight; -- panel->backlight.disable = pwm_disable_backlight; -- panel->backlight.set = pwm_set_backlight; -- panel->backlight.get = pwm_get_backlight; -+ panel->backlight.setup = vlv_pmic_setup_backlight; -+ panel->backlight.enable = vlv_pmic_enable_backlight; -+ panel->backlight.disable = vlv_pmic_disable_backlight; -+ panel->backlight.set = vlv_pmic_set_backlight; -+ panel->backlight.get = vlv_pmic_get_backlight; - } else { - panel->backlight.setup = vlv_setup_backlight; - panel->backlight.enable = vlv_enable_backlight; - panel->backlight.disable = vlv_disable_backlight; - panel->backlight.set = vlv_set_backlight; - panel->backlight.get = vlv_get_backlight; -- panel->backlight.hz_to_pwm = vlv_hz_to_pwm; - } - } else if (IS_GEN4(dev_priv)) { - panel->backlight.setup = i965_setup_backlight; -diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c -index dbed12c484c9..a2f9a4671193 100644 ---- a/drivers/gpu/drm/i915/intel_sprite.c -+++ b/drivers/gpu/drm/i915/intel_sprite.c -@@ -81,10 +81,13 @@ int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode, - */ - void intel_pipe_update_start(struct intel_crtc *crtc) - { -+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; - long timeout = msecs_to_jiffies_timeout(1); - int scanline, min, max, vblank_start; - wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); -+ bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && -+ intel_crtc_has_type(crtc->config, INTEL_OUTPUT_DSI); - DEFINE_WAIT(wait); - - vblank_start = adjusted_mode->crtc_vblank_start; -@@ -136,6 +139,25 @@ void intel_pipe_update_start(struct intel_crtc *crtc) - - drm_crtc_vblank_put(&crtc->base); - -+ /* -+ * On VLV/CHV DSI the scanline counter would appear to -+ * increment approx. 1/3 of a scanline before start of vblank. -+ * The registers still get latched at start of vblank however. -+ * This means we must not write any registers on the first -+ * line of vblank (since not the whole line is actually in -+ * vblank). And unfortunately we can't use the interrupt to -+ * wait here since it may have already fired before we check -+ * the scanline. We could use the frame start interrupt instead -+ * since it will fire after the critical scanline, but that would -+ * require more changes in the interrupt code. So for now we'll -+ * just do the nasty thing and poll for the bad scanline to -+ * pass us by. -+ * -+ * FIXME figure out if BXT+ DSI suffers from this as well -+ */ -+ while (need_vlv_dsi_wa && scanline == vblank_start) -+ scanline = intel_get_crtc_scanline(crtc); -+ - crtc->debug.scanline_start = scanline; - crtc->debug.start_vbl_time = ktime_get(); - crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc); -diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c -index 12d6ebb4ae5d..8583e77deae0 100644 ---- a/drivers/mfd/intel_soc_pmic_core.c -+++ b/drivers/mfd/intel_soc_pmic_core.c -@@ -44,6 +44,8 @@ static struct pwm_lookup crc_pwm_lookup[] = { - PWM_LOOKUP("crystal_cove_pwm", 0, "0000:00:02.0", "pwm_backlight", 0, PWM_POLARITY_NORMAL), - }; - -+static struct intel_soc_pmic *pmic_hack = NULL; -+ - static int intel_soc_pmic_find_gpio_irq(struct device *dev) - { - struct gpio_desc *desc; -@@ -77,6 +79,7 @@ static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c, - config = (struct intel_soc_pmic_config *)id->driver_data; - - pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); -+ pmic_hack = pmic; - if (!pmic) - return -ENOMEM; - -@@ -168,6 +171,37 @@ static int intel_soc_pmic_resume(struct device *dev) - } - #endif - -+int intel_soc_pmic_readb(int reg) -+{ -+ int ret; -+ unsigned int val; -+ -+ if (!pmic_hack) { -+ ret = -EIO; -+ } else { -+ ret = regmap_read(pmic_hack->regmap, reg, &val); -+ if (!ret) { -+ ret = val; -+ } -+ } -+ -+ return ret; -+} -+EXPORT_SYMBOL(intel_soc_pmic_readb); -+ -+int intel_soc_pmic_writeb(int reg, u8 val) -+{ -+ int ret; -+ -+ if (!pmic_hack) { -+ ret = -EIO; -+ } else { -+ ret = regmap_write(pmic_hack->regmap, reg, val); -+ } -+ return ret; -+} -+EXPORT_SYMBOL(intel_soc_pmic_writeb); -+ - static SIMPLE_DEV_PM_OPS(intel_soc_pmic_pm_ops, intel_soc_pmic_suspend, - intel_soc_pmic_resume); - -diff --git a/include/linux/mfd/intel_soc_pmic.h b/include/linux/mfd/intel_soc_pmic.h -index cf619dbeace2..52ad034f606a 100644 ---- a/include/linux/mfd/intel_soc_pmic.h -+++ b/include/linux/mfd/intel_soc_pmic.h -@@ -29,4 +29,7 @@ struct intel_soc_pmic { - struct device *dev; - }; - -+int intel_soc_pmic_readb(int reg); -+int intel_soc_pmic_writeb(int reg, u8 val); -+ - #endif /* __INTEL_SOC_PMIC_H__ */ diff --git a/modules/hardware/t100ha/sdio.patch b/modules/hardware/t100ha/sdio.patch deleted file mode 100644 index 3bfef26d..00000000 --- a/modules/hardware/t100ha/sdio.patch +++ /dev/null @@ -1,52 +0,0 @@ -Patch from https://github.com/hadess/rtl8723bs/issues/80#issuecomment-252259702 - -diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c -index 159f7f1..2076427 100644 ---- a/drivers/acpi/acpi_platform.c -+++ b/drivers/acpi/acpi_platform.c -@@ -50,8 +50,10 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev) - int count; - - /* If the ACPI node already has a physical device attached, skip it. */ -- if (adev->physical_node_count) -- return NULL; -+ if (adev->physical_node_count && !( -+ !strcmp(acpi_device_hid(adev), "80860F14") && -+ !strcmp(adev->pnp.unique_id, "2") -+ )) return NULL; - - if (!acpi_match_device_ids(adev, forbidden_id_list)) - return ERR_PTR(-EINVAL); -diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c -index 458ffb7..2807f78 100644 ---- a/drivers/mmc/host/sdhci-acpi.c -+++ b/drivers/mmc/host/sdhci-acpi.c -@@ -47,6 +47,7 @@ - #endif - - #include "sdhci.h" -+#include <linux/pci.h> - - enum { - SDHCI_ACPI_SD_CD = BIT(0), -@@ -381,6 +382,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev) - struct acpi_device *device, *child; - struct sdhci_acpi_host *c; - struct sdhci_host *host; -+ struct pci_dev *pcidev = NULL; - struct resource *iomem; - resource_size_t len; - const char *hid; -@@ -404,6 +406,12 @@ static int sdhci_acpi_probe(struct platform_device *pdev) - hid = acpi_device_hid(device); - uid = device->pnp.unique_id; - -+ /* Workaround for CherryTrail x5-z8xxx: Make sure the SDIO controller -+ * doesn't get added via PCI. */ -+ if (!strcmp(hid, "80860F14") && !strcmp(uid, "1") && -+ (pcidev = pci_get_device(0x8086, 0x2280, NULL)) != NULL) -+ pci_stop_and_remove_bus_device(pcidev); -+ - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iomem) - return -ENOMEM; diff --git a/modules/hardware/t100ha/sound.patch b/modules/hardware/t100ha/sound.patch deleted file mode 100644 index 15a2a883..00000000 --- a/modules/hardware/t100ha/sound.patch +++ /dev/null @@ -1,5620 +0,0 @@ -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index bada636d1065..233898ec1fbd 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -2756,6 +2756,7 @@ config X86_DMA_REMAP - config PMC_ATOM - def_bool y - depends on PCI -+ select COMMON_CLK - - source "net/Kconfig" - -diff --git a/arch/x86/include/asm/pmc_atom.h b/arch/x86/include/asm/pmc_atom.h -index aa8744c77c6d..59f95168fa8d 100644 ---- a/arch/x86/include/asm/pmc_atom.h -+++ b/arch/x86/include/asm/pmc_atom.h -@@ -152,6 +152,12 @@ - #define SLEEP_TYPE_S5 0x1C00 - #define SLEEP_ENABLE 0x2000 - -+struct pmc_clk { -+ const char *name; -+ unsigned long freq; -+ const char *parent_name; -+}; -+ - extern int pmc_atom_read(int offset, u32 *value); - extern int pmc_atom_write(int offset, u32 value); - -diff --git a/arch/x86/platform/atom/pmc_atom.c b/arch/x86/platform/atom/pmc_atom.c -index 964ff4fc61f9..e2de3e234959 100644 ---- a/arch/x86/platform/atom/pmc_atom.c -+++ b/arch/x86/platform/atom/pmc_atom.c -@@ -21,6 +21,7 @@ - #include <linux/debugfs.h> - #include <linux/seq_file.h> - #include <linux/io.h> -+#include <linux/platform_device.h> - - #include <asm/pmc_atom.h> - -@@ -37,6 +38,11 @@ struct pmc_reg_map { - const struct pmc_bit_map *pss; - }; - -+struct pmc_data { -+ const struct pmc_reg_map *map; -+ const struct pmc_clk *clks; -+}; -+ - struct pmc_dev { - u32 base_addr; - void __iomem *regmap; -@@ -50,6 +56,29 @@ struct pmc_dev { - static struct pmc_dev pmc_device; - static u32 acpi_base_addr; - -+static const struct pmc_clk byt_clks[] = { -+ { -+ .name = "xtal", -+ .freq = 25000000, -+ .parent_name = NULL, -+ }, -+ { -+ .name = "pll", -+ .freq = 19200000, -+ .parent_name = "xtal", -+ }, -+ {}, -+}; -+ -+static const struct pmc_clk cht_clks[] = { -+ { -+ .name = "xtal", -+ .freq = 19200000, -+ .parent_name = NULL, -+ }, -+ {}, -+}; -+ - static const struct pmc_bit_map d3_sts_0_map[] = { - {"LPSS1_F0_DMA", BIT_LPSS1_F0_DMA}, - {"LPSS1_F1_PWM1", BIT_LPSS1_F1_PWM1}, -@@ -169,6 +198,16 @@ static const struct pmc_reg_map cht_reg_map = { - .pss = cht_pss_map, - }; - -+static const struct pmc_data byt_data = { -+ .map = &byt_reg_map, -+ .clks = byt_clks, -+}; -+ -+static const struct pmc_data cht_data = { -+ .map = &cht_reg_map, -+ .clks = cht_clks, -+}; -+ - static inline u32 pmc_reg_read(struct pmc_dev *pmc, int reg_offset) - { - return readl(pmc->regmap + reg_offset); -@@ -384,8 +423,11 @@ static int pmc_dbgfs_register(struct pmc_dev *pmc) - - static int pmc_setup_dev(struct pci_dev *pdev, const struct pci_device_id *ent) - { -+ struct platform_device *clkdev; - struct pmc_dev *pmc = &pmc_device; -- const struct pmc_reg_map *map = (struct pmc_reg_map *)ent->driver_data; -+ const struct pmc_data *data = (struct pmc_data *)ent->driver_data; -+ const struct pmc_reg_map *map = data->map; -+ const struct pmc_clk *clks = data->clks; - int ret; - - /* Obtain ACPI base address */ -@@ -414,6 +456,13 @@ static int pmc_setup_dev(struct pci_dev *pdev, const struct pci_device_id *ent) - if (ret) - dev_warn(&pdev->dev, "debugfs register failed\n"); - -+ /* Register platform clocks - PMC_PLT_CLK [5:0] */ -+ clkdev = platform_device_register_data(NULL, "clk-byt-plt", -1, -+ &clks, sizeof(clks)); -+ if (IS_ERR(clkdev)) -+ dev_warn(&pdev->dev, "platform clocks register failed: %ld\n", -+ PTR_ERR(clkdev)); -+ - pmc->init = true; - return ret; - } -@@ -424,8 +473,8 @@ static int pmc_setup_dev(struct pci_dev *pdev, const struct pci_device_id *ent) - * used by pci_match_id() call below. - */ - static const struct pci_device_id pmc_pci_ids[] = { -- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_VLV_PMC), (kernel_ulong_t)&byt_reg_map }, -- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_CHT_PMC), (kernel_ulong_t)&cht_reg_map }, -+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_VLV_PMC), (kernel_ulong_t)&byt_data }, -+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_CHT_PMC), (kernel_ulong_t)&cht_data }, - { 0, }, - }; - -diff --git a/drivers/clk/x86/Makefile b/drivers/clk/x86/Makefile -index 04781389d0fb..cbdc8cc00060 100644 ---- a/drivers/clk/x86/Makefile -+++ b/drivers/clk/x86/Makefile -@@ -1,2 +1,3 @@ - clk-x86-lpss-objs := clk-lpt.o - obj-$(CONFIG_X86_INTEL_LPSS) += clk-x86-lpss.o -+obj-$(CONFIG_PMC_ATOM) += clk-byt-plt.o -diff --git a/drivers/clk/x86/clk-byt-plt.c b/drivers/clk/x86/clk-byt-plt.c -new file mode 100644 -index 000000000000..330cd35d1d27 ---- /dev/null -+++ b/drivers/clk/x86/clk-byt-plt.c -@@ -0,0 +1,413 @@ -+/* -+ * Intel Atom platform clocks driver for Baytrail and CherryTrail SoC. -+ * -+ * Copyright (C) 2016, Intel Corporation -+ * Author: Irina Tirdea <irina.tirdea@intel.com> -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms and conditions of the GNU General Public License, -+ * version 2, as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope 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 <linux/clk-provider.h> -+#include <linux/err.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/slab.h> -+#include <linux/clkdev.h> -+ -+#include <asm/pmc_atom.h> -+ -+#define PLT_CLK_NAME_BASE "pmc_plt_clk_" -+#define PLT_CLK_DRIVER_NAME "clk-byt-plt" -+ -+#define PMC_CLK_CTL_0 0x60 -+#define PMC_CLK_CTL_SIZE 4 -+#define PMC_CLK_NUM 6 -+#define PMC_MASK_CLK_CTL GENMASK(1, 0) -+#define PMC_MASK_CLK_FREQ BIT(2) -+#define PMC_CLK_CTL_GATED_ON_D3 0x0 -+#define PMC_CLK_CTL_FORCE_ON 0x1 -+#define PMC_CLK_CTL_FORCE_OFF 0x2 -+#define PMC_CLK_CTL_RESERVED 0x3 -+#define PMC_CLK_FREQ_XTAL 0x0 /* 25 MHz */ -+#define PMC_CLK_FREQ_PLL 0x4 /* 19.2 MHz */ -+ -+struct clk_plt_fixed { -+ struct clk *clk; -+ struct clk_lookup *lookup; -+}; -+ -+struct clk_plt { -+ struct clk_hw hw; -+ u8 id; -+ u32 offset; -+ struct clk_lookup *lookup; -+ spinlock_t lock; -+}; -+ -+#define to_clk_plt(_hw) container_of(_hw, struct clk_plt, hw) -+ -+struct clk_plt_data { -+ struct clk_plt_fixed **parents; -+ u8 nparents; -+ struct clk *clks[PMC_CLK_NUM]; -+}; -+ -+static inline int plt_reg_to_parent(int reg) -+{ -+ switch (reg & PMC_MASK_CLK_FREQ) { -+ case PMC_CLK_FREQ_XTAL: -+ return 0; /* index 0 in parents[] */ -+ case PMC_CLK_FREQ_PLL: -+ return 1; /* index 1 in parents[] */ -+ } -+ -+ return 0; -+} -+ -+static inline int plt_parent_to_reg(int index) -+{ -+ switch (index) { -+ case 0: /* index 0 in parents[] */ -+ return PMC_CLK_FREQ_XTAL; -+ case 1: /* index 0 in parents[] */ -+ return PMC_CLK_FREQ_PLL; -+ } -+ -+ return PMC_CLK_FREQ_XTAL; -+} -+ -+static inline int plt_reg_to_enabled(int reg) -+{ -+ switch (reg & PMC_MASK_CLK_CTL) { -+ case PMC_CLK_CTL_GATED_ON_D3: -+ case PMC_CLK_CTL_FORCE_ON: -+ return 1; /* enabled */ -+ case PMC_CLK_CTL_FORCE_OFF: -+ case PMC_CLK_CTL_RESERVED: -+ default: -+ return 0; /* disabled */ -+ } -+} -+ -+static int plt_pmc_atom_update(struct clk_plt *clk, u32 mask, u32 val) -+{ -+ int ret; -+ u32 orig, tmp; -+ unsigned long flags = 0; -+ -+ spin_lock_irqsave(&clk->lock, flags); -+ -+ ret = pmc_atom_read(clk->offset, &orig); -+ if (ret) -+ goto out; -+ -+ tmp = orig & ~mask; -+ tmp |= val & mask; -+ -+ if (tmp == orig) -+ goto out; -+ -+ ret = pmc_atom_write(clk->offset, tmp); -+ if (ret) -+ goto out; -+ -+out: -+ spin_unlock_irqrestore(&clk->lock, flags); -+ -+ return ret; -+} -+ -+static int plt_clk_set_parent(struct clk_hw *hw, u8 index) -+{ -+ struct clk_plt *clk = to_clk_plt(hw); -+ -+ return plt_pmc_atom_update(clk, PMC_MASK_CLK_FREQ, -+ plt_parent_to_reg(index)); -+} -+ -+static u8 plt_clk_get_parent(struct clk_hw *hw) -+{ -+ struct clk_plt *clk = to_clk_plt(hw); -+ u32 value; -+ int ret; -+ -+ ret = pmc_atom_read(clk->offset, &value); -+ if (ret) -+ return ret; -+ -+ return plt_reg_to_parent(value); -+} -+ -+static int plt_clk_enable(struct clk_hw *hw) -+{ -+ struct clk_plt *clk = to_clk_plt(hw); -+ -+ return plt_pmc_atom_update(clk, PMC_MASK_CLK_CTL, PMC_CLK_CTL_FORCE_ON); -+} -+ -+static void plt_clk_disable(struct clk_hw *hw) -+{ -+ struct clk_plt *clk = to_clk_plt(hw); -+ -+ plt_pmc_atom_update(clk, PMC_MASK_CLK_CTL, PMC_CLK_CTL_FORCE_OFF); -+} -+ -+static int plt_clk_is_enabled(struct clk_hw *hw) -+{ -+ struct clk_plt *clk = to_clk_plt(hw); -+ u32 value; -+ int ret; -+ -+ ret = pmc_atom_read(clk->offset, &value); -+ if (ret) -+ return ret; -+ -+ return plt_reg_to_enabled(value); -+} -+ -+static const struct clk_ops plt_clk_ops = { -+ .enable = plt_clk_enable, -+ .disable = plt_clk_disable, -+ .is_enabled = plt_clk_is_enabled, -+ .get_parent = plt_clk_get_parent, -+ .set_parent = plt_clk_set_parent, -+ .determine_rate = __clk_mux_determine_rate, -+}; -+ -+static struct clk *plt_clk_register(struct platform_device *pdev, int id, -+ const char **parent_names, int num_parents) -+{ -+ struct clk_plt *pclk; -+ struct clk *clk; -+ struct clk_init_data init; -+ int ret = 0; -+ -+ pclk = devm_kzalloc(&pdev->dev, sizeof(*pclk), GFP_KERNEL); -+ if (!pclk) -+ return ERR_PTR(-ENOMEM); -+ -+ init.name = kasprintf(GFP_KERNEL, "%s%d", PLT_CLK_NAME_BASE, id); -+ init.ops = &plt_clk_ops; -+ init.flags = 0; -+ init.parent_names = parent_names; -+ init.num_parents = num_parents; -+ -+ pclk->hw.init = &init; -+ pclk->id = id; -+ pclk->offset = PMC_CLK_CTL_0 + id * PMC_CLK_CTL_SIZE; -+ spin_lock_init(&pclk->lock); -+ -+ clk = clk_register(&pdev->dev, &pclk->hw); -+ if (IS_ERR(clk)) { -+ ret = PTR_ERR(clk); -+ goto err_free_pclk; -+ } -+ -+ pclk->lookup = clkdev_create(clk, init.name, NULL); -+ if (!pclk->lookup) { -+ ret = -ENOMEM; -+ goto err_clk_unregister; -+ } -+ -+ kfree(init.name); -+ -+ return clk; -+ -+err_clk_unregister: -+ clk_unregister(clk); -+err_free_pclk: -+ kfree(init.name); -+ return ERR_PTR(ret); -+} -+ -+static void plt_clk_unregister(struct clk *clk) -+{ -+ struct clk_plt *pclk; -+ struct clk_hw *hw; -+ -+ hw = __clk_get_hw(clk); -+ if (!hw) -+ return; -+ -+ pclk = to_clk_plt(hw); -+ -+ clkdev_drop(pclk->lookup); -+ clk_unregister(clk); -+} -+ -+static struct clk_plt_fixed *plt_clk_register_fixed_rate(struct platform_device *pdev, -+ const char *name, -+ const char *parent_name, -+ unsigned long fixed_rate) -+{ -+ struct clk_plt_fixed *pclk; -+ int ret = 0; -+ -+ pclk = devm_kzalloc(&pdev->dev, sizeof(*pclk), GFP_KERNEL); -+ if (!pclk) -+ return ERR_PTR(-ENOMEM); -+ -+ pclk->clk = clk_register_fixed_rate(&pdev->dev, name, parent_name, -+ 0, fixed_rate); -+ if (IS_ERR(pclk->clk)) { -+ ret = PTR_ERR(pclk->clk); -+ return ERR_PTR(ret); -+ } -+ -+ pclk->lookup = clkdev_create(pclk->clk, name, NULL); -+ if (!pclk->lookup) { -+ ret = -ENOMEM; -+ goto err_clk_unregister; -+ } -+ -+ return pclk; -+ -+err_clk_unregister: -+ clk_unregister_fixed_rate(pclk->clk); -+ return ERR_PTR(ret); -+} -+ -+static void plt_clk_unregister_fixed_rate(struct clk_plt_fixed *pclk) -+{ -+ clkdev_drop(pclk->lookup); -+ clk_unregister_fixed_rate(pclk->clk); -+} -+ -+static const char **plt_clk_register_parents(struct platform_device *pdev, -+ struct clk_plt_data *data) -+{ -+ struct pmc_clk **pclks, *clks; -+ const char **parent_names; -+ int i, err; -+ -+ data->nparents = 0; -+ pclks = dev_get_platdata(&pdev->dev); -+ if (!pclks) -+ return NULL; -+ -+ clks = *pclks; -+ while (clks[data->nparents].name) -+ data->nparents++; -+ -+ data->parents = devm_kzalloc(&pdev->dev, -+ sizeof(*data->parents) * data->nparents, -+ GFP_KERNEL); -+ if (!data->parents) { -+ err = -ENOMEM; -+ goto err_out; -+ } -+ -+ parent_names = kcalloc(data->nparents, sizeof(*parent_names), -+ GFP_KERNEL); -+ if (!parent_names) { -+ err = -ENOMEM; -+ goto err_out; -+ } -+ -+ for (i = 0; i < data->nparents; i++) { -+ data->parents[i] = -+ plt_clk_register_fixed_rate(pdev, clks[i].name, -+ clks[i].parent_name, -+ clks[i].freq); -+ if (IS_ERR(data->parents[i])) { -+ err = PTR_ERR(data->parents[i]); -+ goto err_unreg; -+ } -+ parent_names[i] = kstrdup_const(clks[i].name, GFP_KERNEL); -+ } -+ -+ return parent_names; -+ -+err_unreg: -+ for (i--; i >= 0; i--) { -+ plt_clk_unregister_fixed_rate(data->parents[i]); -+ kfree_const(parent_names[i]); -+ } -+ kfree(parent_names); -+err_out: -+ data->nparents = 0; -+ return ERR_PTR(err); -+} -+ -+static void plt_clk_unregister_parents(struct clk_plt_data *data) -+{ -+ int i; -+ -+ for (i = 0; i < data->nparents; i++) -+ plt_clk_unregister_fixed_rate(data->parents[i]); -+} -+ -+static int plt_clk_probe(struct platform_device *pdev) -+{ -+ struct clk_plt_data *data; -+ int i, err; -+ const char **parent_names; -+ -+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ -+ parent_names = plt_clk_register_parents(pdev, data); -+ if (IS_ERR(parent_names)) -+ return PTR_ERR(parent_names); -+ -+ for (i = 0; i < PMC_CLK_NUM; i++) { -+ data->clks[i] = plt_clk_register(pdev, i, parent_names, -+ data->nparents); -+ if (IS_ERR(data->clks[i])) { -+ err = PTR_ERR(data->clks[i]); -+ goto err_unreg_clk_plt; -+ } -+ } -+ -+ for (i = 0; i < data->nparents; i++) -+ kfree_const(parent_names[i]); -+ kfree(parent_names); -+ -+ dev_set_drvdata(&pdev->dev, data); -+ return 0; -+ -+err_unreg_clk_plt: -+ for (i--; i >= 0; i--) -+ plt_clk_unregister(data->clks[i]); -+ plt_clk_unregister_parents(data); -+ for (i = 0; i < data->nparents; i++) -+ kfree_const(parent_names[i]); -+ kfree(parent_names); -+ return err; -+} -+ -+static int plt_clk_remove(struct platform_device *pdev) -+{ -+ struct clk_plt_data *data; -+ int i; -+ -+ data = dev_get_drvdata(&pdev->dev); -+ if (!data) -+ return 0; -+ -+ for (i = 0; i < PMC_CLK_NUM; i++) -+ plt_clk_unregister(data->clks[i]); -+ plt_clk_unregister_parents(data); -+ return 0; -+} -+ -+static struct platform_driver plt_clk_driver = { -+ .driver = { -+ .name = PLT_CLK_DRIVER_NAME, -+ }, -+ .probe = plt_clk_probe, -+ .remove = plt_clk_remove, -+}; -+module_platform_driver(plt_clk_driver); -+ -+MODULE_DESCRIPTION("Intel Atom platform clocks driver"); -+MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>"); -+MODULE_LICENSE("GPL v2"); -diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index c67667bb970f..655e2f4d1dd0 100644 ---- a/sound/soc/codecs/Kconfig -+++ b/sound/soc/codecs/Kconfig -@@ -61,6 +61,7 @@ config SND_SOC_ALL_CODECS - select SND_SOC_CS47L24 if MFD_CS47L24 - select SND_SOC_CS53L30 if I2C - select SND_SOC_CX20442 if TTY -+ select SND_SOC_CX2072X if I2C - select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI - select SND_SOC_DA7213 if I2C - select SND_SOC_DA7218 if I2C -@@ -478,6 +479,10 @@ config SND_SOC_CX20442 - tristate - depends on TTY - -+config SND_SOC_CX2072X -+ tristate "Conexant CX2072X CODEC" -+ depends on I2C -+ - config SND_SOC_JZ4740_CODEC - select REGMAP_MMIO - tristate -diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile -index 958cd4912fbc..1dded20a4d84 100644 ---- a/sound/soc/codecs/Makefile -+++ b/sound/soc/codecs/Makefile -@@ -54,6 +54,7 @@ snd-soc-cs4349-objs := cs4349.o - snd-soc-cs47l24-objs := cs47l24.o - snd-soc-cs53l30-objs := cs53l30.o - snd-soc-cx20442-objs := cx20442.o -+snd-soc-cx2072x-objs := cx2072x.o - snd-soc-da7210-objs := da7210.o - snd-soc-da7213-objs := da7213.o - snd-soc-da7218-objs := da7218.o -@@ -279,6 +280,7 @@ obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o - obj-$(CONFIG_SND_SOC_CS47L24) += snd-soc-cs47l24.o - obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o - obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o -+obj-$(CONFIG_SND_SOC_CX2072X) += snd-soc-cx2072x.o - obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o - obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o - obj-$(CONFIG_SND_SOC_DA7218) += snd-soc-da7218.o -diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c -new file mode 100644 -index 000000000000..aaec3722854c ---- /dev/null -+++ b/sound/soc/codecs/cx2072x.c -@@ -0,0 +1,2124 @@ -+/* -+ * ALSA SoC CX20721/cx20723 Solana codec driver -+ * Copyright: (C) 2016 Conexant Systems, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ ************************************************************************/ -+#define DEBUG -+/*#define INTEL_MCLK_CONTROL*/ -+ -+/*#define ENABLE_MIC_POP_WA*/ -+ -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/init.h> -+#include <linux/delay.h> -+#include <linux/pm.h> -+#include <linux/platform_device.h> -+#include <sound/core.h> -+#include <sound/pcm.h> -+#include <sound/pcm_params.h> -+#include <sound/soc.h> -+#include <sound/soc-dapm.h> -+#include <sound/initval.h> -+#include <sound/tlv.h> -+#include <linux/of_gpio.h> -+#include <linux/gpio.h> -+#include <sound/jack.h> -+#include <linux/slab.h> -+#include <linux/i2c.h> -+#include <linux/firmware.h> -+#include <linux/regmap.h> -+#include <linux/proc_fs.h> -+#include <linux/interrupt.h> -+#include <linux/irq.h> -+#include <linux/acpi.h> -+#ifdef INTEL_MCLK_CONTROL -+#include <linux/vlv2_plat_clock.h> -+#endif -+#include "cx2072x.h" -+ -+#define SUPPORT_RKI2S_FORMAT -+#define CX2072X_REV_A2 0x00100002 -+#define CXDBG_REG_DUMP -+ -+/*FIXME: need to move the EQ/DRC setting to device tree*/ -+static unsigned char cx2072x_eq_coeff_array[MAX_EQ_BAND][MAC_EQ_COEFF] = { -+ {0x77, 0x26, 0x13, 0xb3, 0x76, 0x26, 0x0a, 0x3d, 0xd4, 0xe2, 0x04}, -+ {0x97, 0x3e, 0xb3, 0x86, 0xc2, 0x3b, 0x4d, 0x79, 0xa7, 0xc5, 0x03}, -+ {0x0f, 0x39, 0x76, 0xa3, 0x1b, 0x2b, 0x89, 0x5c, 0xd7, 0xdb, 0x03}, -+ {0x21, 0x46, 0xfe, 0xa6, 0xec, 0x24, 0x01, 0x59, 0xf4, 0xd4, 0x03}, -+ {0xe9, 0x78, 0x9c, 0xb0, 0x8a, 0x56, 0x64, 0x4f, 0x8d, 0xb0, 0x02}, -+ {0x60, 0x6e, 0x57, 0xee, 0xec, 0x18, 0xa8, 0x11, 0xb5, 0xf8, 0x02}, -+ {0x5a, 0x14, 0x68, 0xe9, 0x1d, 0x06, 0xb9, 0x5f, 0x68, 0xdc, 0x03}, -+}; -+ -+static unsigned char cx2072x_drc_array[MAX_DRC_REGS] = { -+ 0x65, 0x55, 0x3C, 0x01, 0x05, 0x39, 0x76, 0x1A, 0x00 -+}; -+ -+/*#define CXDBG_REG_DUMP*/ -+#ifdef CXDBG_REG_DUMP -+ -+#define CX2072X_FORMATS (SNDRV_PCM_FMTBIT_S24_LE \ -+ | SNDRV_PCM_FMTBIT_S16_LE) -+#define BITS_PER_SLOT 8 -+ -+#define _REG(_name_, _size_, _access_, _volatile_) { \ -+ #_name_, _name_, _size_ | _access_ | _volatile_} -+ -+struct CX2072X_REG_DEF { -+ const char *name; -+ unsigned int addr; -+ unsigned int attr; -+}; -+ -+#define WO 0x0100 -+#define RO 0x0200 -+#define RW 0x0300 -+#define VO 0x8000 -+#define NV 0x0000 -+#define REGISTER_SIZE_MASK 0x000F -+#define REGISTER_ASSCESS_MASK 0x0F00 -+#define REGISTER_VOLATILE_MASK 0x8000 -+#define UNAVAILABLE 0 -+ -+ -+static const struct CX2072X_REG_DEF cx2072x_regs[] = { -+ _REG(CX2072X_VENDOR_ID, 4, RO, VO), -+ _REG(CX2072X_REVISION_ID, 4, RO, VO), -+ _REG(CX2072X_CURRENT_BCLK_FREQUENCY, 4, RO, VO), -+ _REG(CX2072X_AFG_POWER_STATE, 1, RW, NV), -+ _REG(CX2072X_UM_RESPONSE, 1, RW, NV), -+ _REG(CX2072X_GPIO_DATA, 1, RW, NV), -+ _REG(CX2072X_GPIO_ENABLE, 1, RW, NV), -+ _REG(CX2072X_GPIO_DIRECTION, 1, RW, NV), -+ _REG(CX2072X_GPIO_WAKE, 1, RW, NV), -+ _REG(CX2072X_GPIO_UM_ENABLE, 1, RW, NV), -+ _REG(CX2072X_GPIO_STICKY_MASK, 1, RW, NV), -+ _REG(CX2072X_AFG_FUNCTION_RESET, 1, WO, NV), -+ _REG(CX2072X_DAC1_CONVERTER_FORMAT, 2, RW, NV), -+ _REG(CX2072X_DAC1_AMP_GAIN_RIGHT, 1, RW, NV), -+ _REG(CX2072X_DAC1_AMP_GAIN_LEFT, 1, RW, NV), -+ _REG(CX2072X_DAC1_POWER_STATE, 1, RW, NV), -+ _REG(CX2072X_DAC1_CONVERTER_STREAM_CHANNEL, 1, RW, NV), -+ _REG(CX2072X_DAC1_EAPD_ENABLE, 1, RW, NV), -+ _REG(CX2072X_DAC2_CONVERTER_FORMAT, 2, RW, NV), -+ _REG(CX2072X_DAC2_AMP_GAIN_RIGHT, 1, RW, NV), -+ _REG(CX2072X_DAC2_AMP_GAIN_LEFT, 1, RW, NV), -+ _REG(CX2072X_DAC2_POWER_STATE, 1, RW, NV), -+ _REG(CX2072X_DAC2_CONVERTER_STREAM_CHANNEL, 1, RW, NV), -+ _REG(CX2072X_ADC1_CONVERTER_FORMAT, 2, RW, NV), -+ _REG(CX2072X_ADC1_AMP_GAIN_RIGHT_0, 1, RW, NV), -+ _REG(CX2072X_ADC1_AMP_GAIN_LEFT_0, 1, RW, NV), -+ _REG(CX2072X_ADC1_AMP_GAIN_RIGHT_1, 1, RW, NV), -+ _REG(CX2072X_ADC1_AMP_GAIN_LEFT_1, 1, RW, NV), -+ _REG(CX2072X_ADC1_AMP_GAIN_RIGHT_2, 1, RW, NV), -+ _REG(CX2072X_ADC1_AMP_GAIN_LEFT_2, 1, RW, NV), -+ _REG(CX2072X_ADC1_AMP_GAIN_RIGHT_3, 1, RW, NV), -+ _REG(CX2072X_ADC1_AMP_GAIN_LEFT_3, 1, RW, NV), -+ _REG(CX2072X_ADC1_AMP_GAIN_RIGHT_4, 1, RW, NV), -+ _REG(CX2072X_ADC1_AMP_GAIN_LEFT_4, 1, RW, NV), -+ _REG(CX2072X_ADC1_AMP_GAIN_RIGHT_5, 1, RW, NV), -+ _REG(CX2072X_ADC1_AMP_GAIN_LEFT_5, 1, RW, NV), -+ _REG(CX2072X_ADC1_AMP_GAIN_RIGHT_6, 1, RW, NV), -+ _REG(CX2072X_ADC1_AMP_GAIN_LEFT_6, 1, RW, NV), -+ _REG(CX2072X_ADC1_CONNECTION_SELECT_CONTROL, 1, RW, NV), -+ _REG(CX2072X_ADC1_POWER_STATE, 1, RW, NV), -+ _REG(CX2072X_ADC1_CONVERTER_STREAM_CHANNEL, 1, RW, NV), -+ _REG(CX2072X_ADC2_CONVERTER_FORMAT, 2, WO, NV), -+ _REG(CX2072X_ADC2_AMP_GAIN_RIGHT_0, 1, RW, NV), -+ _REG(CX2072X_ADC2_AMP_GAIN_LEFT_0, 1, RW, NV), -+ _REG(CX2072X_ADC2_AMP_GAIN_RIGHT_1, 1, RW, NV), -+ _REG(CX2072X_ADC2_AMP_GAIN_LEFT_1, 1, RW, NV), -+ _REG(CX2072X_ADC2_AMP_GAIN_RIGHT_2, 1, RW, NV), -+ _REG(CX2072X_ADC2_AMP_GAIN_LEFT_2, 1, RW, NV), -+ _REG(CX2072X_ADC2_CONNECTION_SELECT_CONTROL, 1, RW, NV), -+ _REG(CX2072X_ADC2_POWER_STATE, 1, RW, NV), -+ _REG(CX2072X_ADC2_CONVERTER_STREAM_CHANNEL, 1, RW, NV), -+ _REG(CX2072X_PORTA_CONNECTION_SELECT_CTRL, 1, RW, NV), -+ _REG(CX2072X_PORTA_POWER_STATE, 1, RW, NV), -+ _REG(CX2072X_PORTA_PIN_CTRL, 1, RW, NV), -+ _REG(CX2072X_PORTA_UNSOLICITED_RESPONSE, 1, RW, NV), -+ _REG(CX2072X_PORTA_PIN_SENSE, 4, RO, VO), -+ _REG(CX2072X_PORTA_EAPD_BTL, 1, RW, NV), -+ _REG(CX2072X_PORTB_POWER_STATE, 1, RW, NV), -+ _REG(CX2072X_PORTB_PIN_CTRL, 1, RW, NV), -+ _REG(CX2072X_PORTB_UNSOLICITED_RESPONSE, 1, RW, NV), -+ _REG(CX2072X_PORTB_PIN_SENSE, 4, RO, VO), -+ _REG(CX2072X_PORTB_EAPD_BTL, 1, RW, NV), -+ _REG(CX2072X_PORTB_GAIN_RIGHT, 1, RW, NV), -+ _REG(CX2072X_PORTB_GAIN_LEFT, 1, RW, NV), -+ _REG(CX2072X_PORTC_POWER_STATE, 1, RW, NV), -+ _REG(CX2072X_PORTC_PIN_CTRL, 1, RW, NV), -+ _REG(CX2072X_PORTC_GAIN_RIGHT, 1, RW, NV), -+ _REG(CX2072X_PORTC_GAIN_LEFT, 1, RW, NV), -+ _REG(CX2072X_PORTD_POWER_STATE, 1, RW, NV), -+ _REG(CX2072X_PORTD_PIN_CTRL, 1, RW, NV), -+ _REG(CX2072X_PORTD_UNSOLICITED_RESPONSE, 1, RW, NV), -+ _REG(CX2072X_PORTD_PIN_SENSE, 4, RO, VO), -+ _REG(CX2072X_PORTD_GAIN_RIGHT, 1, RW, NV), -+ _REG(CX2072X_PORTD_GAIN_LEFT, 1, RW, NV), -+ _REG(CX2072X_PORTE_CONNECTION_SELECT_CTRL, 1, RW, NV), -+ _REG(CX2072X_PORTE_POWER_STATE, 1, RW, NV), -+ _REG(CX2072X_PORTE_PIN_CTRL, 1, RW, NV), -+ _REG(CX2072X_PORTE_UNSOLICITED_RESPONSE, 1, RW, NV), -+ _REG(CX2072X_PORTE_PIN_SENSE, 4, RO, VO), -+ _REG(CX2072X_PORTE_EAPD_BTL, 1, RW, NV), -+ _REG(CX2072X_PORTE_GAIN_RIGHT, 1, RW, NV), -+ _REG(CX2072X_PORTE_GAIN_LEFT, 1, RW, NV), -+ _REG(CX2072X_PORTF_POWER_STATE, 1, RW, NV), -+ _REG(CX2072X_PORTF_PIN_CTRL, 1, RW, NV), -+ _REG(CX2072X_PORTF_UNSOLICITED_RESPONSE, 1, RW, NV), -+ _REG(CX2072X_PORTF_PIN_SENSE, 4, RO, VO), -+ _REG(CX2072X_PORTF_GAIN_RIGHT, 1, RW, NV), -+ _REG(CX2072X_PORTF_GAIN_LEFT, 1, RW, NV), -+ _REG(CX2072X_PORTG_POWER_STATE, 1, RW, NV), -+ _REG(CX2072X_PORTG_PIN_CTRL, 1, RW, NV), -+ _REG(CX2072X_PORTG_CONNECTION_SELECT_CTRL, 1, RW, NV), -+ _REG(CX2072X_PORTG_EAPD_BTL, 1, RW, NV), -+ _REG(CX2072X_PORTM_POWER_STATE, 1, RW, NV), -+ _REG(CX2072X_PORTM_PIN_CTRL, 1, RW, NV), -+ _REG(CX2072X_PORTM_CONNECTION_SELECT_CTRL, 1, RW, NV), -+ _REG(CX2072X_PORTM_EAPD_BTL, 1, RW, NV), -+ _REG(CX2072X_MIXER_POWER_STATE, 1, RW, NV), -+ _REG(CX2072X_MIXER_GAIN_RIGHT_0, 1, RW, NV), -+ _REG(CX2072X_MIXER_GAIN_LEFT_0, 1, WO, NV), -+ _REG(CX2072X_MIXER_GAIN_RIGHT_1, 1, RW, NV), -+ _REG(CX2072X_MIXER_GAIN_LEFT_1, 1, RW, NV), -+ _REG(CX2072X_EQ_ENABLE_BYPASS, 2, RW, NV), -+ _REG(CX2072X_EQ_B0_COEFF, 2, WO, VO), -+ _REG(CX2072X_EQ_B1_COEFF, 2, WO, VO), -+ _REG(CX2072X_EQ_B2_COEFF, 2, WO, VO), -+ _REG(CX2072X_EQ_A1_COEFF, 2, WO, VO), -+ _REG(CX2072X_EQ_A2_COEFF, 2, WO, VO), -+ _REG(CX2072X_EQ_G_COEFF, 1, WO, VO), -+ _REG(CX2072X_EQ_BAND, 1, WO, VO), -+ _REG(CX2072X_SPKR_DRC_ENABLE_STEP, 1, RW, NV), -+ _REG(CX2072X_SPKR_DRC_CONTROL, 4, RW, NV), -+ _REG(CX2072X_SPKR_DRC_TEST, 4, RW, NV), -+ _REG(CX2072X_DIGITAL_BIOS_TEST0, 4, RW, NV), -+ _REG(CX2072X_DIGITAL_BIOS_TEST2, 4, RW, NV), -+ _REG(CX2072X_I2SPCM_CONTROL1, 4, RW, NV), -+ _REG(CX2072X_I2SPCM_CONTROL2, 4, RW, NV), -+ _REG(CX2072X_I2SPCM_CONTROL3, 4, RW, NV), -+ _REG(CX2072X_I2SPCM_CONTROL4, 4, RW, NV), -+ _REG(CX2072X_I2SPCM_CONTROL5, 4, RW, NV), -+ _REG(CX2072X_I2SPCM_CONTROL6, 4, RW, NV), -+ _REG(CX2072X_UM_INTERRUPT_CRTL_E, 4, RW, NV), -+ _REG(CX2072X_CODEC_TEST20, 2, RW, NV), -+ _REG(CX2072X_CODEC_TEST26, 2, RW, NV), -+ _REG(CX2072X_ANALOG_TEST4, 2, RW, NV), -+ _REG(CX2072X_ANALOG_TEST5, 2, RW, NV), -+ _REG(CX2072X_ANALOG_TEST6, 2, WO, NV), -+ _REG(CX2072X_ANALOG_TEST7, 2, RW, NV), -+ _REG(CX2072X_ANALOG_TEST8, 2, RW, NV), -+ _REG(CX2072X_ANALOG_TEST9, 2, RW, NV), -+ _REG(CX2072X_ANALOG_TEST10, 2, RW, NV), -+ _REG(CX2072X_ANALOG_TEST11, 2, RW, NV), -+ _REG(CX2072X_ANALOG_TEST12, 2, RW, NV), -+ _REG(CX2072X_ANALOG_TEST13, 2, RW, NV), -+ _REG(CX2072X_DIGITAL_TEST0, 2, RW, NV), -+ _REG(CX2072X_DIGITAL_TEST1, 2, RW, NV), -+ _REG(CX2072X_DIGITAL_TEST11, 2, RW, NV), -+ _REG(CX2072X_DIGITAL_TEST12, 2, RW, NV), -+ _REG(CX2072X_DIGITAL_TEST15, 2, RW, NV), -+ _REG(CX2072X_DIGITAL_TEST16, 2, RW, NV), -+ _REG(CX2072X_DIGITAL_TEST17, 2, RW, NV), -+ _REG(CX2072X_DIGITAL_TEST18, 2, RW, NV), -+ _REG(CX2072X_DIGITAL_TEST19, 2, RW, NV), -+ _REG(CX2072X_DIGITAL_TEST20, 2, RW, NV), -+}; -+#endif -+ -+/* codec private data */ -+struct cx2072x_priv { -+ struct regmap *regmap; -+ unsigned int mclk; -+ struct device *dev; -+ struct snd_soc_codec *codec; -+ struct snd_soc_dai_driver *dai_drv; -+ int is_biason; -+ struct snd_soc_jack *jack; -+ bool jack_detecting; -+ bool jack_mic; -+ int jack_mode; -+ int jack_flips; -+ unsigned int jack_state; -+ int audsmt_enable; -+ struct mutex lock; -+ unsigned int bclk_ratio; -+ -+#ifdef ENABLE_MIC_POP_WA -+ struct delayed_work mic_pop_workq; -+#endif -+ -+ bool plbk_dsp_en; -+ bool plbk_dsp_changed; -+ bool plbk_dsp_init; -+ bool pll_changed; -+ bool i2spcm_changed; -+ int sample_size; /*used for non-PCM mode*/ -+ int frame_size; /*used for non-PCM mode*/ -+ int sample_rate; -+ unsigned int dai_fmt; -+ int tdm_rx_mask; -+ int tdm_tx_mask; -+ int tdm_slot_width; -+ int tdm_slots; -+ u32 rev_id; -+}; -+ -+/* -+* DAC/ADC Volume -+* -+* max : 74 : 0 dB -+* ( in 1 dB step ) -+* min : 0 : -74 dB -+*/ -+static const DECLARE_TLV_DB_SCALE(adc_tlv, -7400, 100, 0); -+static const DECLARE_TLV_DB_SCALE(dac_tlv, -7400, 100, 0); -+static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 1200, 0); -+ -+#define get_cx2072x_priv(_codec_) \ -+ ((struct cx2072x_priv *) snd_soc_codec_get_drvdata(_codec_)) -+ -+/* Lookup table for PRE_DIV*/ -+static struct { -+ unsigned int mclk; -+ unsigned int div; -+} MCLK_PRE_DIV[] = { -+ { 6144000, 1 }, -+ { 12288000, 2 }, -+ { 19200000, 3 }, -+ { 26000000, 4 }, -+ { 28224000, 5 }, -+ { 36864000, 6 }, -+ { 36864000, 7 },/* Don't use div 7*/ -+ { 48000000, 8 }, -+ { 49152000, 8 }, -+}; -+ -+/* -+ * cx2072x register cache. -+ */ -+static const struct reg_default cx2072x_reg_defaults[] = { -+ { 0x0414, 0x00000003 }, /*2072X_AFG_POWER_STATE */ -+ { 0x0420, 0x00000000 }, /*2072X_UM_RESPONSE */ -+ { 0x0454, 0x00000000 }, /*2072X_GPIO_DATA */ -+ { 0x0458, 0x00000000 }, /*2072X_GPIO_ENABLE */ -+ { 0x045c, 0x00000000 }, /*2072X_GPIO_DIRECTION */ -+ { 0x0460, 0x00000000 }, /*2072X_GPIO_WAKE */ -+ { 0x0464, 0x00000000 }, /*2072X_GPIO_UM_ENABLE */ -+ { 0x0468, 0x00000000 }, /*2072X_GPIO_STICKY_MASK */ -+ { 0x43c8, 0x00000031 }, /*2072X_DAC1_CONVERTER_FORMAT */ -+ { 0x41c0, 0x0000004a }, /*2072X_DAC1_AMP_GAIN_RIGHT */ -+ { 0x41e0, 0x0000004a }, /*2072X_DAC1_AMP_GAIN_LEFT */ -+ { 0x4014, 0x00000433 }, /*2072X_DAC1_POWER_STATE */ -+ { 0x4018, 0x00000000 }, /*2072X_DAC1_CONVERTER_STREAM_CHANNEL */ -+ { 0x4030, 0x00000000 }, /*2072X_DAC1_EAPD_ENABLE */ -+ { 0x47c8, 0x00000031 }, /*2072X_DAC2_CONVERTER_FORMAT */ -+ { 0x45c0, 0x0000004a }, /*2072X_DAC2_AMP_GAIN_RIGHT */ -+ { 0x45e0, 0x0000004a }, /*2072X_DAC2_AMP_GAIN_LEFT */ -+ { 0x4414, 0x00000433 }, /*2072X_DAC2_POWER_STATE */ -+ { 0x4418, 0x00000000 }, /*2072X_DAC2_CONVERTER_STREAM_CHANNEL */ -+ { 0x4fc8, 0x00000031 }, /*2072X_ADC1_CONVERTER_FORMAT */ -+ { 0x4d80, 0x0000004a }, /*2072X_ADC1_AMP_GAIN_RIGHT_0 */ -+ { 0x4da0, 0x0000004a }, /*2072X_ADC1_AMP_GAIN_LEFT_0 */ -+ { 0x4d84, 0x0000004a }, /*2072X_ADC1_AMP_GAIN_RIGHT_1 */ -+ { 0x4da4, 0x0000004a }, /*2072X_ADC1_AMP_GAIN_LEFT_1 */ -+ { 0x4d88, 0x0000004a }, /*2072X_ADC1_AMP_GAIN_RIGHT_2 */ -+ { 0x4da8, 0x0000004a }, /*2072X_ADC1_AMP_GAIN_LEFT_2 */ -+ { 0x4d8c, 0x0000004a }, /*2072X_ADC1_AMP_GAIN_RIGHT_3 */ -+ { 0x4dac, 0x0000004a }, /*2072X_ADC1_AMP_GAIN_LEFT_3 */ -+ { 0x4d90, 0x0000004a }, /*2072X_ADC1_AMP_GAIN_RIGHT_4 */ -+ { 0x4db0, 0x0000004a }, /*2072X_ADC1_AMP_GAIN_LEFT_4 */ -+ { 0x4d94, 0x0000004a }, /*2072X_ADC1_AMP_GAIN_RIGHT_5 */ -+ { 0x4db4, 0x0000004a }, /*2072X_ADC1_AMP_GAIN_LEFT_5 */ -+ { 0x4d98, 0x0000004a }, /*2072X_ADC1_AMP_GAIN_RIGHT_6 */ -+ { 0x4db8, 0x0000004a }, /*2072X_ADC1_AMP_GAIN_LEFT_6 */ -+ { 0x4c04, 0x00000000 }, /*2072X_ADC1_CONNECTION_SELECT_CONTROL */ -+ { 0x4c14, 0x00000433 }, /*2072X_ADC1_POWER_STATE */ -+ { 0x4c18, 0x00000000 }, /*2072X_ADC1_CONVERTER_STREAM_CHANNEL */ -+ { 0x53c8, 0x00000031 }, /*2072X_ADC2_CONVERTER_FORMAT */ -+ { 0x5180, 0x0000004a }, /*2072X_ADC2_AMP_GAIN_RIGHT_0 */ -+ { 0x51a0, 0x0000004a }, /*2072X_ADC2_AMP_GAIN_LEFT_0 */ -+ { 0x5184, 0x0000004a }, /*2072X_ADC2_AMP_GAIN_RIGHT_1 */ -+ { 0x51a4, 0x0000004a }, /*2072X_ADC2_AMP_GAIN_LEFT_1 */ -+ { 0x5188, 0x0000004a }, /*2072X_ADC2_AMP_GAIN_RIGHT_2 */ -+ { 0x51a8, 0x0000004a }, /*2072X_ADC2_AMP_GAIN_LEFT_2 */ -+ { 0x5004, 0x00000000 }, /*2072X_ADC2_CONNECTION_SELECT_CONTROL */ -+ { 0x5014, 0x00000433 }, /*2072X_ADC2_POWER_STATE */ -+ { 0x5018, 0x00000000 }, /*2072X_ADC2_CONVERTER_STREAM_CHANNEL */ -+ { 0x5804, 0x00000000 }, /*2072X_PORTA_CONNECTION_SELECT_CTRL */ -+ { 0x5814, 0x00000433 }, /*2072X_PORTA_POWER_STATE */ -+ { 0x581c, 0x000000c0 }, /*2072X_PORTA_PIN_CTRL */ -+ { 0x5820, 0x00000000 }, /*2072X_PORTA_UNSOLICITED_RESPONSE */ -+ { 0x5824, 0x00000000 }, /*2072X_PORTA_PIN_SENSE */ -+ { 0x5830, 0x00000002 }, /*2072X_PORTA_EAPD_BTL */ -+ { 0x6014, 0x00000433 }, /*2072X_PORTB_POWER_STATE */ -+ { 0x601c, 0x00000000 }, /*2072X_PORTB_PIN_CTRL */ -+ { 0x6020, 0x00000000 }, /*2072X_PORTB_UNSOLICITED_RESPONSE */ -+ { 0x6024, 0x00000000 }, /*2072X_PORTB_PIN_SENSE */ -+ { 0x6030, 0x00000002 }, /*2072X_PORTB_EAPD_BTL */ -+ { 0x6180, 0x00000000 }, /*2072X_PORTB_GAIN_RIGHT */ -+ { 0x61a0, 0x00000000 }, /*2072X_PORTB_GAIN_LEFT */ -+ { 0x6814, 0x00000433 }, /*2072X_PORTC_POWER_STATE */ -+ { 0x681c, 0x00000000 }, /*2072X_PORTC_PIN_CTRL */ -+ { 0x6980, 0x00000000 }, /*2072X_PORTC_GAIN_RIGHT */ -+ { 0x69a0, 0x00000000 }, /*2072X_PORTC_GAIN_LEFT */ -+ { 0x6414, 0x00000433 }, /*2072X_PORTD_POWER_STATE */ -+ { 0x641c, 0x00000020 }, /*2072X_PORTD_PIN_CTRL */ -+ { 0x6420, 0x00000000 }, /*2072X_PORTD_UNSOLICITED_RESPONSE */ -+ { 0x6424, 0x00000000 }, /*2072X_PORTD_PIN_SENSE */ -+ { 0x6580, 0x00000000 }, /*2072X_PORTD_GAIN_RIGHT */ -+ { 0x65a0, 0x00000000 }, /*2072X_PORTD_GAIN_LEFT */ -+ { 0x7404, 0x00000000 }, /*2072X_PORTE_CONNECTION_SELECT_CTRL */ -+ { 0x7414, 0x00000433 }, /*2072X_PORTE_POWER_STATE */ -+ { 0x741c, 0x00000040 }, /*2072X_PORTE_PIN_CTRL */ -+ { 0x7420, 0x00000000 }, /*2072X_PORTE_UNSOLICITED_RESPONSE */ -+ { 0x7424, 0x00000000 }, /*2072X_PORTE_PIN_SENSE */ -+ { 0x7430, 0x00000002 }, /*2072X_PORTE_EAPD_BTL */ -+ { 0x7580, 0x00000000 }, /*2072X_PORTE_GAIN_RIGHT */ -+ { 0x75a0, 0x00000000 }, /*2072X_PORTE_GAIN_LEFT */ -+ { 0x7814, 0x00000433 }, /*2072X_PORTF_POWER_STATE */ -+ { 0x781c, 0x00000000 }, /*2072X_PORTF_PIN_CTRL */ -+ { 0x7820, 0x00000000 }, /*2072X_PORTF_UNSOLICITED_RESPONSE */ -+ { 0x7824, 0x00000000 }, /*2072X_PORTF_PIN_SENSE */ -+ { 0x7980, 0x00000000 }, /*2072X_PORTF_GAIN_RIGHT */ -+ { 0x79a0, 0x00000000 }, /*2072X_PORTF_GAIN_LEFT */ -+ { 0x5c14, 0x00000433 }, /*2072X_PORTG_POWER_STATE */ -+ { 0x5c1c, 0x00000040 }, /*2072X_PORTG_PIN_CTRL */ -+ { 0x5c04, 0x00000000 }, /*2072X_PORTG_CONNECTION_SELECT_CTRL */ -+ { 0x5c30, 0x00000002 }, /*2072X_PORTG_EAPD_BTL */ -+ { 0x8814, 0x00000433 }, /*2072X_PORTM_POWER_STATE */ -+ { 0x881c, 0x00000000 }, /*2072X_PORTM_PIN_CTRL */ -+ { 0x8804, 0x00000000 }, /*2072X_PORTM_CONNECTION_SELECT_CTRL */ -+ { 0x8830, 0x00000002 }, /*2072X_PORTM_EAPD_BTL */ -+ { 0x5414, 0x00000433 }, /*2072X_MIXER_POWER_STATE */ -+ { 0x5580, 0x0000004a }, /*2072X_MIXER_GAIN_RIGHT_0 */ -+ { 0x55a0, 0x0000004a }, /*2072X_MIXER_GAIN_LEFT_0 */ -+ { 0x5584, 0x0000004a }, /*2072X_MIXER_GAIN_RIGHT_1 */ -+ { 0x55a4, 0x0000004a }, /*2072X_MIXER_GAIN_LEFT_1 */ -+ { 0x6d00, 0x0000720c }, /*2072X_EQ_ENABLE_BYPASS */ -+ { 0x6d10, 0x040065a4 }, /*2072X_SPKR_DRC_ENABLE_STEP */ -+ { 0x6d14, 0x007b0024 }, /*2072X_SPKR_DRC_CONTROL */ -+ { 0X6D18, 0x00000000 }, /*2072X_SPKR_DRC_TEST */ -+ { 0x6d80, 0x001f008a }, /*2072X_DIGITAL_BIOS_TEST0 */ -+ { 0x6d84, 0x00990026 }, /*2072X_DIGITAL_BIOS_TEST2 */ -+ { 0x6e00, 0x00010001 }, /*2072X_I2SPCM_CONTROL1 */ -+ { 0x6e04, 0x00000000 }, /*2072X_I2SPCM_CONTROL2 */ -+ { 0x6e08, 0x00000000 }, /*2072X_I2SPCM_CONTROL3 */ -+ { 0x6e0c, 0x00000000 }, /*2072X_I2SPCM_CONTROL4 */ -+ { 0x6e10, 0x00000000 }, /*2072X_I2SPCM_CONTROL5 */ -+ { 0x6e18, 0x00000000 }, /*2072X_I2SPCM_CONTROL6 */ -+ { 0x6e14, 0x00000000 }, /*2072X_UM_INTERRUPT_CRTL_E */ -+ { 0x7310, 0x00000600 }, /*2072X_CODEC_TEST20 */ -+ { 0x7328, 0x00000208 }, /*2072X_CODEC_TEST26 */ -+ { 0x7190, 0x00000000 }, /*2072X_ANALOG_TEST4 */ -+ { 0x7194, 0x00000000 }, /*2072X_ANALOG_TEST5 */ -+ { 0x7198, 0x0000059a }, /*2072X_ANALOG_TEST6 */ -+ { 0x719c, 0x000000a7 }, /*2072X_ANALOG_TEST7 */ -+ { 0x71a0, 0x00000017 }, /*2072X_ANALOG_TEST8 */ -+ { 0x71a4, 0x00000000 }, /*2072X_ANALOG_TEST9 */ -+ { 0x71a8, 0x00000285 }, /*2072X_ANALOG_TEST10 */ -+ { 0x71ac, 0x00000000 }, /*2072X_ANALOG_TEST11 */ -+ { 0x71b0, 0x00000000 }, /*2072X_ANALOG_TEST12 */ -+ { 0x71b4, 0x00000000 }, /*2072X_ANALOG_TEST13 */ -+ { 0x7204, 0x00000242 }, /*2072X_DIGITAL_TEST1 */ -+ { 0x7224, 0x00000000 }, /*2072X_DIGITAL_TEST11 */ -+ { 0x7230, 0x00000084 }, /*2072X_DIGITAL_TEST12 */ -+ { 0x723c, 0x00000077 }, /*2072X_DIGITAL_TEST15 */ -+ { 0x7080, 0x00000021 }, /*2072X_DIGITAL_TEST16 */ -+ { 0x7084, 0x00000018 }, /*2072X_DIGITAL_TEST17 */ -+ { 0x7088, 0x00000024 }, /*2072X_DIGITAL_TEST18 */ -+ { 0x708c, 0x00000001 }, /*2072X_DIGITAL_TEST19 */ -+ { 0x7090, 0x00000002 }, /*2072X_DIGITAL_TEST20 */ -+}; -+ -+ -+/* -+ * cx2072x patch. -+ */ -+static const struct reg_sequence cx2072x_patch[] = { -+ { 0x71A4, 0x080 }, /* DC offset Calibration */ -+ { 0x71a8, 0x287 }, /* Set max spk power to 1.5 W */ -+ { 0x7328, 0xa8c }, /* Set average spk power to 1.5W*/ -+ { 0x7310, 0xf01 }, /* */ -+ { 0x7328, 0xa8f }, /* */ -+ { 0x7124, 0x001 }, /* Enable 30 Hz High pass filter*/ -+ { 0x718c, 0x300 }, /* Disable PCBEEP pad */ -+ { 0x731c, 0x100 }, /* Disable SnM mode */ -+ { 0x641c, 0x020 }, /* Enable PortD input */ -+ { 0x0458, 0x040 }, /* Enable GPIO7 pin for button */ -+ { 0x0464, 0x040 }, /* Enable UM for GPIO7 */ -+ { 0x0420, 0x080 }, /* Enable button response */ -+ { 0x7230, 0x0c4 }, /* Enable headset button */ -+ { 0x7200, 0x415 }, /* Power down class-d during idle*/ -+}; -+ -+ -+/* return register size */ -+static unsigned int cx2072x_register_size(struct device *dev, -+ unsigned int reg) -+{ -+ switch (reg) { -+ case CX2072X_VENDOR_ID: -+ case CX2072X_REVISION_ID: -+ case CX2072X_PORTA_PIN_SENSE: -+ case CX2072X_PORTB_PIN_SENSE: -+ case CX2072X_PORTD_PIN_SENSE: -+ case CX2072X_PORTE_PIN_SENSE: -+ case CX2072X_PORTF_PIN_SENSE: -+ case CX2072X_I2SPCM_CONTROL1: -+ case CX2072X_I2SPCM_CONTROL2: -+ case CX2072X_I2SPCM_CONTROL3: -+ case CX2072X_I2SPCM_CONTROL4: -+ case CX2072X_I2SPCM_CONTROL5: -+ case CX2072X_I2SPCM_CONTROL6: -+ case CX2072X_UM_INTERRUPT_CRTL_E: -+ case CX2072X_EQ_G_COEFF: -+ /*case CX2072X_SPKR_DRC_ENABLE_STEP:*/ -+ case CX2072X_SPKR_DRC_CONTROL: -+ case CX2072X_SPKR_DRC_TEST: -+ case CX2072X_DIGITAL_BIOS_TEST0: -+ case CX2072X_DIGITAL_BIOS_TEST2: -+ return 4; -+ case CX2072X_EQ_ENABLE_BYPASS: -+ case CX2072X_EQ_B0_COEFF: -+ case CX2072X_EQ_B1_COEFF: -+ case CX2072X_EQ_B2_COEFF: -+ case CX2072X_EQ_A1_COEFF: -+ case CX2072X_EQ_A2_COEFF: -+ case CX2072X_DAC1_CONVERTER_FORMAT: -+ case CX2072X_DAC2_CONVERTER_FORMAT: -+ case CX2072X_ADC1_CONVERTER_FORMAT: -+ case CX2072X_ADC2_CONVERTER_FORMAT: -+ case CX2072X_CODEC_TEST20: -+ case CX2072X_CODEC_TEST26: -+ case CX2072X_ANALOG_TEST3: -+ case CX2072X_ANALOG_TEST4: -+ case CX2072X_ANALOG_TEST5: -+ case CX2072X_ANALOG_TEST6: -+ case CX2072X_ANALOG_TEST7: -+ case CX2072X_ANALOG_TEST8: -+ case CX2072X_ANALOG_TEST9: -+ case CX2072X_ANALOG_TEST10: -+ case CX2072X_ANALOG_TEST11: -+ case CX2072X_ANALOG_TEST12: -+ case CX2072X_ANALOG_TEST13: -+ case CX2072X_DIGITAL_TEST0: -+ case CX2072X_DIGITAL_TEST1: -+ case CX2072X_DIGITAL_TEST11: -+ case CX2072X_DIGITAL_TEST12: -+ case CX2072X_DIGITAL_TEST15: -+ case CX2072X_DIGITAL_TEST16: -+ case CX2072X_DIGITAL_TEST17: -+ case CX2072X_DIGITAL_TEST18: -+ case CX2072X_DIGITAL_TEST19: -+ case CX2072X_DIGITAL_TEST20: -+ return 2; -+ default: -+ return 1; -+ } -+ -+} -+ -+#ifdef CXDBG_REG_DUMP -+static const char *cx2072x_get_reg_name(struct device *dev, unsigned int reg) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(cx2072x_regs); i++) -+ if (cx2072x_regs[i].addr == reg) -+ return cx2072x_regs[i].name; -+ -+ dev_err(dev, "Unkown reg %08x\n", reg); -+ -+ return "Unknown reg"; -+} -+#endif -+ -+static int cx2072x_reg_write(void *context, unsigned int reg, -+ unsigned int value) -+{ -+ struct i2c_client *client = context; -+ unsigned int i; -+ unsigned int size; -+ uint8_t buf[6]; -+ int ret; -+ struct device *dev = &client->dev; -+ -+ size = cx2072x_register_size(dev, reg); -+ if (size == 0) -+ return -EINVAL; -+#ifdef CXDBG_REG_DUMP -+ dev_dbg(dev, "I2C write address %40s,%d <= %08x\n", -+ cx2072x_get_reg_name(dev, reg), size, value); -+#endif -+ -+ if (reg == CX2072X_UM_INTERRUPT_CRTL_E) { -+ /* workaround to update the MSB byte only */ -+ reg += 3; -+ size = 1; -+ value >>= 24; -+ } -+ -+ buf[0] = reg >> 8; -+ buf[1] = reg & 0xff; -+ -+ for (i = 2; i < (size + 2); ++i) { -+ buf[i] = value; -+ value >>= 8; -+ } -+ -+ ret = i2c_master_send(client, buf, size + 2); -+ if (ret == size + 2) { -+ ret = 0; -+ } else if (ret < 0) { -+ dev_err(dev, -+ "I2C write address failed\n"); -+ } else { -+ dev_err(dev, -+ "I2C write failed\n"); -+ ret = -EIO; -+ } -+ return ret; -+} -+ -+static int cx2072x_reg_bulk_write(struct snd_soc_codec *codec, -+ unsigned int reg, const void *val, size_t val_count) -+{ -+ /*fix me*/ -+ struct i2c_client *client = to_i2c_client(codec->dev); -+ uint8_t buf[2 + MAC_EQ_COEFF]; -+ int ret; -+ struct device *dev = &client->dev; -+ -+#ifdef CXDBG_REG_DUMP -+ dev_dbg(dev, "I2C bulk write address %40s,%zd\n", -+ cx2072x_get_reg_name(dev, reg), val_count); -+#endif -+ -+ if (val_count > MAC_EQ_COEFF) { -+ dev_err(dev, -+ "cx2072x_reg_bulk_write failed, writing count = %zd\n", -+ val_count); -+ return -EINVAL; -+ } -+ -+ buf[0] = reg >> 8; -+ buf[1] = reg & 0xff; -+ -+ memcpy(&buf[2], val, val_count); -+ -+ ret = i2c_master_send(client, buf, val_count + 2); -+ if (ret == val_count + 2) -+ return 0; -+ else if (ret < 0) { -+ dev_err(dev, -+ "I2C bulk write address failed\n"); -+ } else { -+ dev_err(dev, -+ "I2C bulk write address failed\n"); -+ ret = -EIO; -+ } -+ return ret; -+} -+ -+ -+/* get suggested pre_div valuce from mclk frequency */ -+static unsigned int get_div_from_mclk(unsigned int mclk) -+{ -+ unsigned int div = 8; -+ int i = 0; -+ -+ for (i = 0; i < ARRAY_SIZE(MCLK_PRE_DIV); i++) { -+ if (mclk <= MCLK_PRE_DIV[i].mclk) { -+ div = MCLK_PRE_DIV[i].div; -+ break; -+ } -+ } -+ return div; -+} -+static int cx2072x_reg_read(void *context, unsigned int reg, -+ unsigned int *value) -+{ -+ int ret; -+ unsigned int size; -+ uint8_t send_buf[2]; -+ unsigned int recv_buf = 0; -+ struct i2c_client *client = context; -+ struct i2c_msg msgs[2]; -+ struct device *dev = &client->dev; -+ -+ size = cx2072x_register_size(dev, reg); -+ if (size == 0) -+ return -EINVAL; -+ -+ send_buf[0] = reg >> 8; -+ send_buf[1] = reg & 0xff; -+ -+ msgs[0].addr = client->addr; -+ msgs[0].len = sizeof(send_buf); -+ msgs[0].buf = send_buf; -+ msgs[0].flags = 0; -+ -+ msgs[1].addr = client->addr; -+ msgs[1].len = size; -+ msgs[1].buf = (uint8_t *)&recv_buf; -+ msgs[1].flags = I2C_M_RD; -+ -+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); -+ if (ret < 0) { -+ dev_err(dev, -+ "Failed to register codec: %d\n", ret); -+ return ret; -+ } else if (ret != ARRAY_SIZE(msgs)) { -+ dev_err(dev, -+ "Failed to register codec: %d\n", ret); -+ return -EIO; -+ } -+ -+ *value = recv_buf; -+ -+#ifdef CXDBG_REG_DUMP -+ dev_dbg(dev, -+ "I2C read address %40s,%d => %08x\n", -+ cx2072x_get_reg_name(dev, reg), size, *value); -+#endif -+ return 0; -+} -+ -+static int cx2072x_config_headset_det(struct cx2072x_priv *cx2072x) -+{ -+ const int interrupt_gpio_pin = 1; -+ -+ dev_dbg(cx2072x->dev, -+ "Configure interrupt pin: %d\n", interrupt_gpio_pin); -+ /*No-sticky input type*/ -+ regmap_write(cx2072x->regmap, CX2072X_GPIO_STICKY_MASK, 0x1f); -+ /*Use GPOI0 as intrrupt output pin*/ -+ regmap_write(cx2072x->regmap, CX2072X_UM_INTERRUPT_CRTL_E, 0x12 << 24); -+ -+ /* Enables unsolitited message on PortA*/ -+ regmap_write(cx2072x->regmap, CX2072X_PORTA_UNSOLICITED_RESPONSE, 0x80); -+ -+ /* support both nokia and apple headset set. Monitor time = 275 ms*/ -+ regmap_write(cx2072x->regmap, CX2072X_DIGITAL_TEST15, 0x73); -+ -+ /* Disable TIP detection*/ -+ regmap_write(cx2072x->regmap, CX2072X_ANALOG_TEST12, 0x300); -+ -+ /* Switch MusicD3Live pin to GPIO */ -+ regmap_write(cx2072x->regmap, CX2072X_DIGITAL_TEST1, 0); -+ -+ return 0; -+} -+ -+static int cx2072x_config_pll(struct cx2072x_priv *cx2072x) -+{ -+ struct device *dev = cx2072x->dev; -+ unsigned int pre_div; -+ unsigned int pre_div_val; -+ unsigned int pll_input; -+ unsigned int pll_output; -+ unsigned int int_div; -+ unsigned int frac_div; -+ unsigned int frac_num = 0; -+ unsigned int sample_rate = cx2072x->sample_rate; -+ int pt_sample_per_sync = 2; -+ int pt_clock_per_sample = 96; -+ -+ switch (sample_rate) { -+ case 48000: -+ case 32000: -+ case 24000: -+ case 16000: -+ break; -+ case 96000: -+ pt_sample_per_sync = 1; -+ pt_clock_per_sample = 48; -+ break; -+ case 192000: -+ pt_sample_per_sync = 0; -+ pt_clock_per_sample = 24; -+ break; -+ default: -+ dev_err(dev, "Unsupported sample rate %d\n", sample_rate); -+ return -EINVAL; -+ } -+ -+ -+ /*Configure PLL settings*/ -+ pre_div = get_div_from_mclk(cx2072x->mclk); -+ pll_input = cx2072x->mclk / pre_div; -+ pll_output = sample_rate * 3072; -+ int_div = pll_output / pll_input; -+ frac_div = pll_output - (int_div * pll_input); -+ -+ if (frac_div) { -+ frac_div *= 1000; -+ frac_div /= pll_input; -+ frac_num = ((4000 + frac_div) * ((1 << 20) - 4)); -+ do_div(frac_num, 7); -+ frac_num = (frac_num + 499) / 1000; -+ } -+ pre_div_val = (pre_div - 1) * 2; -+ -+ regmap_write(cx2072x->regmap, CX2072X_ANALOG_TEST4, 0X40 -+ | (pre_div_val << 8)); -+ if (frac_div == 0) { -+ /*Int mode*/ -+ regmap_write(cx2072x->regmap, CX2072X_ANALOG_TEST7, 0x100); -+ } else { -+ /*frac mode*/ -+ regmap_write(cx2072x->regmap, CX2072X_ANALOG_TEST6, -+ frac_num & 0xfff); -+ regmap_write(cx2072x->regmap, CX2072X_ANALOG_TEST7, -+ (unsigned char)(frac_num >> 12)); -+ } -+ int_div--; -+ regmap_write(cx2072x->regmap, CX2072X_ANALOG_TEST8, -+ (unsigned char)int_div & 0xffff); -+ -+ /* configure PLL tracking*/ -+ if (frac_div == 0) { -+ /* disable PLL tracking*/ -+ regmap_write(cx2072x->regmap, CX2072X_DIGITAL_TEST16, 0x00); -+ } else { -+ /* configure and enable PLL tracking*/ -+ regmap_write(cx2072x->regmap, CX2072X_DIGITAL_TEST16, -+ (pt_sample_per_sync << 4) & 0xf0); -+ regmap_write(cx2072x->regmap, CX2072X_DIGITAL_TEST17, -+ pt_clock_per_sample); -+ regmap_write(cx2072x->regmap, CX2072X_DIGITAL_TEST18, -+ pt_clock_per_sample * 3 / 2); -+ regmap_write(cx2072x->regmap, CX2072X_DIGITAL_TEST19, 0x01); -+ regmap_write(cx2072x->regmap, CX2072X_DIGITAL_TEST20, 0x02); -+ regmap_update_bits(cx2072x->regmap, CX2072X_DIGITAL_TEST16, -+ 0X01, 0X01); -+ } -+ -+ return 0; -+} -+ -+ -+static int cx2072x_config_i2spcm(struct cx2072x_priv *cx2072x) -+{ -+ struct device *dev = cx2072x->dev; -+ -+ int is_i2s = 0; -+ int has_one_bit_delay = 0; -+ int is_right_j = 0; -+ int is_frame_inv = 0; -+ int is_bclk_inv = 0; -+ int pulse_len = 1; -+ int frame_len = cx2072x->frame_size; -+ int sample_size = cx2072x->sample_size; -+ int i2s_right_slot; -+ int i2s_right_pause_interval = 0; -+ int i2s_right_pause_pos; -+ int is_big_endian = 1; -+ const int slots_per_channel = cx2072x->tdm_slot_width / BITS_PER_SLOT; -+ const unsigned fmt = cx2072x->dai_fmt; -+ -+ REG_I2SPCM_CTRL_REG1 reg1 = { .ulVal = 0 }; -+ REG_I2SPCM_CTRL_REG2 reg2 = { .ulVal = 0 }; -+ REG_I2SPCM_CTRL_REG3 reg3 = { .ulVal = 0 }; -+ REG_I2SPCM_CTRL_REG4 reg4 = { .ulVal = 0 }; -+ REG_I2SPCM_CTRL_REG5 reg5 = { .ulVal = 0 }; -+ REG_I2SPCM_CTRL_REG6 reg6 = { .ulVal = 0 }; -+ REG_DIGITAL_BIOS_TEST2 regDBT2 = { .ulVal = 0 }; -+ -+ if (frame_len <= 0) { -+ dev_err(dev, "Incorrect frame len %d\n", frame_len); -+ return -EINVAL; -+ } -+ -+ if (sample_size <= 0) { -+ dev_err(dev, "Incorrect sample size %d\n", sample_size); -+ return -EINVAL; -+ } -+ -+ /*fix me */ -+ regDBT2.ulVal = 0xac; -+ -+ /* set master/slave */ -+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { -+ case SND_SOC_DAIFMT_CBM_CFM: -+ reg2.r.tx_master = 1; -+ reg3.r.rx_master = 1; -+ dev_err(dev, "DAI master mode is not implemented yet.\n"); -+ return -EINVAL; -+ case SND_SOC_DAIFMT_CBS_CFS: -+ break; -+ default: -+ dev_err(dev, "Unsupported DAI master mode\n"); -+ return -EINVAL; -+ } -+ -+ /* set format */ -+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { -+ case SND_SOC_DAIFMT_I2S: -+ is_i2s = 1; -+ has_one_bit_delay = 1; -+ pulse_len = frame_len / 2; -+ break; -+ case SND_SOC_DAIFMT_RIGHT_J: -+ is_i2s = 1; -+ is_right_j = 1; -+ pulse_len = frame_len / 2; -+ break; -+ case SND_SOC_DAIFMT_LEFT_J: -+ is_i2s = 1; -+ pulse_len = frame_len / 2; -+ break; -+ case SND_SOC_DAIFMT_DSP_A: -+ has_one_bit_delay = 1; -+ break; -+ case SND_SOC_DAIFMT_DSP_B: -+ break; -+ default: -+ dev_err(dev, "Unsupported DAI format\n"); -+ return -EINVAL; -+ } -+ -+ /* clock inversion */ -+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { -+ case SND_SOC_DAIFMT_NB_NF: -+ is_frame_inv = is_i2s ? 1 : 0; -+ is_bclk_inv = is_i2s ? 1 : 0; -+ break; -+ case SND_SOC_DAIFMT_IB_IF: -+ is_frame_inv = is_i2s ? 0 : 1; -+ is_bclk_inv = is_i2s ? 0 : 1; -+ break; -+ case SND_SOC_DAIFMT_IB_NF: -+ is_frame_inv = is_i2s ? 1 : 0; -+ is_bclk_inv = is_i2s ? 0 : 1; -+ break; -+ case SND_SOC_DAIFMT_NB_IF: -+ is_frame_inv = is_i2s ? 0 : 1; -+ is_bclk_inv = is_i2s ? 1 : 0; -+ break; -+ default: -+ dev_err(dev, "Unsupported DAI clock inversion\n"); -+ return -EINVAL; -+ } -+ -+ cx2072x->dai_fmt = fmt; -+ -+ reg1.r.rx_data_one_line = 1; -+ reg1.r.tx_data_one_line = 1; -+ -+ if (is_i2s) { -+ i2s_right_slot = (frame_len / 2) / BITS_PER_SLOT; -+ i2s_right_pause_interval = (frame_len / 2) % BITS_PER_SLOT; -+ i2s_right_pause_pos = i2s_right_slot * BITS_PER_SLOT; -+ } -+ -+ reg1.r.rx_ws_pol = is_frame_inv; -+ reg1.r.rx_ws_wid = pulse_len - 1; -+ -+ reg1.r.rx_frm_len = frame_len / BITS_PER_SLOT - 1; -+ reg1.r.rx_sa_size = (sample_size / BITS_PER_SLOT) - 1; -+ -+ reg1.r.tx_ws_pol = reg1.r.rx_ws_pol; -+ reg1.r.tx_ws_wid = pulse_len - 1; -+ reg1.r.tx_frm_len = reg1.r.rx_frm_len; -+ reg1.r.tx_sa_size = reg1.r.rx_sa_size; -+ -+ reg2.r.tx_endian_sel = is_big_endian ? 0 : 1; -+ reg2.r.tx_dstart_dly = has_one_bit_delay; -+ -+ reg3.r.rx_endian_sel = is_big_endian ? 0 : 1; -+ reg3.r.rx_dstart_dly = has_one_bit_delay; -+ -+ if (is_i2s) { -+ reg2.r.tx_en_ch1 = 1; -+ reg2.r.tx_en_ch2 = 1; -+ reg2.r.tx_slot_1 = 0; -+ reg2.r.tx_slot_2 = i2s_right_slot; -+ reg3.r.rx_en_ch1 = 1; -+ reg3.r.rx_en_ch2 = 1; -+ reg3.r.rx_slot_1 = 0; -+ reg3.r.rx_slot_2 = i2s_right_slot; -+ reg6.r.rx_pause_start_pos = i2s_right_pause_pos; -+ reg6.r.rx_pause_cycles = i2s_right_pause_interval; -+ reg6.r.tx_pause_start_pos = i2s_right_pause_pos; -+ reg6.r.tx_pause_cycles = i2s_right_pause_interval; -+ } else { -+ reg2.r.tx_en_ch1 = cx2072x->tdm_tx_mask & 0x01 ? 1 : 0; -+ reg2.r.tx_en_ch2 = cx2072x->tdm_tx_mask & 0x02 ? 1 : 0; -+ reg2.r.tx_en_ch3 = cx2072x->tdm_tx_mask & 0x04 ? 1 : 0; -+ reg2.r.tx_en_ch4 = cx2072x->tdm_tx_mask & 0x08 ? 1 : 0; -+ reg2.r.tx_slot_1 = 0; -+ reg2.r.tx_slot_2 = slots_per_channel * 1; -+ reg2.r.tx_slot_3 = slots_per_channel * 2; -+ reg2.r.tx_slot_4 = slots_per_channel * 3; -+ -+ reg3.r.rx_en_ch1 = cx2072x->tdm_rx_mask & 0x01 ? 1 : 0; -+ reg3.r.rx_en_ch2 = cx2072x->tdm_rx_mask & 0x02 ? 1 : 0; -+ reg3.r.rx_en_ch3 = cx2072x->tdm_rx_mask & 0x04 ? 1 : 0; -+ reg3.r.rx_en_ch4 = cx2072x->tdm_rx_mask & 0x08 ? 1 : 0; -+ reg3.r.rx_slot_1 = 0; -+ reg3.r.rx_slot_2 = slots_per_channel * 1; -+ reg3.r.rx_slot_3 = slots_per_channel * 2; -+ reg3.r.rx_slot_4 = slots_per_channel * 3; -+ } -+ regDBT2.r.i2s_bclk_invert = is_bclk_inv; -+ -+ reg1.r.rx_data_one_line = 1; -+ reg1.r.tx_data_one_line = 1; -+ -+#ifdef ENABLE_MIC_POP_WA -+ /*Mute I2S TX*/ -+ reg4.ulVal |= 0x2; -+#endif -+ regmap_write(cx2072x->regmap, CX2072X_I2SPCM_CONTROL1, reg1.ulVal); -+ regmap_write(cx2072x->regmap, CX2072X_I2SPCM_CONTROL2, reg2.ulVal); -+ regmap_write(cx2072x->regmap, CX2072X_I2SPCM_CONTROL3, reg3.ulVal); -+ regmap_write(cx2072x->regmap, CX2072X_I2SPCM_CONTROL4, reg4.ulVal); -+ regmap_write(cx2072x->regmap, CX2072X_I2SPCM_CONTROL5, reg5.ulVal); -+ regmap_write(cx2072x->regmap, CX2072X_I2SPCM_CONTROL6, reg6.ulVal); -+ /*enable bclk and EAPD input*/ -+ if (cx2072x->rev_id == CX2072X_REV_A2) -+ regmap_update_bits(cx2072x->regmap, CX2072X_DIGITAL_BIOS_TEST2, -+ 0x84, 0xFF); -+ else -+ regmap_write(cx2072x->regmap, CX2072X_DIGITAL_BIOS_TEST2, -+ regDBT2.ulVal); -+ -+ return 0; -+} -+ -+ -+static void cx2072x_dsp_init(struct snd_soc_codec *codec) -+{ -+ struct cx2072x_priv *cx2072x = get_cx2072x_priv(codec); -+ int i, j, band; -+ unsigned char *pCoef = &cx2072x_eq_coeff_array[0][0]; -+ -+ regmap_write(cx2072x->regmap, CX2072X_EQ_ENABLE_BYPASS, 0x6e0f); -+ -+ for (i = 0; i < MAX_EQ_BAND; i++) { -+ for (j = 0; j < 2; j++) { -+ cx2072x_reg_bulk_write(codec, CX2072X_EQ_B0_COEFF, -+ pCoef + (MAC_EQ_COEFF*i), MAC_EQ_COEFF); -+ band = i + (j << 3) + (1 << 6); -+ regmap_write(cx2072x->regmap, CX2072X_EQ_BAND, band); -+ mdelay(5); -+ } -+ } -+ -+ cx2072x_reg_bulk_write(codec, CX2072X_SPKR_DRC_ENABLE_STEP, -+ cx2072x_drc_array, MAX_DRC_REGS); -+} -+static void cx2072x_update_dsp(struct snd_soc_codec *codec) -+{ -+ unsigned int afg_reg; -+ struct cx2072x_priv *cx2072x = get_cx2072x_priv(codec); -+ -+ regmap_read(cx2072x->regmap, CX2072X_AFG_POWER_STATE, &afg_reg); -+ -+ if (!cx2072x->plbk_dsp_changed) { -+ /*nothing change*/ -+ return; -+ } -+ -+ if ((afg_reg & 0xf) != 0) { -+ /*skip since device is on D3 mode*/ -+ return; -+ } -+ -+ if (cx2072x->plbk_dsp_en && !cx2072x->plbk_dsp_init) { -+ cx2072x_dsp_init(codec); -+ cx2072x->plbk_dsp_init = true; -+ } -+ -+ if (cx2072x->plbk_dsp_en) { -+ regmap_write(cx2072x->regmap, CX2072X_EQ_ENABLE_BYPASS, -+ 0x6203); -+ regmap_write(cx2072x->regmap, CX2072X_SPKR_DRC_ENABLE_STEP, -+ 0x65); -+ } else { -+ /*By pass DRC and EQ.*/ -+ regmap_write(cx2072x->regmap, CX2072X_EQ_ENABLE_BYPASS, -+ 0x620c); -+ regmap_write(cx2072x->regmap, CX2072X_SPKR_DRC_ENABLE_STEP, -+ 0xa4); -+ } -+ cx2072x->plbk_dsp_changed = false; -+} -+ -+ -+ -+static int afg_power_ev(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *kcontrol, int event) -+{ -+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); -+ struct cx2072x_priv *cx2072x = get_cx2072x_priv(codec); -+ -+ switch (event) { -+ case SND_SOC_DAPM_POST_PMU: -+ regmap_update_bits(cx2072x->regmap, CX2072X_DIGITAL_BIOS_TEST0, -+ 0x00, 0x10); -+ break; -+ -+ case SND_SOC_DAPM_PRE_PMD: -+ regmap_update_bits(cx2072x->regmap, CX2072X_DIGITAL_BIOS_TEST0, -+ 0x10, 0x10); -+ break; -+ } -+ -+ return 0; -+} -+ -+#ifdef ENABLE_MIC_POP_WA -+/* -+ * This work will be called at ADC widget power on time. -+ * to reduce initial mic pop noise caused by hardware -+ */ -+ -+static void cx2072x_anit_mic_pop_work(struct work_struct *work) -+{ -+ struct snd_soc_dapm_context *dapm = -+ container_of(work, struct snd_soc_dapm_context, -+ delayed_work.work); -+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); -+ struct cx2072x_priv *cx2072x = get_cx2072x_priv(codec); -+ -+ dev_dbg(cx2072x->dev, "Unmute I2S TX\n"); -+ /*Unmute I2S TX*/ -+ -+ regmap_update_bits(cx2072x->regmap, CX2072X_I2SPCM_CONTROL4, -+ 0x2, 0x0); -+} -+#endif -+ -+static int adc1_power_ev(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *kcontrol, int event) -+{ -+#ifdef ENABLE_MIC_POP_WA -+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); -+ struct cx2072x_priv *cx2072x = get_cx2072x_priv(codec); -+ -+ switch (event) { -+ case SND_SOC_DAPM_POST_PMU: -+ /* Umute I2S TX after 300 ms to get around the mic -+ * pop noise issue. -+ */ -+ schedule_delayed_work(&codec->dapm.delayed_work, -+ msecs_to_jiffies(300)); -+ break; -+ -+ case SND_SOC_DAPM_POST_PMD: -+ /*Mute TX I2S*/ -+ -+ regmap_update_bits(cx2072x->regmap, CX2072X_I2SPCM_CONTROL4, -+ 0x2, 0x2); -+ break; -+ } -+#endif -+ return 0; -+} -+ -+ -+static int portg_power_ev(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *kcontrol, int event) -+{ -+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); -+ -+ switch (event) { -+ case SND_SOC_DAPM_POST_PMU: -+ cx2072x_update_dsp(codec); -+ break; -+ default: -+ break; -+ } -+ return 0; -+} -+static int cx2072x_plbk_dsp_info(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_info *uinfo) -+{ -+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; -+ uinfo->count = 1; -+ uinfo->value.integer.min = 0; -+ uinfo->value.integer.max = 1; -+ return 0; -+} -+ -+static int cx2072x_plbk_dsp_get(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); -+ struct cx2072x_priv *cx2072x = get_cx2072x_priv(codec); -+ -+ ucontrol->value.integer.value[0] = cx2072x->plbk_dsp_en; -+ -+ return 0; -+} -+ -+static int cx2072x_plbk_dsp_put(struct snd_kcontrol *kcontrol, -+ struct snd_ctl_elem_value *ucontrol) -+{ -+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); -+ struct cx2072x_priv *cx2072x = get_cx2072x_priv(codec); -+ const bool en_dsp = ucontrol->value.integer.value[0]; -+ -+ if (ucontrol->value.integer.value[0] > 1) -+ return -EINVAL; -+ -+ if (cx2072x->plbk_dsp_en != en_dsp) { -+ cx2072x->plbk_dsp_en = en_dsp; -+ cx2072x->plbk_dsp_changed = true; -+ cx2072x_update_dsp(codec); -+ } -+ return 0; -+} -+ -+ -+#define CX2072X_PLBK_DSP_SWITCH(xname) {\ -+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ -+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\ -+ .info = cx2072x_plbk_dsp_info, \ -+ .get = cx2072x_plbk_dsp_get, .put = cx2072x_plbk_dsp_put} -+ -+static const struct snd_kcontrol_new cx2072x_snd_controls[] = { -+ -+ SOC_DOUBLE_R_TLV("PortD Boost", CX2072X_PORTD_GAIN_LEFT, -+ CX2072X_PORTD_GAIN_RIGHT, 0, 3, 0, boost_tlv), -+ SOC_DOUBLE_R_TLV("PortC Boost", CX2072X_PORTC_GAIN_LEFT, -+ CX2072X_PORTC_GAIN_RIGHT, 0, 3, 0, boost_tlv), -+ SOC_DOUBLE_R_TLV("PortB Boost", CX2072X_PORTB_GAIN_LEFT, -+ CX2072X_PORTB_GAIN_RIGHT, 0, 3, 0, boost_tlv), -+ -+ SOC_DOUBLE_R_TLV("PortD ADC1 Volume", CX2072X_ADC1_AMP_GAIN_LEFT_1, -+ CX2072X_ADC1_AMP_GAIN_RIGHT_1, 0, 0x4a, 0, adc_tlv), -+ SOC_DOUBLE_R_TLV("PortC ADC1 Volume", CX2072X_ADC1_AMP_GAIN_LEFT_2, -+ CX2072X_ADC1_AMP_GAIN_RIGHT_2, 0, 0x4a, 0, adc_tlv), -+ SOC_DOUBLE_R_TLV("PortB ADC1 Volume", CX2072X_ADC1_AMP_GAIN_LEFT_0, -+ CX2072X_ADC1_AMP_GAIN_RIGHT_0, 0, 0x4a, 0, adc_tlv), -+ -+ SOC_DOUBLE_R_TLV("DAC1 Volume", CX2072X_DAC1_AMP_GAIN_LEFT, -+ CX2072X_DAC1_AMP_GAIN_RIGHT, 0, 0x4a, 0, dac_tlv), -+ -+ SOC_DOUBLE_R("DAC1 Mute", CX2072X_DAC1_AMP_GAIN_LEFT, -+ CX2072X_DAC1_AMP_GAIN_RIGHT, 7, 1, 0), -+ -+ SOC_DOUBLE_R_TLV("DAC2 Volume", CX2072X_DAC2_AMP_GAIN_LEFT, -+ CX2072X_DAC2_AMP_GAIN_RIGHT, 0, 0x4a, 0, dac_tlv), -+ -+ CX2072X_PLBK_DSP_SWITCH("Playback DSP Switch"), -+}; -+ -+/** -+* cx2072x_hs_jack_report: Report jack notification to upper layer -+* @codec : pointer variable to codec having information related to codec -+* @jack : Pointer variable to snd_soc_jack having information of codec -+* and pin number$ -+* @report : Provides informaton of whether it is headphone or microphone -+* -+*/ -+int cx2072x_hs_jack_report(struct snd_soc_codec *codec) -+{ -+ unsigned int jack; -+ unsigned int type = 0; -+ int state = 0; -+ struct cx2072x_priv *cx2072x = get_cx2072x_priv(codec); -+ -+ -+ regcache_cache_bypass(cx2072x->regmap, true); -+ cx2072x->jack_state = CX_JACK_NONE; -+ regmap_read(cx2072x->regmap, CX2072X_PORTA_PIN_SENSE, &jack); -+ jack = jack >> 24; -+ regmap_read(cx2072x->regmap, CX2072X_DIGITAL_TEST11, &type); -+ regcache_cache_bypass(cx2072x->regmap, false); -+ if (jack == 0x80) { -+ type = type >> 8; -+ -+ if (type & 0x8) { -+ state |= SND_JACK_HEADSET; -+ cx2072x->jack_state = CX_JACK_APPLE_HEADSET; -+ if (type & 0x2) -+ state |= SND_JACK_BTN_0; -+ } else if (type & 0x4) { -+ state |= SND_JACK_HEADPHONE; -+ cx2072x->jack_state = CX_JACK_NOKIE_HEADSET; -+ } else { -+ state |= SND_JACK_HEADPHONE; -+ cx2072x->jack_state = CX_JACK_HEADPHONE; -+ } -+ -+ } -+ -+ -+ /* clear interrupt */ -+ regmap_write(cx2072x->regmap, CX2072X_UM_INTERRUPT_CRTL_E, 0x12 << 24); -+ -+ dev_err(codec->dev, "CX2072X_HSDETECT type=0x%X,Jack state = %x\n", -+ type, state); -+ return state; -+} -+EXPORT_SYMBOL_GPL(cx2072x_hs_jack_report); -+ -+ -+ -+ -+ -+static int cx2072x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, -+ unsigned int rx_mask, int slots, int slot_width) -+{ -+ struct snd_soc_codec *codec = dai->codec; -+ struct cx2072x_priv *cx2072x = snd_soc_codec_get_drvdata(codec); -+ -+ if (slots == 0) -+ goto out; -+ -+ -+ switch (rx_mask) { -+ case 1 ... 0xf: -+ default: -+ return -EINVAL; -+ } -+ -+ -+ switch (tx_mask) { -+ case 1 ... 0xf: -+ default: -+ return -EINVAL; -+ } -+ -+out: -+ cx2072x->tdm_rx_mask = rx_mask; -+ cx2072x->tdm_tx_mask = tx_mask; -+ cx2072x->tdm_slot_width = slot_width; -+ cx2072x->tdm_slots = slots; -+ return 0; -+} -+ -+static int cx2072x_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params, -+ struct snd_soc_dai *dai) -+{ -+ struct snd_soc_codec *codec = dai->codec; -+ struct cx2072x_priv *cx2072x = get_cx2072x_priv(codec); -+ struct device *dev = codec->dev; -+ const unsigned int sample_rate = params_rate(params); -+ int sample_size, frame_size; -+ -+ /* Data sizes if not using TDM */ -+ sample_size = params_width(params); -+ -+ if (sample_size < 0) -+ return sample_size; -+ -+ frame_size = snd_soc_params_to_frame_size(params); -+ if (frame_size < 0) -+ return frame_size; -+ -+ if (cx2072x->bclk_ratio) -+ frame_size = cx2072x->bclk_ratio; -+ -+ switch (sample_rate) { -+ case 48000: -+ case 32000: -+ case 24000: -+ case 16000: -+ case 96000: -+ case 192000: -+ break; -+ default: -+ dev_err(dev, "Unsupported sample rate %d\n", sample_rate); -+ return -EINVAL; -+ } -+ -+ dev_dbg(dev, "Sample size %d bits, frame = %d bits, rate = %d Hz\n", -+ sample_size, frame_size, sample_rate); -+ -+ cx2072x->frame_size = frame_size; -+ cx2072x->sample_size = sample_size; -+ cx2072x->sample_rate = sample_rate; -+ -+ if (cx2072x->pll_changed) { -+ cx2072x_config_pll(cx2072x); -+ cx2072x->pll_changed = false; -+ } -+ if (cx2072x->i2spcm_changed) { -+ cx2072x_config_i2spcm(cx2072x); -+ cx2072x->i2spcm_changed = false; -+ } -+ -+ return 0; -+} -+ -+ -+static int cx2072x_digital_mute(struct snd_soc_dai *dai, int mute) -+{ -+ return 0; -+} -+ -+static int cx2072x_set_dai_bclk_ratio(struct snd_soc_dai *dai, -+ unsigned int ratio) -+{ -+ struct snd_soc_codec *codec = dai->codec; -+ struct cx2072x_priv *cx2072x = get_cx2072x_priv(codec); -+ -+ cx2072x->bclk_ratio = ratio; -+ return 0; -+} -+ -+ -+static int cx2072x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, -+ unsigned int freq, int dir) -+{ -+ struct snd_soc_codec *codec = dai->codec; -+ struct cx2072x_priv *cx2072x = get_cx2072x_priv(codec); -+ struct device *dev = codec->dev; -+ -+ if (freq == 0) { -+ dev_dbg(dev, "MCLK: Switch to internal OSC\n"); -+ return 0; -+ } -+ cx2072x->mclk = freq; -+ switch (clk_id) { -+ case CX2072X_MCLK_EXTERNAL_PLL: -+ dev_dbg(dev, "MCLK: Switch to external PLL\n"); -+ break; -+ case CX2072X_MCLK_INTERNAL_OSC: -+ dev_err(dev, "Unsupported DAI format\n"); -+ break; -+ default: -+ dev_dbg(dev, "the MCLK is not configured\n"); -+ break; -+ } -+ -+ return 0; -+} -+ -+static int cx2072x_set_dai_fmt(struct snd_soc_dai *dai, -+ unsigned int fmt) -+{ -+ struct snd_soc_codec *codec = dai->codec; -+ struct cx2072x_priv *cx2072x = get_cx2072x_priv(codec); -+ struct device *dev = codec->dev; -+ -+ /* set master/slave */ -+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { -+ case SND_SOC_DAIFMT_CBM_CFM: -+ case SND_SOC_DAIFMT_CBS_CFS: -+ break; -+ default: -+ dev_err(dev, "Unsupported DAI master mode\n"); -+ return -EINVAL; -+ } -+ -+ /* set format */ -+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { -+ case SND_SOC_DAIFMT_I2S: -+ case SND_SOC_DAIFMT_RIGHT_J: -+ case SND_SOC_DAIFMT_LEFT_J: -+ case SND_SOC_DAIFMT_DSP_A: -+ case SND_SOC_DAIFMT_DSP_B: -+ break; -+ default: -+ dev_err(dev, "Unsupported DAI format\n"); -+ return -EINVAL; -+ } -+ -+ /* clock inversion */ -+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { -+ case SND_SOC_DAIFMT_NB_NF: -+ case SND_SOC_DAIFMT_IB_IF: -+ case SND_SOC_DAIFMT_IB_NF: -+ case SND_SOC_DAIFMT_NB_IF: -+ break; -+ default: -+ dev_err(dev, "Unsupported DAI clock inversion\n"); -+ return -EINVAL; -+ } -+ -+ cx2072x->dai_fmt = fmt; -+ return 0; -+} -+ -+ -+static const char * const dac_enum_text[] = { -+ "DAC1 Switch", "DAC2 Switch", -+}; -+ -+static const struct soc_enum porta_dac_enum = -+SOC_ENUM_SINGLE(CX2072X_PORTA_CONNECTION_SELECT_CTRL, 0, 2, dac_enum_text); -+ -+static const struct snd_kcontrol_new porta_mux = -+SOC_DAPM_ENUM("PortA Mux", porta_dac_enum); -+ -+static const struct soc_enum portg_dac_enum = -+SOC_ENUM_SINGLE(CX2072X_PORTG_CONNECTION_SELECT_CTRL, 0, 2, dac_enum_text); -+ -+static const struct snd_kcontrol_new portg_mux = -+SOC_DAPM_ENUM("PortG Mux", portg_dac_enum); -+ -+static const struct soc_enum porte_dac_enum = -+SOC_ENUM_SINGLE(CX2072X_PORTE_CONNECTION_SELECT_CTRL, 0, 2, dac_enum_text); -+ -+static const struct snd_kcontrol_new porte_mux = -+SOC_DAPM_ENUM("PortE Mux", porte_dac_enum); -+ -+static const char * const adc1in_sel_text[] = { -+ "PortB Switch", "PortD Switch", "PortC Switch", "Widget15 Switch", -+ "PortE Switch", "PortF Switch", "PortH Switch" -+}; -+ -+static const struct soc_enum adc1in_sel_enum = -+SOC_ENUM_SINGLE(CX2072X_ADC1_CONNECTION_SELECT_CONTROL, 0, 7, adc1in_sel_text); -+ -+static const struct snd_kcontrol_new adc1_mux = -+SOC_DAPM_ENUM("ADC1 Mux", adc1in_sel_enum); -+ -+#define CX2072X_DAPM_SUPPLY_S(wname, wsubseq, wreg, wshift, wmask, won_val, \ -+ woff_val, wevent, wflags) \ -+ {.id = snd_soc_dapm_supply, .name = wname, .kcontrol_news = NULL, \ -+ .num_kcontrols = 0, .reg = wreg, .shift = wshift, .mask = wmask, \ -+ .on_val = won_val, .off_val = woff_val, \ -+ .subseq = wsubseq, .event = wevent, .event_flags = wflags} -+ -+#define CX2072X_DAPM_SWITCH(wname, wreg, wshift, wmask, won_val, woff_val, \ -+ wevent, wflags) \ -+ {.id = snd_soc_dapm_switch, .name = wname, .kcontrol_news = NULL, \ -+ .num_kcontrols = 0, .reg = wreg, .shift = wshift, .mask = wmask, \ -+ .on_val = won_val, .off_val = woff_val, \ -+ .event = wevent, .event_flags = wflags} -+ -+ -+#define CX2072X_DAPM_SWITCH(wname, wreg, wshift, wmask, won_val, woff_val, \ -+ wevent, wflags) \ -+ {.id = snd_soc_dapm_switch, .name = wname, .kcontrol_news = NULL, \ -+ .num_kcontrols = 0, .reg = wreg, .shift = wshift, .mask = wmask, \ -+ .on_val = won_val, .off_val = woff_val, \ -+ .event = wevent, .event_flags = wflags} -+ -+#define CX2072X_DAPM_REG_E(wid, wname, wreg, wshift, wmask, won_val, woff_val, \ -+ wevent, wflags) \ -+ {.id = wid, .name = wname, .kcontrol_news = NULL, .num_kcontrols = 0, \ -+ .reg = wreg, .shift = wshift, .mask = wmask, \ -+ .on_val = won_val, .off_val = woff_val, \ -+ .event = wevent, .event_flags = wflags} -+ -+static const struct snd_soc_dapm_widget cx2072x_dapm_widgets[] = { -+ /*Playback*/ -+ SND_SOC_DAPM_AIF_IN("In AIF", "Playback", 0, SND_SOC_NOPM, 0, 0), -+ -+ SND_SOC_DAPM_REG(snd_soc_dapm_dac, "DAC1", CX2072X_DAC1_POWER_STATE, -+ 0, 0xFFF, 0x00, 0x03), -+ -+ SND_SOC_DAPM_REG(snd_soc_dapm_dac, "DAC2", CX2072X_DAC2_POWER_STATE, -+ 0, 0xFFF, 0x00, 0x03), -+ -+ SND_SOC_DAPM_MUX("PortA Mux", SND_SOC_NOPM, 0, 0, &porta_mux), -+ SND_SOC_DAPM_MUX("PortG Mux", SND_SOC_NOPM, 0, 0, &portg_mux), -+ SND_SOC_DAPM_MUX("PortE Mux", SND_SOC_NOPM, 0, 0, &porte_mux), -+ -+ SND_SOC_DAPM_REG(snd_soc_dapm_switch, "PortA", -+ CX2072X_PORTA_POWER_STATE, 0, 0xFFF, 0x00, 0x03), -+ SND_SOC_DAPM_REG(snd_soc_dapm_switch, "PortG", -+ CX2072X_PORTG_POWER_STATE, 0, 0xFFF, 0x00, 0x03), -+ CX2072X_DAPM_SWITCH("PortG", CX2072X_PORTG_POWER_STATE, 0, 0xFF, -+ 0x00, 0x03, portg_power_ev, SND_SOC_DAPM_POST_PMU), -+ -+ CX2072X_DAPM_SUPPLY_S("AFG Power", 0, CX2072X_AFG_POWER_STATE, -+ 0, 0xFFF, 0x00, 0x03, afg_power_ev, -+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), -+ -+ SND_SOC_DAPM_OUTPUT("PORTA"), -+ SND_SOC_DAPM_OUTPUT("PORTG"), -+ SND_SOC_DAPM_OUTPUT("PORTE"), -+ -+ /*Capture*/ -+ SND_SOC_DAPM_AIF_OUT("Out AIF", "Capture", 0, SND_SOC_NOPM, 0, 0), -+ -+ CX2072X_DAPM_REG_E(snd_soc_dapm_adc, "ADC1", CX2072X_ADC1_POWER_STATE, -+ 0, 0xFF, 0x00, 0x03, adc1_power_ev, -+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), -+ -+ SND_SOC_DAPM_REG(snd_soc_dapm_adc, "ADC2", CX2072X_ADC2_POWER_STATE, -+ 0, 0xFF, 0x00, 0x03), -+ -+ SND_SOC_DAPM_MUX("ADC1 Mux", SND_SOC_NOPM, 0, 0, &adc1_mux), -+ -+ SND_SOC_DAPM_REG(snd_soc_dapm_switch, "PortB", -+ CX2072X_PORTB_POWER_STATE, 0, 0xFFF, 0x00, 0x03), -+ SND_SOC_DAPM_REG(snd_soc_dapm_switch, "PortC", -+ CX2072X_PORTC_POWER_STATE, 0, 0xFFF, 0x00, 0x03), -+ SND_SOC_DAPM_REG(snd_soc_dapm_switch, "PortD", -+ CX2072X_PORTD_POWER_STATE, 0, 0xFFF, 0x00, 0x03), -+ SND_SOC_DAPM_REG(snd_soc_dapm_switch, "PortE", -+ CX2072X_PORTE_POWER_STATE, 0, 0xFFF, 0x00, 0x03), -+ SND_SOC_DAPM_REG(snd_soc_dapm_switch, "Widget15", -+ CX2072X_MIXER_POWER_STATE, 0, 0xFFF, 0x00, 0x03), -+ -+ SND_SOC_DAPM_INPUT("PORTB"), -+ SND_SOC_DAPM_INPUT("PORTC"), -+ SND_SOC_DAPM_INPUT("PORTD"), -+ -+ SND_SOC_DAPM_MICBIAS("Headset Bias", CX2072X_ANALOG_TEST11, 1, 0), -+ SND_SOC_DAPM_MICBIAS("PortD Mic Bias", CX2072X_PORTD_PIN_CTRL, 2, 0), -+ SND_SOC_DAPM_MICBIAS("PortB Mic Bias", CX2072X_PORTB_PIN_CTRL, 2, 0), -+ -+}; -+ -+static const struct snd_soc_dapm_route cx2072x_intercon[] = { -+ -+ /* Playback */ -+ {"In AIF", NULL, "AFG Power"}, -+ {"DAC1", NULL, "In AIF"}, -+ {"DAC2", NULL, "In AIF"}, -+ {"PortA Mux", "DAC1 Switch", "DAC1"}, -+ {"PortA Mux", "DAC2 Switch", "DAC2"}, -+ {"PortG Mux", "DAC1 Switch", "DAC1"}, -+ {"PortG Mux", "DAC2 Switch", "DAC2"}, -+ {"PortE Mux", "DAC1 Switch", "DAC1"}, -+ {"PortE Mux", "DAC2 Switch", "DAC2"}, -+ {"Widget15", NULL, "DAC1"}, -+ {"Widget15", NULL, "DAC2"}, -+ {"PortA", NULL, "PortA Mux"}, -+ {"PortG", NULL, "PortG Mux"}, -+ {"PortE", NULL, "PortE Mux"}, -+ {"PORTA", NULL, "PortA"}, -+ {"PORTG", NULL, "PortG"}, -+ {"PORTE", NULL, "PortE"}, -+ -+ /* Capture */ -+ {"PORTD", NULL, "Headset Bias"}, -+ {"PortD", NULL, "PORTD"}, -+ {"PortC", NULL, "PORTC"}, -+ {"PortB", NULL, "PORTB"}, -+ {"ADC1 Mux", "PortD Switch", "PortD"}, -+ {"ADC1 Mux", "PortC Switch", "PortC"}, -+ {"ADC1 Mux", "PortB Switch", "PortB"}, -+ {"ADC1 Mux", "Widget15 Switch", "Widget15"}, -+ {"ADC1", NULL, "ADC1 Mux"}, -+ {"Out AIF", NULL, "ADC1"}, -+ {"Out AIF", NULL, "AFG Power"}, -+ -+}; -+ -+ -+static void cx2072x_sw_reset(struct cx2072x_priv *cx2072x) -+{ -+ -+ regmap_write(cx2072x->regmap, CX2072X_AFG_FUNCTION_RESET, 0x01); -+ regmap_write(cx2072x->regmap, CX2072X_AFG_FUNCTION_RESET, 0x01); -+} -+ -+static int cx2072x_init(struct snd_soc_codec *codec) -+{ -+ struct cx2072x_priv *cx2072x = get_cx2072x_priv(codec); -+ int ret; -+ -+ cx2072x_sw_reset(cx2072x); -+ -+ cx2072x->plbk_dsp_changed = true; -+ cx2072x->plbk_dsp_init = false; -+ -+ regmap_update_bits(cx2072x->regmap, CX2072X_DIGITAL_TEST15, -+ 0x00, 0x06); /* reduce the monitor time.*/ -+ -+ cx2072x_config_headset_det(cx2072x); -+ -+ regmap_update_bits(cx2072x->regmap, CX2072X_PORTC_PIN_CTRL, -+ 0x20, 0x20); /*reduce the monitor time*/ -+ -+ ret = regmap_register_patch(cx2072x->regmap, cx2072x_patch, -+ ARRAY_SIZE(cx2072x_patch)); -+ if (ret) -+ return ret; -+ -+ /*enable bclk and EAPD input*/ -+ if (cx2072x->rev_id == CX2072X_REV_A2) -+ regmap_update_bits(cx2072x->regmap, CX2072X_DIGITAL_BIOS_TEST2, -+ 0x84, 0xFF); -+ -+ return 0; -+} -+static int cx2072x_set_bias_level(struct snd_soc_codec *codec, -+enum snd_soc_bias_level level) -+{ -+ struct cx2072x_priv *cx2072x = get_cx2072x_priv(codec); -+ const enum snd_soc_bias_level old_level = -+ snd_soc_codec_get_bias_level(codec); -+ -+ switch (level) { -+ case SND_SOC_BIAS_ON: -+ dev_dbg(cx2072x->dev, "SND_SOC_BIAS_ON\n"); -+ /* Enable Headset Mic Bias */ -+ if (cx2072x->is_biason == 0) -+ cx2072x->is_biason = 1; -+ break; -+ case SND_SOC_BIAS_PREPARE: -+ dev_dbg(cx2072x->dev, "SND_SOC_BIAS_PREPARE\n"); -+ if (SND_SOC_BIAS_STANDBY == old_level) { -+ dev_dbg(cx2072x->dev, "SND_SOC_BIAS_STANDBY = > SND_SOC_BIAS_PREPARE\n"); -+#ifdef INTEL_MCLK_CONTROL -+ /*FIXME: added some delay to make sure the MCLK -+ * is stable before Codec is on. */ -+ mdelay(3); -+ dev_dbg(cx2072x->dev, "Turn on MCLK\n"); -+#endif -+ } -+ break; -+ case SND_SOC_BIAS_STANDBY: -+ dev_dbg(cx2072x->dev, "SND_SOC_BIAS_STANDBY\n"); -+ -+ if (SND_SOC_BIAS_OFF == old_level) { -+ dev_dbg(codec->dev, "Initialize codec\n"); -+#ifdef INTEL_MCLK_CONTROL -+ dev_dbg(cx2072x->dev, "Turn on MCLK\n"); -+ /*FIXME: added some delay to make sure the MCLK is -+ stable before Codec is on. */ -+ mdelay(3); -+#endif -+ cx2072x_init(codec); -+ } -+ /*power device into standby mode*/ -+#ifdef INTEL_MCLK_CONTROL -+ dev_dbg(cx2072x->dev, "Turn off MCLK\n"); -+#endif -+ break; -+ case SND_SOC_BIAS_OFF: -+ dev_dbg(cx2072x->dev, "SND_SOC_BIAS_OFF\n"); -+ /* Gracefully shutdwon codec*/ -+ -+ regmap_write(cx2072x->regmap, CX2072X_PORTA_POWER_STATE, 3); -+ regmap_write(cx2072x->regmap, CX2072X_PORTB_POWER_STATE, 3); -+ regmap_write(cx2072x->regmap, CX2072X_PORTC_POWER_STATE, 3); -+ regmap_write(cx2072x->regmap, CX2072X_PORTD_POWER_STATE, 3); -+ regmap_write(cx2072x->regmap, CX2072X_PORTG_POWER_STATE, 3); -+ regmap_write(cx2072x->regmap, CX2072X_ADC1_POWER_STATE, 3); -+ regmap_write(cx2072x->regmap, CX2072X_ADC2_POWER_STATE, 3); -+ regmap_write(cx2072x->regmap, CX2072X_DAC1_POWER_STATE, 3); -+ regmap_write(cx2072x->regmap, CX2072X_DAC2_POWER_STATE, 3); -+ regmap_write(cx2072x->regmap, CX2072X_AFG_POWER_STATE, 3); -+ regmap_update_bits(cx2072x->regmap, CX2072X_DIGITAL_BIOS_TEST0, -+ 0x10, 0x10); -+ /*Shutdown codec completely*/ -+ cx2072x_sw_reset(cx2072x); -+ break; -+ } -+ return 0; -+} -+ -+ -+static int cx2072x_probe(struct snd_soc_codec *codec) -+{ -+ struct cx2072x_priv *cx2072x = get_cx2072x_priv(codec); -+ int ret = 0; -+ unsigned int ven_id; -+ -+ cx2072x->codec = codec; -+ codec->control_data = cx2072x->regmap; -+ -+ dev_dbg(codec->dev, "codec version: 4.4.18\n"); -+ regmap_read(cx2072x->regmap, CX2072X_VENDOR_ID, &ven_id); -+ regmap_read(cx2072x->regmap, CX2072X_REVISION_ID, &cx2072x->rev_id); -+ dev_dbg(codec->dev, "codec version: %08x,%08x\n", -+ ven_id, cx2072x->rev_id); -+ -+#ifdef ENABLE_MIC_POP_WA -+ INIT_DELAYED_WORK(&codec->dapm.delayed_work, -+ cx2072x_anit_mic_pop_work); -+#endif -+ -+ /*power on device*/ -+ cx2072x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -+ -+ return ret; -+} -+ -+static int cx2072x_remove(struct snd_soc_codec *codec) -+{ -+ struct cx2072x_priv *cx2072x = get_cx2072x_priv(codec); -+ /*power off device*/ -+ cx2072x_set_bias_level(cx2072x->codec, SND_SOC_BIAS_OFF); -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+static int cx2072x_runtime_suspend(struct device *dev) -+{ -+ struct cx2072x_priv *cx2072x = dev_get_drvdata(dev); -+ -+ dev_dbg(cx2072x->codec->dev, "%s----%d\n", __func__, __LINE__); -+ cx2072x_set_bias_level(cx2072x->codec, SND_SOC_BIAS_OFF); -+ -+ return 0; -+} -+ -+static int cx2072x_runtime_resume(struct device *dev) -+{ -+ struct cx2072x_priv *cx2072x = dev_get_drvdata(dev); -+ -+ dev_dbg(cx2072x->codec->dev, "%s----%d\n", __func__, __LINE__); -+ cx2072x_set_bias_level(cx2072x->codec, SND_SOC_BIAS_STANDBY); -+ return 0; -+} -+#else -+#define cx2072x_suspend NULL -+#define cx2072x_resume NULL -+#endif -+ -+ -+ -+ -+static bool cx2072x_readable_register(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ -+ case CX2072X_VENDOR_ID: -+ case CX2072X_REVISION_ID: -+ case CX2072X_CURRENT_BCLK_FREQUENCY: -+ case CX2072X_AFG_POWER_STATE: -+ case CX2072X_UM_RESPONSE: -+ case CX2072X_GPIO_DATA: -+ case CX2072X_GPIO_ENABLE: -+ case CX2072X_GPIO_DIRECTION: -+ case CX2072X_GPIO_WAKE: -+ case CX2072X_GPIO_UM_ENABLE: -+ case CX2072X_GPIO_STICKY_MASK: -+ case CX2072X_DAC1_CONVERTER_FORMAT: -+ case CX2072X_DAC1_AMP_GAIN_RIGHT: -+ case CX2072X_DAC1_AMP_GAIN_LEFT: -+ case CX2072X_DAC1_POWER_STATE: -+ case CX2072X_DAC1_CONVERTER_STREAM_CHANNEL: -+ case CX2072X_DAC1_EAPD_ENABLE: -+ case CX2072X_DAC2_CONVERTER_FORMAT: -+ case CX2072X_DAC2_AMP_GAIN_RIGHT: -+ case CX2072X_DAC2_AMP_GAIN_LEFT: -+ case CX2072X_DAC2_POWER_STATE: -+ case CX2072X_DAC2_CONVERTER_STREAM_CHANNEL: -+ case CX2072X_ADC1_CONVERTER_FORMAT: -+ case CX2072X_ADC1_AMP_GAIN_RIGHT_0: -+ case CX2072X_ADC1_AMP_GAIN_LEFT_0: -+ case CX2072X_ADC1_AMP_GAIN_RIGHT_1: -+ case CX2072X_ADC1_AMP_GAIN_LEFT_1: -+ case CX2072X_ADC1_AMP_GAIN_RIGHT_2: -+ case CX2072X_ADC1_AMP_GAIN_LEFT_2: -+ case CX2072X_ADC1_AMP_GAIN_RIGHT_3: -+ case CX2072X_ADC1_AMP_GAIN_LEFT_3: -+ case CX2072X_ADC1_AMP_GAIN_RIGHT_4: -+ case CX2072X_ADC1_AMP_GAIN_LEFT_4: -+ case CX2072X_ADC1_AMP_GAIN_RIGHT_5: -+ case CX2072X_ADC1_AMP_GAIN_LEFT_5: -+ case CX2072X_ADC1_AMP_GAIN_RIGHT_6: -+ case CX2072X_ADC1_AMP_GAIN_LEFT_6: -+ case CX2072X_ADC1_CONNECTION_SELECT_CONTROL: -+ case CX2072X_ADC1_POWER_STATE: -+ case CX2072X_ADC1_CONVERTER_STREAM_CHANNEL: -+ case CX2072X_ADC2_CONVERTER_FORMAT: -+ case CX2072X_ADC2_AMP_GAIN_RIGHT_0: -+ case CX2072X_ADC2_AMP_GAIN_LEFT_0: -+ case CX2072X_ADC2_AMP_GAIN_RIGHT_1: -+ case CX2072X_ADC2_AMP_GAIN_LEFT_1: -+ case CX2072X_ADC2_AMP_GAIN_RIGHT_2: -+ case CX2072X_ADC2_AMP_GAIN_LEFT_2: -+ case CX2072X_ADC2_CONNECTION_SELECT_CONTROL: -+ case CX2072X_ADC2_POWER_STATE: -+ case CX2072X_ADC2_CONVERTER_STREAM_CHANNEL: -+ case CX2072X_PORTA_CONNECTION_SELECT_CTRL: -+ case CX2072X_PORTA_POWER_STATE: -+ case CX2072X_PORTA_PIN_CTRL: -+ case CX2072X_PORTA_UNSOLICITED_RESPONSE: -+ case CX2072X_PORTA_PIN_SENSE: -+ case CX2072X_PORTA_EAPD_BTL: -+ case CX2072X_PORTB_POWER_STATE: -+ case CX2072X_PORTB_PIN_CTRL: -+ case CX2072X_PORTB_UNSOLICITED_RESPONSE: -+ case CX2072X_PORTB_PIN_SENSE: -+ case CX2072X_PORTB_EAPD_BTL: -+ case CX2072X_PORTB_GAIN_RIGHT: -+ case CX2072X_PORTB_GAIN_LEFT: -+ case CX2072X_PORTC_POWER_STATE: -+ case CX2072X_PORTC_PIN_CTRL: -+ case CX2072X_PORTC_GAIN_RIGHT: -+ case CX2072X_PORTC_GAIN_LEFT: -+ case CX2072X_PORTD_POWER_STATE: -+ case CX2072X_PORTD_PIN_CTRL: -+ case CX2072X_PORTD_UNSOLICITED_RESPONSE: -+ case CX2072X_PORTD_PIN_SENSE: -+ case CX2072X_PORTD_GAIN_RIGHT: -+ case CX2072X_PORTD_GAIN_LEFT: -+ case CX2072X_PORTE_CONNECTION_SELECT_CTRL: -+ case CX2072X_PORTE_POWER_STATE: -+ case CX2072X_PORTE_PIN_CTRL: -+ case CX2072X_PORTE_UNSOLICITED_RESPONSE: -+ case CX2072X_PORTE_PIN_SENSE: -+ case CX2072X_PORTE_EAPD_BTL: -+ case CX2072X_PORTE_GAIN_RIGHT: -+ case CX2072X_PORTE_GAIN_LEFT: -+ case CX2072X_PORTF_POWER_STATE: -+ case CX2072X_PORTF_PIN_CTRL: -+ case CX2072X_PORTF_UNSOLICITED_RESPONSE: -+ case CX2072X_PORTF_PIN_SENSE: -+ case CX2072X_PORTF_GAIN_RIGHT: -+ case CX2072X_PORTF_GAIN_LEFT: -+ case CX2072X_PORTG_POWER_STATE: -+ case CX2072X_PORTG_PIN_CTRL: -+ case CX2072X_PORTG_CONNECTION_SELECT_CTRL: -+ case CX2072X_PORTG_EAPD_BTL: -+ case CX2072X_PORTM_POWER_STATE: -+ case CX2072X_PORTM_PIN_CTRL: -+ case CX2072X_PORTM_CONNECTION_SELECT_CTRL: -+ case CX2072X_PORTM_EAPD_BTL: -+ case CX2072X_MIXER_POWER_STATE: -+ case CX2072X_MIXER_GAIN_RIGHT_0: -+ case CX2072X_MIXER_GAIN_LEFT_0: -+ case CX2072X_MIXER_GAIN_RIGHT_1: -+ case CX2072X_MIXER_GAIN_LEFT_1: -+ case CX2072X_EQ_ENABLE_BYPASS: -+ case CX2072X_EQ_B0_COEFF: -+ case CX2072X_EQ_B1_COEFF: -+ case CX2072X_EQ_B2_COEFF: -+ case CX2072X_EQ_A1_COEFF: -+ case CX2072X_EQ_A2_COEFF: -+ case CX2072X_EQ_G_COEFF: -+ case CX2072X_SPKR_DRC_ENABLE_STEP: -+ case CX2072X_SPKR_DRC_CONTROL: -+ case CX2072X_SPKR_DRC_TEST: -+ case CX2072X_DIGITAL_BIOS_TEST0: -+ case CX2072X_DIGITAL_BIOS_TEST2: -+ case CX2072X_I2SPCM_CONTROL1: -+ case CX2072X_I2SPCM_CONTROL2: -+ case CX2072X_I2SPCM_CONTROL3: -+ case CX2072X_I2SPCM_CONTROL4: -+ case CX2072X_I2SPCM_CONTROL5: -+ case CX2072X_I2SPCM_CONTROL6: -+ case CX2072X_UM_INTERRUPT_CRTL_E: -+ case CX2072X_CODEC_TEST2: -+ case CX2072X_CODEC_TEST20: -+ case CX2072X_CODEC_TEST26: -+ case CX2072X_ANALOG_TEST4: -+ case CX2072X_ANALOG_TEST5: -+ case CX2072X_ANALOG_TEST6: -+ case CX2072X_ANALOG_TEST7: -+ case CX2072X_ANALOG_TEST8: -+ case CX2072X_ANALOG_TEST9: -+ case CX2072X_ANALOG_TEST10: -+ case CX2072X_ANALOG_TEST11: -+ case CX2072X_ANALOG_TEST12: -+ case CX2072X_ANALOG_TEST13: -+ case CX2072X_DIGITAL_TEST0: -+ case CX2072X_DIGITAL_TEST1: -+ case CX2072X_DIGITAL_TEST11: -+ case CX2072X_DIGITAL_TEST12: -+ case CX2072X_DIGITAL_TEST15: -+ case CX2072X_DIGITAL_TEST16: -+ case CX2072X_DIGITAL_TEST17: -+ case CX2072X_DIGITAL_TEST18: -+ case CX2072X_DIGITAL_TEST19: -+ case CX2072X_DIGITAL_TEST20: -+ return true; -+ default: -+ return false; -+ } -+} -+ -+static bool cx2072x_volatile_register(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case CX2072X_VENDOR_ID: -+ case CX2072X_REVISION_ID: -+ case CX2072X_UM_INTERRUPT_CRTL_E: -+ case CX2072X_DIGITAL_TEST11: -+ case CX2072X_PORTA_PIN_SENSE: -+ case CX2072X_PORTB_PIN_SENSE: -+ case CX2072X_PORTD_PIN_SENSE: -+ case CX2072X_PORTE_PIN_SENSE: -+ case CX2072X_PORTF_PIN_SENSE: -+ case CX2072X_EQ_G_COEFF: -+ case CX2072X_EQ_BAND: -+ return true; -+ default: -+ return false; -+ -+ } -+} -+ -+static struct snd_soc_codec_driver soc_codec_driver_cx2072x = { -+ .probe = cx2072x_probe, -+ .remove = cx2072x_remove, -+ .set_bias_level = cx2072x_set_bias_level, -+ .component_driver = { -+ .controls = cx2072x_snd_controls, -+ .num_controls = ARRAY_SIZE(cx2072x_snd_controls), -+ .dapm_widgets = cx2072x_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(cx2072x_dapm_widgets), -+ .dapm_routes = cx2072x_intercon, -+ .num_dapm_routes = ARRAY_SIZE(cx2072x_intercon), -+ } -+}; -+ -+/* -+ * DAI ops -+ */ -+static struct snd_soc_dai_ops cx2072x_dai_ops = { -+ .set_sysclk = cx2072x_set_dai_sysclk, -+ .set_fmt = cx2072x_set_dai_fmt, -+ .set_tdm_slot = cx2072x_set_tdm_slot, -+ .hw_params = cx2072x_hw_params, -+ .digital_mute = cx2072x_digital_mute, -+ .set_bclk_ratio = cx2072x_set_dai_bclk_ratio -+}; -+ -+/* -+ * DAI driver -+ */ -+static struct snd_soc_dai_driver soc_codec_cx2072x_dai = { -+ .name = "cx2072x-hifi", -+ .playback = { -+ .stream_name = "Playback", -+ .channels_min = 1, -+ .channels_max = 2, -+ .rates = CX2072X_RATES_DSP, -+ .formats = CX2072X_FORMATS, -+ }, -+ .capture = { -+ .stream_name = "Capture", -+ .channels_min = 1, -+ .channels_max = 2, -+ .rates = CX2072X_RATES_DSP, -+ .formats = CX2072X_FORMATS, -+ }, -+ .ops = &cx2072x_dai_ops, -+ .symmetric_rates = 1, -+}; -+EXPORT_SYMBOL_GPL(soc_codec_cx2072x_dai); -+ -+static const struct regmap_config cx2072x_regmap = { -+ .reg_bits = 16, -+ .val_bits = 32, -+ .max_register = CX2072X_REG_MAX, .reg_defaults = cx2072x_reg_defaults, -+ .num_reg_defaults = ARRAY_SIZE(cx2072x_reg_defaults), -+ .cache_type = REGCACHE_RBTREE, -+ -+ .readable_reg = cx2072x_readable_register, -+ .volatile_reg = cx2072x_volatile_register, -+ .reg_read = cx2072x_reg_read, -+ .reg_write = cx2072x_reg_write, -+}; -+ -+ -+static int cx2072x_i2c_probe(struct i2c_client *i2c, -+ const struct i2c_device_id *id) -+{ -+ int ret = -1; -+ struct cx2072x_priv *cx2072x; -+ -+ dev_dbg(&i2c->dev, "CX2072X codec driver i2c probe() is called\n"); -+ -+ cx2072x = (struct cx2072x_priv *)devm_kzalloc( -+ &i2c->dev, sizeof(struct cx2072x_priv), GFP_KERNEL); -+ if (cx2072x == NULL) { -+ dev_err(&i2c->dev, "Out of memory!\n"); -+ return -ENOMEM; -+ } -+ -+ mutex_init(&cx2072x->lock); -+ -+ cx2072x->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, -+ &cx2072x_regmap); -+ if (IS_ERR(&cx2072x->regmap)) { -+ ret = PTR_ERR(cx2072x->regmap); -+ dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); -+ return ret; -+ } -+ -+ i2c_set_clientdata(i2c, cx2072x); -+ -+ cx2072x->dev = &i2c->dev; -+ cx2072x->pll_changed = true; -+ cx2072x->i2spcm_changed = true; -+ -+ /* setts the frame size to -+ * Frame size = number of channel * sample width -+ */ -+ cx2072x->bclk_ratio = 0; -+ -+ ret = snd_soc_register_codec(cx2072x->dev, -+ &soc_codec_driver_cx2072x, &soc_codec_cx2072x_dai, -+ 1); -+ if (ret < 0) -+ dev_err(cx2072x->dev, -+ "Failed to register codec: %d\n", ret); -+ else -+ dev_dbg(cx2072x->dev, -+ "%s: Register codec.\n", __func__); -+ -+ return ret; -+} -+ -+static int cx2072x_i2c_remove(struct i2c_client *client) -+{ -+ snd_soc_unregister_codec(&client->dev); -+ return 0; -+} -+ -+static void cx2072x_i2c_shutdown(struct i2c_client *client) -+{ -+ struct cx2072x_priv *cx2072x = i2c_get_clientdata(client); -+ cx2072x_set_bias_level(cx2072x->codec, SND_SOC_BIAS_OFF); -+} -+ -+ -+const struct dev_pm_ops cx2072x_pm_ops = { -+ SET_RUNTIME_PM_OPS(cx2072x_runtime_suspend, cx2072x_runtime_resume, -+ NULL) -+}; -+static const struct i2c_device_id cx2072x_i2c_id[] = { -+ { "cx20721", 0 }, -+ { "cx20722", 0 }, -+ { "14F10720", 0 }, -+ {} -+}; -+MODULE_DEVICE_TABLE(i2c, cx2072x_i2c_id); -+ -+static const struct of_device_id cx2072x_of_match[] = { -+ { .compatible = "cnxt,cx20721", }, -+ { .compatible = "cnxt,cx20723", }, -+ { .compatible = "cnxt,cx7601", }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, cx2072x_of_match); -+#ifdef CONFIG_ACPI -+static struct acpi_device_id cx2072x_acpi_match[] = { -+ { "14F10720", 0 }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(acpi, cx2072x_acpi_match); -+#endif -+ -+static struct i2c_driver cx2072x_i2c_driver = { -+ .probe = cx2072x_i2c_probe, -+ .remove = cx2072x_i2c_remove, -+ .shutdown = cx2072x_i2c_shutdown, -+ .id_table = cx2072x_i2c_id, -+ .driver = { -+ .name = "cx2072x", -+ .owner = THIS_MODULE, -+ .of_match_table = cx2072x_of_match, -+#ifdef CONFIG_ACPI -+ .acpi_match_table = ACPI_PTR(cx2072x_acpi_match), -+#endif -+ .pm = &cx2072x_pm_ops, -+ }, -+}; -+ -+module_i2c_driver(cx2072x_i2c_driver); -+ -+MODULE_DESCRIPTION("ASoC cx2072x Codec Driver"); -+MODULE_AUTHOR("Simon Ho <simon.ho@conexant.com>"); -+MODULE_LICENSE("GPL"); -+ -diff --git a/sound/soc/codecs/cx2072x.h b/sound/soc/codecs/cx2072x.h -new file mode 100644 -index 000000000000..67b90c184c6b ---- /dev/null -+++ b/sound/soc/codecs/cx2072x.h -@@ -0,0 +1,339 @@ -+/* -+ * ALSA SoC CX2072x Solana codec driver -+ * -+ * Copyright: (C) 2016 Conexant Systems, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ ************************************************************************/ -+ -+#define NUM_OF_DAI 1 -+#define CX2072X_MCLK_PLL 1 -+#define CX2072X_MCLK_EXTERNAL_PLL 1 -+#define CX2072X_MCLK_INTERNAL_OSC 2 -+ -+/*#define CX2072X_RATES SNDRV_PCM_RATE_8000_192000*/ -+#define CX2072X_RATES_DSP SNDRV_PCM_RATE_48000 -+ -+#define CX2072X_REG_MAX 0x8a3c -+#define AUDDRV_VERSION(major0, major1, minor, build) \ -+ ((major0)<<24 | (major1)<<16 | (minor)<<8 | (build)) -+ -+#define CX2072X_VENDOR_ID 0x0200 -+#define CX2072X_REVISION_ID 0x0208 -+#define CX2072X_CURRENT_BCLK_FREQUENCY 0x00dc -+#define CX2072X_AFG_POWER_STATE 0x0414 -+#define CX2072X_UM_RESPONSE 0x0420 -+#define CX2072X_GPIO_DATA 0x0454 -+#define CX2072X_GPIO_ENABLE 0x0458 -+#define CX2072X_GPIO_DIRECTION 0x045c -+#define CX2072X_GPIO_WAKE 0x0460 -+#define CX2072X_GPIO_UM_ENABLE 0x0464 -+#define CX2072X_GPIO_STICKY_MASK 0x0468 -+#define CX2072X_AFG_FUNCTION_RESET 0x07FC -+#define CX2072X_DAC1_CONVERTER_FORMAT 0x43c8 -+#define CX2072X_DAC1_AMP_GAIN_RIGHT 0x41c0 -+#define CX2072X_DAC1_AMP_GAIN_LEFT 0x41e0 -+#define CX2072X_DAC1_POWER_STATE 0x4014 -+#define CX2072X_DAC1_CONVERTER_STREAM_CHANNEL 0x4018 -+#define CX2072X_DAC1_EAPD_ENABLE 0x4030 -+#define CX2072X_DAC2_CONVERTER_FORMAT 0x47c8 -+#define CX2072X_DAC2_AMP_GAIN_RIGHT 0x45c0 -+#define CX2072X_DAC2_AMP_GAIN_LEFT 0x45e0 -+#define CX2072X_DAC2_POWER_STATE 0x4414 -+#define CX2072X_DAC2_CONVERTER_STREAM_CHANNEL 0x4418 -+#define CX2072X_ADC1_CONVERTER_FORMAT 0x4fc8 -+#define CX2072X_ADC1_AMP_GAIN_RIGHT_0 0x4d80 -+#define CX2072X_ADC1_AMP_GAIN_LEFT_0 0x4da0 -+#define CX2072X_ADC1_AMP_GAIN_RIGHT_1 0x4d84 -+#define CX2072X_ADC1_AMP_GAIN_LEFT_1 0x4da4 -+#define CX2072X_ADC1_AMP_GAIN_RIGHT_2 0x4d88 -+#define CX2072X_ADC1_AMP_GAIN_LEFT_2 0x4da8 -+#define CX2072X_ADC1_AMP_GAIN_RIGHT_3 0x4d8c -+#define CX2072X_ADC1_AMP_GAIN_LEFT_3 0x4dac -+#define CX2072X_ADC1_AMP_GAIN_RIGHT_4 0x4d90 -+#define CX2072X_ADC1_AMP_GAIN_LEFT_4 0x4db0 -+#define CX2072X_ADC1_AMP_GAIN_RIGHT_5 0x4d94 -+#define CX2072X_ADC1_AMP_GAIN_LEFT_5 0x4db4 -+#define CX2072X_ADC1_AMP_GAIN_RIGHT_6 0x4d98 -+#define CX2072X_ADC1_AMP_GAIN_LEFT_6 0x4db8 -+#define CX2072X_ADC1_CONNECTION_SELECT_CONTROL 0x4c04 -+#define CX2072X_ADC1_POWER_STATE 0x4c14 -+#define CX2072X_ADC1_CONVERTER_STREAM_CHANNEL 0x4c18 -+#define CX2072X_ADC2_CONVERTER_FORMAT 0x53c8 -+#define CX2072X_ADC2_AMP_GAIN_RIGHT_0 0x5180 -+#define CX2072X_ADC2_AMP_GAIN_LEFT_0 0x51a0 -+#define CX2072X_ADC2_AMP_GAIN_RIGHT_1 0x5184 -+#define CX2072X_ADC2_AMP_GAIN_LEFT_1 0x51a4 -+#define CX2072X_ADC2_AMP_GAIN_RIGHT_2 0x5188 -+#define CX2072X_ADC2_AMP_GAIN_LEFT_2 0x51a8 -+#define CX2072X_ADC2_CONNECTION_SELECT_CONTROL 0x5004 -+#define CX2072X_ADC2_POWER_STATE 0x5014 -+#define CX2072X_ADC2_CONVERTER_STREAM_CHANNEL 0x5018 -+#define CX2072X_PORTA_CONNECTION_SELECT_CTRL 0x5804 -+#define CX2072X_PORTA_POWER_STATE 0x5814 -+#define CX2072X_PORTA_PIN_CTRL 0x581c -+#define CX2072X_PORTA_UNSOLICITED_RESPONSE 0x5820 -+#define CX2072X_PORTA_PIN_SENSE 0x5824 -+#define CX2072X_PORTA_EAPD_BTL 0x5830 -+#define CX2072X_PORTB_POWER_STATE 0x6014 -+#define CX2072X_PORTB_PIN_CTRL 0x601c -+#define CX2072X_PORTB_UNSOLICITED_RESPONSE 0x6020 -+#define CX2072X_PORTB_PIN_SENSE 0x6024 -+#define CX2072X_PORTB_EAPD_BTL 0x6030 -+#define CX2072X_PORTB_GAIN_RIGHT 0x6180 -+#define CX2072X_PORTB_GAIN_LEFT 0x61a0 -+#define CX2072X_PORTC_POWER_STATE 0x6814 -+#define CX2072X_PORTC_PIN_CTRL 0x681c -+#define CX2072X_PORTC_GAIN_RIGHT 0x6980 -+#define CX2072X_PORTC_GAIN_LEFT 0x69a0 -+#define CX2072X_PORTD_POWER_STATE 0x6414 -+#define CX2072X_PORTD_PIN_CTRL 0x641c -+#define CX2072X_PORTD_UNSOLICITED_RESPONSE 0x6420 -+#define CX2072X_PORTD_PIN_SENSE 0x6424 -+#define CX2072X_PORTD_GAIN_RIGHT 0x6580 -+#define CX2072X_PORTD_GAIN_LEFT 0x65a0 -+#define CX2072X_PORTE_CONNECTION_SELECT_CTRL 0x7404 -+#define CX2072X_PORTE_POWER_STATE 0x7414 -+#define CX2072X_PORTE_PIN_CTRL 0x741c -+#define CX2072X_PORTE_UNSOLICITED_RESPONSE 0x7420 -+#define CX2072X_PORTE_PIN_SENSE 0x7424 -+#define CX2072X_PORTE_EAPD_BTL 0x7430 -+#define CX2072X_PORTE_GAIN_RIGHT 0x7580 -+#define CX2072X_PORTE_GAIN_LEFT 0x75a0 -+#define CX2072X_PORTF_POWER_STATE 0x7814 -+#define CX2072X_PORTF_PIN_CTRL 0x781c -+#define CX2072X_PORTF_UNSOLICITED_RESPONSE 0x7820 -+#define CX2072X_PORTF_PIN_SENSE 0x7824 -+#define CX2072X_PORTF_GAIN_RIGHT 0x7980 -+#define CX2072X_PORTF_GAIN_LEFT 0x79a0 -+#define CX2072X_PORTG_POWER_STATE 0x5c14 -+#define CX2072X_PORTG_PIN_CTRL 0x5c1c -+#define CX2072X_PORTG_CONNECTION_SELECT_CTRL 0x5c04 -+#define CX2072X_PORTG_EAPD_BTL 0x5c30 -+#define CX2072X_PORTM_POWER_STATE 0x8814 -+#define CX2072X_PORTM_PIN_CTRL 0x881c -+#define CX2072X_PORTM_CONNECTION_SELECT_CTRL 0x8804 -+#define CX2072X_PORTM_EAPD_BTL 0x8830 -+#define CX2072X_MIXER_POWER_STATE 0x5414 -+#define CX2072X_MIXER_GAIN_RIGHT_0 0x5580 -+#define CX2072X_MIXER_GAIN_LEFT_0 0x55a0 -+#define CX2072X_MIXER_GAIN_RIGHT_1 0x5584 -+#define CX2072X_MIXER_GAIN_LEFT_1 0x55a4 -+#define CX2072X_EQ_ENABLE_BYPASS 0x6d00 -+#define CX2072X_EQ_B0_COEFF 0x6d02 -+#define CX2072X_EQ_B1_COEFF 0x6d04 -+#define CX2072X_EQ_B2_COEFF 0x6d06 -+#define CX2072X_EQ_A1_COEFF 0x6d08 -+#define CX2072X_EQ_A2_COEFF 0x6d0a -+#define CX2072X_EQ_G_COEFF 0x6d0c -+#define CX2072X_EQ_BAND 0x6d0d -+#define CX2072X_SPKR_DRC_ENABLE_STEP 0x6d10 -+#define CX2072X_SPKR_DRC_CONTROL 0x6d14 -+#define CX2072X_SPKR_DRC_TEST 0X6D18 -+#define CX2072X_DIGITAL_BIOS_TEST0 0x6d80 -+#define CX2072X_DIGITAL_BIOS_TEST2 0x6d84 -+#define CX2072X_I2SPCM_CONTROL1 0x6e00 -+#define CX2072X_I2SPCM_CONTROL2 0x6e04 -+#define CX2072X_I2SPCM_CONTROL3 0x6e08 -+#define CX2072X_I2SPCM_CONTROL4 0x6e0c -+#define CX2072X_I2SPCM_CONTROL5 0x6e10 -+#define CX2072X_I2SPCM_CONTROL6 0x6e18 -+#define CX2072X_UM_INTERRUPT_CRTL_E 0x6e14 -+#define CX2072X_CODEC_TEST2 0x7108 -+#define CX2072X_CODEC_TEST20 0x7310 -+#define CX2072X_CODEC_TEST26 0x7328 -+#define CX2072X_ANALOG_TEST3 0x718c -+#define CX2072X_ANALOG_TEST4 0x7190 -+#define CX2072X_ANALOG_TEST5 0x7194 -+#define CX2072X_ANALOG_TEST6 0x7198 -+#define CX2072X_ANALOG_TEST7 0x719c -+#define CX2072X_ANALOG_TEST8 0x71a0 -+#define CX2072X_ANALOG_TEST9 0x71a4 -+#define CX2072X_ANALOG_TEST10 0x71a8 -+#define CX2072X_ANALOG_TEST11 0x71ac -+#define CX2072X_ANALOG_TEST12 0x71b0 -+#define CX2072X_ANALOG_TEST13 0x71b4 -+#define CX2072X_DIGITAL_TEST0 0x7200 -+#define CX2072X_DIGITAL_TEST1 0x7204 -+#define CX2072X_DIGITAL_TEST11 0x722c -+#define CX2072X_DIGITAL_TEST12 0x7230 -+#define CX2072X_DIGITAL_TEST15 0x723c -+#define CX2072X_DIGITAL_TEST16 0x7080 -+#define CX2072X_DIGITAL_TEST17 0x7084 -+#define CX2072X_DIGITAL_TEST18 0x7088 -+#define CX2072X_DIGITAL_TEST19 0x708c -+#define CX2072X_DIGITAL_TEST20 0x7090 -+ -+#define INVALID_GPIO -1 -+#define MAX_EQ_BAND 7 -+#define MAC_EQ_COEFF 11 -+#define MAX_DRC_REGS 9 -+#define MIC_EQ_COEFF 10 -+/* -+static unsigned char cx2072x_eq_coeff_flat[MAX_EQ_BAND][MAC_EQ_COEFF] = { -+ {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, -+ {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, -+ {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, -+ {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, -+ {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, -+ {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, -+ {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}, -+}; -+*/ -+/* -+static unsigned char cx2072x_miceq_coeff_array[][MIC_EQ_COEFF] = { -+ {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, -+ {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, -+ {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, -+ {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, -+ {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, -+ {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, -+ {0x42, 0x17, 0x85, 0x2e, 0x42, 0x17, 0x0a, 0x5d, 0xed, 0xc5}, -+}; -+*/ -+ -+ -+enum cx2072x_jack_types { -+ CX_JACK_NONE = 0x0000, -+ CX_JACK_HEADPHONE = 0x0001, -+ CX_JACK_APPLE_HEADSET = 0x0002, -+ CX_JACK_NOKIE_HEADSET = 0x0003, -+ -+}; -+ -+int cx2072x_hs_jack_report(struct snd_soc_codec *codec); -+ -+typedef enum _REG_SAMPLE_SIZE{ -+ SAMPLE_SIZE_8_BITS = 0 , -+ SAMPLE_SIZE_16_BITS = 1 , -+ SAMPLE_SIZE_24_BITS = 2 , -+ SAMPLE_SIZE_RESERVED = 3 -+}REG_SAMPLE_SIZE; -+ -+typedef union _REG_I2SPCM_CTRL_REG1{ -+ struct { -+ u32 rx_data_one_line :1; -+ u32 rx_ws_pol :1; -+ u32 rx_ws_wid :7; -+ u32 rx_frm_len :5; -+ u32 rx_sa_size :2; -+ u32 tx_data_one_line :1; -+ u32 tx_ws_pol :1; -+ u32 tx_ws_wid :7; -+ u32 tx_frm_len :5; -+ u32 tx_sa_size :2; -+ }r; -+ u32 ulVal; -+}REG_I2SPCM_CTRL_REG1; -+ -+ -+typedef union _REG_I2SPCM_CTRL_REG2{ -+ struct { -+ u32 tx_en_ch1 :1; -+ u32 tx_en_ch2 :1; -+ u32 tx_en_ch3 :1; -+ u32 tx_en_ch4 :1; -+ u32 tx_en_ch5 :1; -+ u32 tx_en_ch6 :1; -+ u32 tx_slot_1 :5; -+ u32 tx_slot_2 :5; -+ u32 tx_slot_3 :5; -+ u32 tx_slot_4 :5; -+ u32 res :1; -+ u32 tx_data_neg_bclk :1; -+ u32 tx_master :1; -+ u32 tx_tri_n :1; -+ u32 tx_endian_sel :1; -+ u32 tx_dstart_dly :1; -+ }r; -+ u32 ulVal; -+}REG_I2SPCM_CTRL_REG2; -+ -+typedef union _REG_I2SPCM_CTRL_REG3{ -+ struct { -+ u32 rx_en_ch1 :1; -+ u32 rx_en_ch2 :1; -+ u32 rx_en_ch3 :1; -+ u32 rx_en_ch4 :1; -+ u32 rx_en_ch5 :1; -+ u32 rx_en_ch6 :1; -+ u32 rx_slot_1 :5; -+ u32 rx_slot_2 :5; -+ u32 rx_slot_3 :5; -+ u32 rx_slot_4 :5; -+ u32 res :1; -+ u32 rx_data_neg_bclk :1; -+ u32 rx_master :1; -+ u32 rx_tri_n :1; -+ u32 rx_endian_sel :1; -+ u32 rx_dstart_dly :1; -+ }r; -+ u32 ulVal; -+}REG_I2SPCM_CTRL_REG3; -+ -+ -+typedef union _REG_I2SPCM_CTRL_REG4{ -+ struct { -+ u32 rx_mute :1; -+ u32 tx_mute :1; -+ u32 reserved :1; -+ u32 dac_34_independent :1; -+ u32 dac_bclk_lrck_share:1; -+ u32 bclk_lrck_share_en :1; -+ u32 reserved2 :2; -+ u32 rx_last_dac_ch_en :1; -+ u32 rx_last_dac_ch :3; -+ u32 tx_last_adc_ch_en :1; -+ u32 tx_last_adc_ch :3; -+ u32 rx_slot_5 :5; -+ u32 rx_slot_6 :5; -+ u32 reserved3 :6; -+ }r; -+ u32 ulVal; -+}REG_I2SPCM_CTRL_REG4; -+ -+ -+typedef union _REG_I2SPCM_CTRL_REG5{ -+ struct { -+ u32 tx_slot_5 :5; -+ u32 reserved :3; -+ u32 tx_slot_6 :5; -+ u32 reserved2 :3; -+ u32 reserved3 :8; -+ u32 i2s_pcm_clk_div :7; -+ u32 i2s_pcm_clk_div_chan_en :1; -+ }r; -+ u32 ulVal; -+}REG_I2SPCM_CTRL_REG5; -+ -+typedef union _REG_I2SPCM_CTRL_REG6{ -+ struct { -+ u32 reserved :5; -+ u32 rx_pause_cycles :3; -+ u32 rx_pause_start_pos :8; -+ u32 reserved2 :5; -+ u32 tx_pause_cycles :3; -+ u32 tx_pause_start_pos :8; -+ }r; -+ u32 ulVal; -+}REG_I2SPCM_CTRL_REG6; -+ -+typedef union _REG_DIGITAL_BIOS_TEST2{ -+ struct { -+ u32 pull_down_eapd :2; -+ u32 input_en_eapd_pad :1; -+ u32 push_pull_mode :1; -+ u32 eapd_pad_output_driver :2; -+ u32 pll_source :1; -+ u32 i2s_bclk_en :1; -+ u32 i2s_bclk_invert :1; -+ u32 pll_ref_clock :1; -+ u32 class_d_sheild_clk:1; -+ u32 audio_pll_bypass_mode:1; -+ u32 reserved :4; -+ }r; -+ u32 ulVal; -+}REG_DIGITAL_BIOS_TEST2; -diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c -index 10c2a564a715..77bde13147bd 100644 ---- a/sound/soc/codecs/rt5645.c -+++ b/sound/soc/codecs/rt5645.c -@@ -3545,8 +3545,10 @@ MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id); - #ifdef CONFIG_ACPI - static const struct acpi_device_id rt5645_acpi_match[] = { - { "10EC5645", 0 }, -+ { "10EC5648", 0 }, - { "10EC5650", 0 }, - { "10EC5640", 0 }, -+ { "10EC3270", 0 }, - {}, - }; - MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match); -@@ -3658,8 +3660,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, - GPIOD_IN); - - if (IS_ERR(rt5645->gpiod_hp_det)) { -- dev_err(&i2c->dev, "failed to initialize gpiod\n"); -- return PTR_ERR(rt5645->gpiod_hp_det); -+ dev_info(&i2c->dev, "failed to initialize gpiod\n"); - } - - for (i = 0; i < ARRAY_SIZE(rt5645->supplies); i++) -diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c -index 49caf1393aeb..fdc14e50d3b9 100644 ---- a/sound/soc/codecs/rt5670.c -+++ b/sound/soc/codecs/rt5670.c -@@ -2813,6 +2813,8 @@ MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id); - #ifdef CONFIG_ACPI - static const struct acpi_device_id rt5670_acpi_match[] = { - { "10EC5670", 0}, -+ { "10EC5672", 0}, -+ { "10EC5640", 0}, /* quirk */ - { }, - }; - MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match); -diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c -index be1a64bfd320..a1b4e14b347a 100644 ---- a/sound/soc/codecs/tlv320aic31xx.c -+++ b/sound/soc/codecs/tlv320aic31xx.c -@@ -192,46 +192,68 @@ static const struct aic31xx_rate_divs aic31xx_divs[] = { - {12000000, 8000, 8, 1920, 128, 48, 2, 128, 48, 2}, - {12000000, 8000, 8, 1920, 128, 32, 3, 128, 32, 3}, - {12500000, 8000, 7, 8643, 128, 48, 2, 128, 48, 2}, -+ {19200000, 8000, 5, 1200, 128, 48, 2, 128, 48, 2}, -+ {19200000, 8000, 5, 1200, 128, 32, 3, 128, 32, 3}, - /* 11.025k rate */ - {12000000, 11025, 7, 5264, 128, 32, 2, 128, 32, 2}, - {12000000, 11025, 8, 4672, 128, 24, 3, 128, 24, 3}, - {12500000, 11025, 7, 2253, 128, 32, 2, 128, 32, 2}, -+ {19200000, 11025, 4, 7040, 128, 24, 2, 128, 32, 2}, -+ {19200000, 11025, 5, 2920, 128, 32, 3, 128, 24, 3}, - /* 16k rate */ - {12000000, 16000, 8, 1920, 128, 24, 2, 128, 24, 2}, - {12000000, 16000, 8, 1920, 128, 16, 3, 128, 16, 3}, - {12500000, 16000, 7, 8643, 128, 24, 2, 128, 24, 2}, -+ {19200000, 16000, 5, 1200, 128, 24, 2, 128, 24, 2}, -+ {19200000, 16000, 5, 1200, 128, 16, 3, 128, 16, 3}, - /* 22.05k rate */ - {12000000, 22050, 7, 5264, 128, 16, 2, 128, 16, 2}, - {12000000, 22050, 8, 4672, 128, 12, 3, 128, 12, 3}, - {12500000, 22050, 7, 2253, 128, 16, 2, 128, 16, 2}, -+ {19200000, 22050, 4, 7040, 128, 16, 2, 128, 16, 2}, -+ {19200000, 22050, 5, 2920, 128, 12, 3, 128, 12, 3}, - /* 32k rate */ - {12000000, 32000, 8, 1920, 128, 12, 2, 128, 12, 2}, - {12000000, 32000, 8, 1920, 128, 8, 3, 128, 8, 3}, - {12500000, 32000, 7, 8643, 128, 12, 2, 128, 12, 2}, -+ {19200000, 32000, 1, 0000, 32, 1, 2, 32, 1, 2}, -+ {19200000, 32000, 5, 1200, 128, 8, 3, 128, 8, 3}, - /* 44.1k rate */ - {12000000, 44100, 7, 5264, 128, 8, 2, 128, 8, 2}, - {12000000, 44100, 8, 4672, 128, 6, 3, 128, 6, 3}, - {12500000, 44100, 7, 2253, 128, 8, 2, 128, 8, 2}, -+ {19200000, 44100, 4, 7040, 128, 8, 2, 128, 8, 2}, -+ {19200000, 44100, 5, 2920, 128, 6, 3, 128, 6, 3}, - /* 48k rate */ - {12000000, 48000, 8, 1920, 128, 8, 2, 128, 8, 2}, - {12000000, 48000, 7, 6800, 96, 5, 4, 96, 5, 4}, - {12500000, 48000, 7, 8643, 128, 8, 2, 128, 8, 2}, -+ {19200000, 48000, 5, 1200, 128, 8, 2, 128, 8, 2}, -+ {19200000, 48000, 4, 8000, 96, 5, 4, 96, 5, 4}, - /* 88.2k rate */ - {12000000, 88200, 7, 5264, 64, 8, 2, 64, 8, 2}, - {12000000, 88200, 8, 4672, 64, 6, 3, 64, 6, 3}, - {12500000, 88200, 7, 2253, 64, 8, 2, 64, 8, 2}, -+ {19200000, 88200, 4, 7040, 64, 8, 2, 64, 8, 2}, -+ {19200000, 88200, 5, 2920, 64, 6, 3, 64, 6, 3}, - /* 96k rate */ - {12000000, 96000, 8, 1920, 64, 8, 2, 64, 8, 2}, - {12000000, 96000, 7, 6800, 48, 5, 4, 48, 5, 4}, - {12500000, 96000, 7, 8643, 64, 8, 2, 64, 8, 2}, -+ {19200000, 96000, 5, 1200, 64, 8, 2, 64, 8, 2}, -+ {19200000, 96000, 4, 8000, 48, 5, 4, 48, 5, 4}, - /* 176.4k rate */ - {12000000, 176400, 7, 5264, 32, 8, 2, 32, 8, 2}, - {12000000, 176400, 8, 4672, 32, 6, 3, 32, 6, 3}, - {12500000, 176400, 7, 2253, 32, 8, 2, 32, 8, 2}, -+ {19200000, 176400, 4, 7040, 32, 8, 2, 32, 8, 2}, -+ {19200000, 176400, 5, 2920, 32, 6, 3, 32, 6, 3}, - /* 192k rate */ - {12000000, 192000, 8, 1920, 32, 8, 2, 32, 8, 2}, - {12000000, 192000, 7, 6800, 24, 5, 4, 24, 5, 4}, - {12500000, 192000, 7, 8643, 32, 8, 2, 32, 8, 2}, -+ {19200000, 192000, 5, 1200, 32, 8, 2, 32, 8, 2}, -+ {19200000, 192000, 4, 8000, 24, 5, 4, 24, 5, 4}, - }; - - static const char * const ldac_in_text[] = { -diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig -index fd5d1e091038..76de542c66b7 100644 ---- a/sound/soc/intel/Kconfig -+++ b/sound/soc/intel/Kconfig -@@ -172,6 +172,32 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH - Say Y if you have such a device. - If unsure select "N". - -+config SND_SOC_INTEL_BYTCR_AIC3100_MACH -+ tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with TLV320AIC31XX codec" -+ depends on X86 && I2C && ACPI -+ select SND_SOC_TLV320AIC31XX -+ select SND_SST_MFLD_PLATFORM -+ select SND_SST_IPC_ACPI -+ select SND_SOC_INTEL_SST_MATCH if ACPI -+ help -+ This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR -+ platforms with TLV320AIC31XX audio codec. -+ Say Y if you have such a device. -+ If unsure select "N". -+ -+config SND_SOC_INTEL_CHT_CX2072X_MACH -+ tristate "ASoC Audio driver for Intel Baytrail and Cherrytrail with CX2072X codec" -+ depends on X86_INTEL_LPSS && I2C && ACPI -+ select SND_SOC_CX2072X -+ select SND_SST_MFLD_PLATFORM -+ select SND_SST_IPC_ACPI -+ select SND_SOC_INTEL_SST_MATCH if ACPI -+ help -+ This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell -+ platforms with Conexant CX2072X audio codec. -+ Say Y if you have such a device. -+ If unsure select "N". -+ - config SND_SOC_INTEL_CHT_BSW_RT5672_MACH - tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" - depends on X86_INTEL_LPSS && I2C && ACPI -diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c -index 0a88537ca58a..4e230282205d 100644 ---- a/sound/soc/intel/atom/sst/sst_acpi.c -+++ b/sound/soc/intel/atom/sst/sst_acpi.c -@@ -400,6 +400,7 @@ static int sst_acpi_remove(struct platform_device *pdev) - static unsigned long cht_machine_id; - - #define CHT_SURFACE_MACH 1 -+#define BYT_THINKPAD_10 2 - - static int cht_surface_quirk_cb(const struct dmi_system_id *id) - { -@@ -407,6 +408,23 @@ static int cht_surface_quirk_cb(const struct dmi_system_id *id) - return 1; - } - -+static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id) -+{ -+ cht_machine_id = BYT_THINKPAD_10; -+ return 1; -+} -+ -+ -+static const struct dmi_system_id byt_table[] = { -+ { -+ .callback = byt_thinkpad10_quirk_cb, -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "20C3001VHH"), -+ }, -+ }, -+ { } -+}; - - static const struct dmi_system_id cht_table[] = { - { -@@ -424,6 +442,10 @@ static struct sst_acpi_mach cht_surface_mach = { - "10EC5640", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, - &chv_platform_data }; - -+static struct sst_acpi_mach byt_thinkpad_10 = { -+ "10EC5640", "cht-bsw-rt5672", "intel/fw_sst_0f28.bin", "cht-bsw", NULL, -+ &byt_rvp_platform_data }; -+ - static struct sst_acpi_mach *cht_quirk(void *arg) - { - struct sst_acpi_mach *mach = arg; -@@ -436,8 +458,21 @@ static struct sst_acpi_mach *cht_quirk(void *arg) - return mach; - } - -+static struct sst_acpi_mach *byt_quirk(void *arg) -+{ -+ struct sst_acpi_mach *mach = arg; -+ -+ dmi_check_system(byt_table); -+ -+ if (cht_machine_id == BYT_THINKPAD_10) -+ return &byt_thinkpad_10; -+ else -+ return mach; -+} -+ -+ - static struct sst_acpi_mach sst_acpi_bytcr[] = { -- {"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, -+ {"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", byt_quirk, - &byt_rvp_platform_data }, - {"10EC5642", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, - &byt_rvp_platform_data }, -@@ -445,6 +480,16 @@ static struct sst_acpi_mach sst_acpi_bytcr[] = { - &byt_rvp_platform_data }, - {"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL, - &byt_rvp_platform_data }, -+ /* some Baytrail platforms rely on RT5645, use CHT machine driver */ -+ {"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL, -+ &byt_rvp_platform_data }, -+ {"10EC5648", "cht-bsw-rt5645", "intel/fw_sst_0f28.bin", "cht-bsw", NULL, -+ &byt_rvp_platform_data }, -+ /* use CHT driver to Baytrail Chromebooks */ -+ {"193C9890", "cht-bsw-max98090", "intel/fw_sst_0f28.bin", "cht-bsw", NULL, -+ &byt_rvp_platform_data }, -+ {"14F10720", "cht-cx2072x", "intel/fw_sst_0f28.bin", "cht-bsw", NULL, -+ &byt_rvp_platform_data }, - {}, - }; - -@@ -456,7 +501,9 @@ static struct sst_acpi_mach sst_acpi_chv[] = { - &chv_platform_data }, - {"10EC5650", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, - &chv_platform_data }, -- {"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, -+ {"10EC3270", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, -+ &chv_platform_data }, -+ {"14F10720", "cht-cx2072x", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, - &chv_platform_data }, - /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ - {"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk, -diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile -index 5639f10774e6..68dd93d91de9 100644 ---- a/sound/soc/intel/boards/Makefile -+++ b/sound/soc/intel/boards/Makefile -@@ -7,6 +7,8 @@ snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o - snd-soc-sst-bxt-rt298-objs := bxt_rt298.o - snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o - snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o -+snd-soc-sst-bytcr-aic3100-objs := bytcr_aic3100.o -+snd-soc-sst-cht-cx2072x-objs := cht_cx2072x.o - snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o - snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o - snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o -@@ -23,6 +25,8 @@ obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o - obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH) += snd-soc-sst-bdw-rt5677-mach.o - obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o - obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o -+obj-$(CONFIG_SND_SOC_INTEL_BYTCR_AIC3100_MACH) += snd-soc-sst-bytcr-aic3100.o -+obj-$(CONFIG_SND_SOC_INTEL_CHT_CX2072X_MACH) += snd-soc-sst-cht-cx2072x.o - obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o - obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o - obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o -diff --git a/sound/soc/intel/boards/bytcr_aic3100.c b/sound/soc/intel/boards/bytcr_aic3100.c -new file mode 100644 -index 000000000000..f6a45f685933 ---- /dev/null -+++ b/sound/soc/intel/boards/bytcr_aic3100.c -@@ -0,0 +1,608 @@ -+/* -+ * bytcr_aic3100.c - ASoc Machine driver for Intel Byt CR platform -+ * -+ * Copyright (C) 2016 Intel Corporation -+ * -+ * Author: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> -+ * Based on earlier 3.14 work by Praveen Diwakar and Gurudatta Bhakte -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * 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 <linux/init.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/acpi.h> -+#include <linux/device.h> -+#include <linux/dmi.h> -+#include <linux/slab.h> -+#include <asm/cpu_device_id.h> -+#include <asm/platform_sst_audio.h> -+#include <linux/clk.h> -+#include <sound/pcm.h> -+#include <sound/pcm_params.h> -+#include <sound/soc.h> -+#include <sound/jack.h> -+#include "../../codecs/tlv320aic31xx.h" -+#include "../atom/sst-atom-controls.h" -+#include "../common/sst-acpi.h" -+#include "../common/sst-dsp.h" -+ -+enum { -+ BYT_AIC3100_IN1_MAP, -+}; -+ -+#define BYT_AIC3100_MAP(quirk) ((quirk) & 0xff) -+#define BYT_AIC3100_SSP2_AIF BIT(16) /* default true, use SSP2 */ -+#define BYT_AIC3100_MCLK_25MHZ BIT(18) /* default false, use 19.2MHz */ -+ -+struct byt_aic3100_private { -+ struct clk *mclk; -+}; -+ -+static unsigned long byt_aic3100_quirk = -+ BYT_AIC3100_IN1_MAP | BYT_AIC3100_SSP2_AIF; -+ -+static void log_quirks(struct device *dev) -+{ -+ if (BYT_AIC3100_MAP(byt_aic3100_quirk) == BYT_AIC3100_IN1_MAP) -+ dev_info(dev, "quirk IN1_MAP enabled"); -+ if (byt_aic3100_quirk & BYT_AIC3100_SSP2_AIF) -+ dev_info(dev, "quirk SSP2_AIF enabled"); -+ else -+ dev_info(dev, "quirk SSP0_AIF enabled"); -+ if (byt_aic3100_quirk & BYT_AIC3100_MCLK_25MHZ) -+ dev_info(dev, "quirk MCLK_25MHZ enabled"); -+ else -+ dev_info(dev, "quirk MCLK_19200kHZ enabled"); -+} -+ -+#define BYT_CODEC_DAI1 "tlv320aic31xx-hifi" -+ -+static inline struct snd_soc_dai *byt_get_codec_dai(struct snd_soc_card *card) -+{ -+ struct snd_soc_pcm_runtime *rtd; -+ -+ list_for_each_entry(rtd, &card->rtd_list, list) { -+ if (!strncmp(rtd->codec_dai->name, BYT_CODEC_DAI1, -+ strlen(BYT_CODEC_DAI1))) -+ return rtd->codec_dai; -+ } -+ return NULL; -+} -+ -+static int platform_clock_control(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *k, int event) -+{ -+ struct snd_soc_dapm_context *dapm = w->dapm; -+ struct snd_soc_card *card = dapm->card; -+ struct snd_soc_dai *codec_dai; -+ struct byt_aic3100_private *priv = snd_soc_card_get_drvdata(card); -+ int ret; -+ -+ codec_dai = byt_get_codec_dai(card); -+ if (!codec_dai) { -+ dev_err(card->dev, -+ "Codec dai not found; Unable to set platform clock\n"); -+ return -EIO; -+ } -+ -+ if (SND_SOC_DAPM_EVENT_ON(event)) { -+ if (priv->mclk) { -+ ret = clk_prepare_enable(priv->mclk); -+ if (ret < 0) { -+ dev_err(card->dev, -+ "could not configure MCLK state"); -+ return ret; -+ } -+ } -+ -+ if (byt_aic3100_quirk & BYT_AIC3100_MCLK_25MHZ) { -+ ret = snd_soc_dai_set_sysclk(codec_dai, -+ AIC31XX_PLL_CLKIN_MCLK, -+ 25000000, -+ SND_SOC_CLOCK_IN); -+ } else { -+ ret = snd_soc_dai_set_sysclk(codec_dai, -+ AIC31XX_PLL_CLKIN_MCLK, -+ 19200000, -+ SND_SOC_CLOCK_IN); -+ } -+ } else { -+ /* -+ * Set codec clock source to internal clock before -+ * turning off the platform clock. Codec needs clock -+ * for Jack detection and button press -+ */ -+ /* FIXME: use RC oscillator? */ -+ ret = snd_soc_dai_set_sysclk(codec_dai, AIC31XX_PLL_CLKIN_MCLK, -+ 0, SND_SOC_CLOCK_IN); -+ if (!ret) { -+ if (priv->mclk) -+ clk_disable_unprepare(priv->mclk); -+ } -+ } -+ -+ if (ret < 0) { -+ dev_err(card->dev, "can't set codec sysclk: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static const struct snd_soc_dapm_widget byt_aic3100_widgets[] = { -+ SND_SOC_DAPM_HP("Headphone", NULL), -+ SND_SOC_DAPM_MIC("Headset Mic", NULL), -+ SND_SOC_DAPM_MIC("Internal Mic", NULL), -+ SND_SOC_DAPM_SPK("Speakers", NULL), -+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, -+ platform_clock_control, SND_SOC_DAPM_PRE_PMU | -+ SND_SOC_DAPM_POST_PMD), -+ -+}; -+ -+static const struct snd_soc_dapm_route byt_aic3100_audio_map[] = { -+ /* External Speakers: HFL, HFR */ -+ {"Speakers", NULL, "SPK"}, -+ -+ /* Headset Stereophone(Headphone): HSOL, HSOR */ -+ {"Headphone", NULL, "HPL"}, -+ {"Headphone", NULL, "HPR"}, -+ -+ {"Headphone", NULL, "Platform Clock"}, -+ {"Headset Mic", NULL, "Platform Clock"}, -+ {"Internal Mic", NULL, "Platform Clock"}, -+ {"Speaker", NULL, "Platform Clock"}, -+ -+}; -+ -+static const struct snd_soc_dapm_route byt_aic3100_intmic_in1_map[] = { -+ {"micbias", NULL, "Internal Mic"}, -+ /* Headset Mic: Headset Mic with bias */ -+ {"MIC1RP", NULL, "Headset Mic"}, -+}; -+ -+static const struct snd_soc_dapm_route byt_aic3100_ssp2_aif_map[] = { -+ {"ssp2 Tx", NULL, "codec_out0"}, -+ {"ssp2 Tx", NULL, "codec_out1"}, -+ {"codec_in0", NULL, "ssp2 Rx"}, -+ {"codec_in1", NULL, "ssp2 Rx"}, -+ -+ {"Playback", NULL, "ssp2 Tx"}, -+ {"ssp2 Rx", NULL, "Capture"}, -+}; -+ -+static const struct snd_soc_dapm_route byt_aic3100_ssp0_aif_map[] = { -+ {"ssp0 Tx", NULL, "modem_out"}, -+ {"modem_in", NULL, "ssp0 Rx"}, -+ -+ {"Playback", NULL, "ssp0 Tx"}, -+ {"ssp0 Rx", NULL, "Capture"}, -+}; -+ -+static const struct snd_kcontrol_new byt_aic3100_controls[] = { -+ SOC_DAPM_PIN_SWITCH("Headphone"), -+ SOC_DAPM_PIN_SWITCH("Headset Mic"), -+ SOC_DAPM_PIN_SWITCH("Internal Mic"), -+ SOC_DAPM_PIN_SWITCH("Speaker"), -+}; -+ -+static int byt_aic3100_aif1_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_dai *codec_dai = rtd->codec_dai; -+ int ret; -+ -+ if (byt_aic3100_quirk & BYT_AIC3100_MCLK_25MHZ) { -+ ret = snd_soc_dai_set_sysclk(codec_dai, AIC31XX_PLL_CLKIN_MCLK, -+ 25000000, -+ SND_SOC_CLOCK_IN); -+ } else { -+ ret = snd_soc_dai_set_sysclk(codec_dai, AIC31XX_PLL_CLKIN_MCLK, -+ 19200000, -+ SND_SOC_CLOCK_IN); -+ } -+ -+ if (ret < 0) { -+ dev_err(rtd->dev, "can't set codec clock %d\n", ret); -+ return ret; -+ } -+ -+ if (byt_aic3100_quirk & BYT_AIC3100_MCLK_25MHZ) { -+ ret = snd_soc_dai_set_pll(codec_dai, 0, AIC31XX_PLL_CLKIN_MCLK, -+ 250000000, params_rate(params)); -+ } else { -+ ret = snd_soc_dai_set_pll(codec_dai, 0, AIC31XX_PLL_CLKIN_MCLK, -+ 19200000, params_rate(params)); -+ -+ } -+ -+ if (ret < 0) { -+ dev_err(rtd->dev, "can't set codec pll: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+/* uncomment when we have an actual quirk -+static int byt_aic3100_quirk_cb(const struct dmi_system_id *id) -+{ -+ byt_aic3100_quirk = (unsigned long)id->driver_data; -+ return 1; -+} -+*/ -+ -+static const struct dmi_system_id byt_aic3100_quirk_table[] = { -+ {} -+}; -+ -+static int byt_aic3100_init(struct snd_soc_pcm_runtime *runtime) -+{ -+ int ret; -+ struct snd_soc_card *card = runtime->card; -+ const struct snd_soc_dapm_route *custom_map; -+ struct byt_aic3100_private *priv = snd_soc_card_get_drvdata(card); -+ int num_routes; -+ -+ card->dapm.idle_bias_off = true; -+ -+ ret = snd_soc_add_card_controls(card, byt_aic3100_controls, -+ ARRAY_SIZE(byt_aic3100_controls)); -+ if (ret) { -+ dev_err(card->dev, "unable to add card controls\n"); -+ return ret; -+ } -+ -+ switch (BYT_AIC3100_MAP(byt_aic3100_quirk)) { -+ case BYT_AIC3100_IN1_MAP: -+ default: -+ custom_map = byt_aic3100_intmic_in1_map; -+ num_routes = ARRAY_SIZE(byt_aic3100_intmic_in1_map); -+ } -+ -+ ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); -+ if (ret) -+ return ret; -+ -+ if (byt_aic3100_quirk & BYT_AIC3100_SSP2_AIF) { -+ ret = snd_soc_dapm_add_routes(&card->dapm, -+ byt_aic3100_ssp2_aif_map, -+ ARRAY_SIZE(byt_aic3100_ssp2_aif_map)); -+ } else { -+ ret = snd_soc_dapm_add_routes(&card->dapm, -+ byt_aic3100_ssp0_aif_map, -+ ARRAY_SIZE(byt_aic3100_ssp0_aif_map)); -+ } -+ if (ret) -+ return ret; -+ -+ snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone"); -+ snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker"); -+ -+ if (priv->mclk) { -+ /* -+ * The firmware might enable the clock at -+ * boot (this information may or may not -+ * be reflected in the enable clock register). -+ * To change the rate we must disable the clock -+ * first to cover these cases. Due to common -+ * clock framework restrictions that do not allow -+ * to disable a clock that has not been enabled, -+ * we need to enable the clock first. -+ */ -+ ret = clk_prepare_enable(priv->mclk); -+ if (!ret) -+ clk_disable_unprepare(priv->mclk); -+ -+ if (byt_aic3100_quirk & BYT_AIC3100_MCLK_25MHZ) -+ ret = clk_set_rate(priv->mclk, 25000000); -+ else -+ ret = clk_set_rate(priv->mclk, 19200000); -+ -+ if (ret) -+ dev_err(card->dev, "unable to set MCLK rate\n"); -+ } -+ -+ return ret; -+} -+ -+static const struct snd_soc_pcm_stream byt_aic3100_dai_params = { -+ .formats = SNDRV_PCM_FMTBIT_S24_LE, -+ .rate_min = 48000, -+ .rate_max = 48000, -+ .channels_min = 2, -+ .channels_max = 2, -+}; -+ -+static int byt_aic3100_codec_fixup(struct snd_soc_pcm_runtime *rtd, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_interval *rate = hw_param_interval(params, -+ SNDRV_PCM_HW_PARAM_RATE); -+ struct snd_interval *channels = hw_param_interval(params, -+ SNDRV_PCM_HW_PARAM_CHANNELS); -+ int ret; -+ -+ /* The DSP will covert the FE rate to 48k, stereo */ -+ rate->min = rate->max = 48000; -+ channels->min = channels->max = 2; -+ -+ if (!(byt_aic3100_quirk & BYT_AIC3100_SSP2_AIF)) { -+ -+ /* set SSP0 to 16-bit */ -+ params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); -+ -+ /* -+ * Default mode for SSP configuration is TDM 4 slot, -+ * override config with explicit setting to I2S 2ch 16-bit. -+ * The word length is set with dai_set_tdm_slot() since there -+ * is no other API exposed -+ */ -+ ret = snd_soc_dai_set_fmt(rtd->cpu_dai, -+ SND_SOC_DAIFMT_I2S | -+ SND_SOC_DAIFMT_NB_IF | -+ SND_SOC_DAIFMT_CBS_CFS -+ ); -+ if (ret < 0) { -+ dev_err(rtd->dev, -+ "can't set format to I2S, err %d\n", ret); -+ return ret; -+ } -+ -+ ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 16); -+ if (ret < 0) { -+ dev_err(rtd->dev, -+ "can't set I2S config, err %d\n", ret); -+ return ret; -+ } -+ -+ } else { -+ -+ /* set SSP2 to 24-bit */ -+ params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); -+ -+ /* -+ * Default mode for SSP configuration is TDM 4 slot, -+ * override config with explicit setting to I2S 2ch 24-bit. -+ * The word length is set with dai_set_tdm_slot() since -+ * there is no other API exposed -+ */ -+ ret = snd_soc_dai_set_fmt(rtd->cpu_dai, -+ SND_SOC_DAIFMT_I2S | -+ SND_SOC_DAIFMT_NB_IF | -+ SND_SOC_DAIFMT_CBS_CFS -+ ); -+ if (ret < 0) { -+ dev_err(rtd->dev, -+ "can't set format to I2S, err %d\n", ret); -+ return ret; -+ } -+ -+ ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); -+ if (ret < 0) { -+ dev_err(rtd->dev, -+ "can't set I2S config, err %d\n", ret); -+ return ret; -+ } -+ } -+ return 0; -+} -+ -+static int byt_aic3100_aif1_startup(struct snd_pcm_substream *substream) -+{ -+ return snd_pcm_hw_constraint_single(substream->runtime, -+ SNDRV_PCM_HW_PARAM_RATE, 48000); -+} -+ -+static struct snd_soc_ops byt_aic3100_aif1_ops = { -+ .startup = byt_aic3100_aif1_startup, -+}; -+ -+static struct snd_soc_ops byt_aic3100_be_ssp2_ops = { -+ .hw_params = byt_aic3100_aif1_hw_params, -+}; -+ -+static struct snd_soc_dai_link byt_aic3100_dais[] = { -+ [MERR_DPCM_AUDIO] = { -+ .name = "Baytrail Audio Port", -+ .stream_name = "Baytrail Audio", -+ .cpu_dai_name = "media-cpu-dai", -+ .codec_dai_name = "snd-soc-dummy-dai", -+ .codec_name = "snd-soc-dummy", -+ .platform_name = "sst-mfld-platform", -+ .ignore_suspend = 1, -+ .dynamic = 1, -+ .dpcm_playback = 1, -+ .dpcm_capture = 1, -+ .ops = &byt_aic3100_aif1_ops, -+ }, -+ [MERR_DPCM_DEEP_BUFFER] = { -+ .name = "Deep-Buffer Audio Port", -+ .stream_name = "Deep-Buffer Audio", -+ .cpu_dai_name = "deepbuffer-cpu-dai", -+ .codec_dai_name = "snd-soc-dummy-dai", -+ .codec_name = "snd-soc-dummy", -+ .platform_name = "sst-mfld-platform", -+ .ignore_suspend = 1, -+ .nonatomic = true, -+ .dynamic = 1, -+ .dpcm_playback = 1, -+ .ops = &byt_aic3100_aif1_ops, -+ }, -+ [MERR_DPCM_COMPR] = { -+ .name = "Baytrail Compressed Port", -+ .stream_name = "Baytrail Compress", -+ .cpu_dai_name = "compress-cpu-dai", -+ .codec_dai_name = "snd-soc-dummy-dai", -+ .codec_name = "snd-soc-dummy", -+ .platform_name = "sst-mfld-platform", -+ }, -+ /* back ends */ -+ { -+ .name = "SSP2-Codec", -+ .id = 1, -+ .cpu_dai_name = "ssp2-port", /* overwritten for ssp0 routing */ -+ .platform_name = "sst-mfld-platform", -+ .no_pcm = 1, -+ .codec_dai_name = "tlv320aic31xx-hifi", -+ .codec_name = "i2c-10TI3100:00", /* overwritten with HID */ -+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF -+ | SND_SOC_DAIFMT_CBS_CFS, -+ .be_hw_params_fixup = byt_aic3100_codec_fixup, -+ .ignore_suspend = 1, -+ .dpcm_playback = 1, -+ .dpcm_capture = 1, -+ .init = byt_aic3100_init, -+ .ops = &byt_aic3100_be_ssp2_ops, -+ }, -+}; -+ -+/* SoC card */ -+static struct snd_soc_card byt_aic3100_card = { -+ .name = "bytcr-aic3100", -+ .owner = THIS_MODULE, -+ .dai_link = byt_aic3100_dais, -+ .num_links = ARRAY_SIZE(byt_aic3100_dais), -+ .dapm_widgets = byt_aic3100_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(byt_aic3100_widgets), -+ .dapm_routes = byt_aic3100_audio_map, -+ .num_dapm_routes = ARRAY_SIZE(byt_aic3100_audio_map), -+ .fully_routed = true, -+}; -+ -+static char byt_aic3100_codec_name[16];/* i2c-<HID>:00 with HID being 8 chars */ -+static char byt_aic3100_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ -+ -+static bool is_valleyview(void) -+{ -+ static const struct x86_cpu_id cpu_ids[] = { -+ { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */ -+ {} -+ }; -+ -+ if (!x86_match_cpu(cpu_ids)) -+ return false; -+ return true; -+} -+ -+ -+static int snd_byt_aic3100_mc_probe(struct platform_device *pdev) -+{ -+ int ret_val = 0; -+ struct sst_acpi_mach *mach; -+ const char *i2c_name = NULL; -+ int i; -+ int dai_index; -+ struct byt_aic3100_private *priv; -+ bool is_bytcr = false; -+ -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC); -+ if (!priv) -+ return -ENOMEM; -+ -+ /* register the soc card */ -+ byt_aic3100_card.dev = &pdev->dev; -+ mach = byt_aic3100_card.dev->platform_data; -+ snd_soc_card_set_drvdata(&byt_aic3100_card, priv); -+ -+ /* fix index of codec dai */ -+ dai_index = MERR_DPCM_COMPR + 1; -+ for (i = 0; i < ARRAY_SIZE(byt_aic3100_dais); i++) { -+ if (!strcmp(byt_aic3100_dais[i].codec_name, -+ "i2c-10TI3100:00")) { -+ dai_index = i; -+ break; -+ } -+ } -+ -+ /* fixup codec name based on HID */ -+ i2c_name = sst_acpi_find_name_from_hid(mach->id); -+ if (i2c_name != NULL) { -+ snprintf(byt_aic3100_codec_name, sizeof(byt_aic3100_codec_name), -+ "%s%s", "i2c-", i2c_name); -+ -+ byt_aic3100_dais[dai_index].codec_name = byt_aic3100_codec_name; -+ } -+ -+ /* -+ * swap SSP0 if bytcr is detected -+ * (will be overridden if DMI quirk is detected) -+ */ -+ if (is_valleyview()) { -+ struct sst_platform_info *p_info = mach->pdata; -+ const struct sst_res_info *res_info = p_info->res_info; -+ -+ if (res_info->acpi_ipc_irq_index == 0) { -+ is_bytcr = true; -+ byt_aic3100_quirk &= ~BYT_AIC3100_SSP2_AIF; -+ } -+ } -+ -+ /* check quirks before creating card */ -+ dmi_check_system(byt_aic3100_quirk_table); -+ log_quirks(&pdev->dev); -+ -+ if (!(byt_aic3100_quirk & BYT_AIC3100_SSP2_AIF)) { -+ -+ /* fixup cpu dai name name */ -+ snprintf(byt_aic3100_cpu_dai_name, -+ sizeof(byt_aic3100_cpu_dai_name), -+ "%s", "ssp0-port"); -+ -+ byt_aic3100_dais[dai_index].cpu_dai_name = -+ byt_aic3100_cpu_dai_name; -+ } -+ -+ if (is_valleyview()) { -+ priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); -+ if (IS_ERR(priv->mclk)) { -+ dev_err(&pdev->dev, -+ "Failed to get MCLK from pmc_plt_clk_3: %ld\n", -+ PTR_ERR(priv->mclk)); -+ -+ /* -+ * Audio output only works with MCLK enabled -+ */ -+ return PTR_ERR(priv->mclk); -+ } -+ } -+ -+ ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_aic3100_card); -+ -+ if (ret_val) { -+ dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", -+ ret_val); -+ return ret_val; -+ } -+ platform_set_drvdata(pdev, &byt_aic3100_card); -+ return ret_val; -+} -+ -+static struct platform_driver snd_byt_aic3100_mc_driver = { -+ .driver = { -+ .name = "bytcr_aic3100", -+ .pm = &snd_soc_pm_ops, -+ }, -+ .probe = snd_byt_aic3100_mc_probe, -+}; -+ -+module_platform_driver(snd_byt_aic3100_mc_driver); -+ -+MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver"); -+MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>"); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:bytcr_aic3100"); -diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c -index bff77a1f27fc..c2ecbdc28459 100644 ---- a/sound/soc/intel/boards/bytcr_rt5640.c -+++ b/sound/soc/intel/boards/bytcr_rt5640.c -@@ -389,6 +389,16 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { - BYT_RT5640_SSP0_AIF1), - - }, -+ { -+ .callback = byt_rt5640_quirk_cb, -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), -+ }, -+ .driver_data = (unsigned long *)(BYT_RT5640_IN3_MAP | -+ BYT_RT5640_MCLK_EN | -+ BYT_RT5640_SSP0_AIF1), -+ -+ }, - {} - }; - -@@ -689,6 +699,10 @@ static bool is_valleyview(void) - return true; - } - -+struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ -+ u64 aif_value; /* 1: AIF1, 2: AIF2 */ -+ u64 mclock_value; /* usually 25MHz (0x17d7940), ignored */ -+}; - - static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) - { -@@ -698,6 +712,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) - int i; - int dai_index; - struct byt_rt5640_private *priv; -+ bool is_bytcr = false; - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC); - if (!priv) -@@ -734,8 +749,52 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) - struct sst_platform_info *p_info = mach->pdata; - const struct sst_res_info *res_info = p_info->res_info; - -- /* TODO: use CHAN package info from BIOS to detect AIF1/AIF2 */ -- if (res_info->acpi_ipc_irq_index == 0) { -+ if (res_info->acpi_ipc_irq_index == 0) -+ is_bytcr = true; -+ } -+ -+ if (is_bytcr) { -+ /* -+ * Baytrail CR platforms may have CHAN package in BIOS, try -+ * to find relevant routing quirk based as done on Windows -+ * platforms. We have to read the information directly from the -+ * BIOS, at this stage the card is not created and the links -+ * with the codec driver/pdata are non-existent -+ */ -+ -+ struct acpi_chan_package chan_package; -+ -+ /* format specified: 2 64-bit integers */ -+ struct acpi_buffer format = {sizeof("NN"), "NN"}; -+ struct acpi_buffer state = {0, NULL}; -+ struct sst_acpi_package_context pkg_ctx; -+ bool pkg_found = false; -+ -+ state.length = sizeof(chan_package); -+ state.pointer = &chan_package; -+ -+ pkg_ctx.name = "CHAN"; -+ pkg_ctx.length = 2; -+ pkg_ctx.format = &format; -+ pkg_ctx.state = &state; -+ pkg_ctx.data_valid = false; -+ -+ pkg_found = sst_acpi_find_package_from_hid(mach->id, &pkg_ctx); -+ if (pkg_found) { -+ if (chan_package.aif_value == 1) { -+ dev_info(&pdev->dev, "BIOS Routing: AIF1 connected\n"); -+ byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF1; -+ } else if (chan_package.aif_value == 2) { -+ dev_info(&pdev->dev, "BIOS Routing: AIF2 connected\n"); -+ byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2; -+ } else { -+ dev_info(&pdev->dev, "BIOS Routing isn't valid, ignored\n"); -+ pkg_found = false; -+ } -+ } -+ -+ if (!pkg_found) { -+ /* no BIOS indications, assume SSP0-AIF2 connection */ - byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2; - } - } -@@ -774,7 +833,21 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) - dev_err(&pdev->dev, - "Failed to get MCLK from pmc_plt_clk_3: %ld\n", - PTR_ERR(priv->mclk)); -- return PTR_ERR(priv->mclk); -+ -+ if (is_bytcr) { -+ /* -+ * Audio output on Baytrail CR only works -+ * with MCLK enabled -+ */ -+ return PTR_ERR(priv->mclk); -+ } else { -+ /* -+ * Audio output can work with bitclock only -+ * on Baytrail, with a limited audio quality -+ * degradation -+ */ -+ byt_rt5640_quirk &= ~BYT_RT5640_MCLK_EN; -+ } - } - } - -diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c -index 35f591eab3c9..1c672768fc35 100644 ---- a/sound/soc/intel/boards/bytcr_rt5651.c -+++ b/sound/soc/intel/boards/bytcr_rt5651.c -@@ -24,21 +24,134 @@ - #include <linux/device.h> - #include <linux/dmi.h> - #include <linux/slab.h> -+#include <asm/cpu_device_id.h> -+#include <asm/platform_sst_audio.h> -+#include <linux/clk.h> - #include <sound/pcm.h> - #include <sound/pcm_params.h> - #include <sound/soc.h> - #include <sound/jack.h> - #include "../../codecs/rt5651.h" - #include "../atom/sst-atom-controls.h" -+#include "../common/sst-acpi.h" -+ -+enum { -+ BYT_RT5651_DMIC1_MAP, -+ BYT_RT5651_DMIC2_MAP, -+ BYT_RT5651_IN1_MAP, -+}; -+ -+#define BYT_RT5651_MAP(quirk) ((quirk) & 0xff) -+#define BYT_RT5651_DMIC_EN BIT(16) -+#define BYT_RT5651_MCLK_EN BIT(17) -+#define BYT_RT5651_MCLK_25MHZ BIT(18) -+ -+struct byt_rt5651_private { -+ struct clk *mclk; -+}; -+ -+static unsigned long byt_rt5651_quirk = BYT_RT5651_DMIC1_MAP | -+ BYT_RT5651_DMIC_EN | -+ BYT_RT5651_MCLK_EN; -+ -+static void log_quirks(struct device *dev) -+{ -+ if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_DMIC1_MAP) -+ dev_info(dev, "quirk DMIC1_MAP enabled"); -+ if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_DMIC2_MAP) -+ dev_info(dev, "quirk DMIC2_MAP enabled"); -+ if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN1_MAP) -+ dev_info(dev, "quirk IN1_MAP enabled"); -+ if (byt_rt5651_quirk & BYT_RT5651_DMIC_EN) -+ dev_info(dev, "quirk DMIC enabled"); -+ if (byt_rt5651_quirk & BYT_RT5651_MCLK_EN) -+ dev_info(dev, "quirk MCLK_EN enabled"); -+ if (byt_rt5651_quirk & BYT_RT5651_MCLK_25MHZ) -+ dev_info(dev, "quirk MCLK_25MHZ enabled"); -+} -+ -+#define BYT_CODEC_DAI1 "rt5651-aif1" -+ -+static inline struct snd_soc_dai *byt_get_codec_dai(struct snd_soc_card *card) -+{ -+ struct snd_soc_pcm_runtime *rtd; -+ -+ list_for_each_entry(rtd, &card->rtd_list, list) { -+ if (!strncmp(rtd->codec_dai->name, BYT_CODEC_DAI1, -+ strlen(BYT_CODEC_DAI1))) -+ return rtd->codec_dai; -+ } -+ return NULL; -+} -+ -+static int platform_clock_control(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *k, int event) -+{ -+ struct snd_soc_dapm_context *dapm = w->dapm; -+ struct snd_soc_card *card = dapm->card; -+ struct snd_soc_dai *codec_dai; -+ struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card); -+ int ret; -+ -+ codec_dai = byt_get_codec_dai(card); -+ if (!codec_dai) { -+ dev_err(card->dev, -+ "Codec dai not found; Unable to set platform clock\n"); -+ return -EIO; -+ } -+ -+ if (SND_SOC_DAPM_EVENT_ON(event)) { -+ if ((byt_rt5651_quirk & BYT_RT5651_MCLK_EN) && priv->mclk) { -+ ret = clk_prepare_enable(priv->mclk); -+ if (ret < 0) { -+ dev_err(card->dev, -+ "could not configure MCLK state"); -+ return ret; -+ } -+ } -+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5651_SCLK_S_PLL1, -+ 48000 * 512, -+ SND_SOC_CLOCK_IN); -+ } else { -+ /* -+ * Set codec clock source to internal clock before -+ * turning off the platform clock. Codec needs clock -+ * for Jack detection and button press -+ */ -+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5651_SCLK_S_RCCLK, -+ 0, -+ SND_SOC_CLOCK_IN); -+ if (!ret) { -+ if ((byt_rt5651_quirk & BYT_RT5651_MCLK_EN) && priv->mclk) -+ clk_disable_unprepare(priv->mclk); -+ } -+ } -+ -+ if (ret < 0) { -+ dev_err(card->dev, "can't set codec sysclk: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} - - static const struct snd_soc_dapm_widget byt_rt5651_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Internal Mic", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), -+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, -+ platform_clock_control, SND_SOC_DAPM_PRE_PMU | -+ SND_SOC_DAPM_POST_PMD), -+ - }; - - static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = { -+ {"Headphone", NULL, "Platform Clock"}, -+ {"Headset Mic", NULL, "Platform Clock"}, -+ {"Internal Mic", NULL, "Platform Clock"}, -+ {"Speaker", NULL, "Platform Clock"}, -+ - {"AIF1 Playback", NULL, "ssp2 Tx"}, - {"ssp2 Tx", NULL, "codec_out0"}, - {"ssp2 Tx", NULL, "codec_out1"}, -@@ -67,18 +180,6 @@ static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_map[] = { - {"IN1P", NULL, "Internal Mic"}, - }; - --enum { -- BYT_RT5651_DMIC1_MAP, -- BYT_RT5651_DMIC2_MAP, -- BYT_RT5651_IN1_MAP, --}; -- --#define BYT_RT5651_MAP(quirk) ((quirk) & 0xff) --#define BYT_RT5651_DMIC_EN BIT(16) -- --static unsigned long byt_rt5651_quirk = BYT_RT5651_DMIC1_MAP | -- BYT_RT5651_DMIC_EN; -- - static const struct snd_kcontrol_new byt_rt5651_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), -@@ -103,9 +204,27 @@ static int byt_rt5651_aif1_hw_params(struct snd_pcm_substream *substream, - return ret; - } - -- ret = snd_soc_dai_set_pll(codec_dai, 0, RT5651_PLL1_S_BCLK1, -- params_rate(params) * 50, -- params_rate(params) * 512); -+ if (!(byt_rt5651_quirk & BYT_RT5651_MCLK_EN)) { -+ /* 2x25 bit slots on SSP2 */ -+ ret = snd_soc_dai_set_pll(codec_dai, 0, -+ RT5651_PLL1_S_BCLK1, -+ params_rate(params) * 50, -+ params_rate(params) * 512); -+ } -+ else { -+ if (byt_rt5651_quirk & BYT_RT5651_MCLK_25MHZ) { -+ ret = snd_soc_dai_set_pll(codec_dai, 0, -+ RT5651_PLL1_S_MCLK, -+ 25000000, -+ params_rate(params) * 512); -+ } else { -+ ret = snd_soc_dai_set_pll(codec_dai, 0, -+ RT5651_PLL1_S_MCLK, -+ 19200000, -+ params_rate(params) * 512); -+ } -+ } -+ - if (ret < 0) { - dev_err(rtd->dev, "can't set codec pll: %d\n", ret); - return ret; -@@ -114,8 +233,22 @@ static int byt_rt5651_aif1_hw_params(struct snd_pcm_substream *substream, - return 0; - } - -+static int byt_rt5651_quirk_cb(const struct dmi_system_id *id) -+{ -+ byt_rt5651_quirk = (unsigned long)id->driver_data; -+ return 1; -+} -+ - static const struct dmi_system_id byt_rt5651_quirk_table[] = { -- {} -+ { -+ .callback = byt_rt5651_quirk_cb, -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"), -+ }, -+ .driver_data = (unsigned long *)(BYT_RT5651_DMIC1_MAP | -+ BYT_RT5651_DMIC_EN), -+ }, - }; - - static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) -@@ -123,6 +256,7 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) - int ret; - struct snd_soc_card *card = runtime->card; - const struct snd_soc_dapm_route *custom_map; -+ struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card); - int num_routes; - - card->dapm.idle_bias_off = true; -@@ -141,6 +275,9 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) - custom_map = byt_rt5651_intmic_dmic1_map; - num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic1_map); - } -+ ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); -+ if (ret) -+ return ret; - - ret = snd_soc_add_card_controls(card, byt_rt5651_controls, - ARRAY_SIZE(byt_rt5651_controls)); -@@ -151,6 +288,30 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) - snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone"); - snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker"); - -+ if ((byt_rt5651_quirk & BYT_RT5651_MCLK_EN) && priv->mclk) { -+ /* -+ * The firmware might enable the clock at -+ * boot (this information may or may not -+ * be reflected in the enable clock register). -+ * To change the rate we must disable the clock -+ * first to cover these cases. Due to common -+ * clock framework restrictions that do not allow -+ * to disable a clock that has not been enabled, -+ * we need to enable the clock first. -+ */ -+ ret = clk_prepare_enable(priv->mclk); -+ if (!ret) -+ clk_disable_unprepare(priv->mclk); -+ -+ if (byt_rt5651_quirk & BYT_RT5651_MCLK_25MHZ) -+ ret = clk_set_rate(priv->mclk, 25000000); -+ else -+ ret = clk_set_rate(priv->mclk, 19200000); -+ -+ if (ret) -+ dev_err(card->dev, "unable to set MCLK rate\n"); -+ } -+ - return ret; - } - -@@ -298,12 +459,73 @@ static struct snd_soc_card byt_rt5651_card = { - .fully_routed = true, - }; - -+static char byt_rt5651_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */ -+ -+static bool is_valleyview(void) -+{ -+ static const struct x86_cpu_id cpu_ids[] = { -+ { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */ -+ {} -+ }; -+ -+ if (!x86_match_cpu(cpu_ids)) -+ return false; -+ return true; -+} -+ - static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) - { - int ret_val = 0; -+ struct sst_acpi_mach *mach; -+ const char *i2c_name = NULL; -+ int i; -+ int dai_index; -+ struct byt_rt5651_private *priv; -+ -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC); -+ if (!priv) -+ return -ENOMEM; - - /* register the soc card */ - byt_rt5651_card.dev = &pdev->dev; -+ mach = byt_rt5651_card.dev->platform_data; -+ -+ /* fix index of codec dai */ -+ dai_index = MERR_DPCM_COMPR + 1; -+ for (i = 0; i < ARRAY_SIZE(byt_rt5651_dais); i++) { -+ if (!strcmp(byt_rt5651_dais[i].codec_name, "i2c-10EC5651:00")) { -+ dai_index = i; -+ break; -+ } -+ } -+ -+ /* fixup codec name based on HID */ -+ i2c_name = sst_acpi_find_name_from_hid(mach->id); -+ if (i2c_name != NULL) { -+ snprintf(byt_rt5651_codec_name, sizeof(byt_rt5651_codec_name), -+ "%s%s", "i2c-", i2c_name); -+ -+ byt_rt5651_dais[dai_index].codec_name = byt_rt5651_codec_name; -+ } -+ -+ /* check quirks before creating card */ -+ dmi_check_system(byt_rt5651_quirk_table); -+ log_quirks(&pdev->dev); -+ -+ if ((byt_rt5651_quirk & BYT_RT5651_MCLK_EN) && (is_valleyview())) { -+ priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); -+ if (IS_ERR(priv->mclk)) { -+ dev_err(&pdev->dev, -+ "Failed to get MCLK from pmc_plt_clk_3: %ld\n", -+ PTR_ERR(priv->mclk)); -+ /* -+ * Audio output can work with bitclock only -+ * on Baytrail, with a limited audio quality -+ * degradation -+ */ -+ byt_rt5651_quirk &= ~BYT_RT5651_MCLK_EN; -+ } -+ } - - ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card); - -diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c -index cdcced9f32b6..a95ae141e3a6 100644 ---- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c -+++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c -@@ -23,6 +23,9 @@ - #include <linux/platform_device.h> - #include <linux/slab.h> - #include <linux/acpi.h> -+#include <asm/cpu_device_id.h> -+#include <asm/platform_sst_audio.h> -+#include <linux/clk.h> - #include <sound/pcm.h> - #include <sound/pcm_params.h> - #include <sound/soc.h> -@@ -37,6 +40,7 @@ - struct cht_mc_private { - struct snd_soc_jack jack; - bool ts3a227e_present; -+ struct clk *mclk; - }; - - static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) -@@ -51,11 +55,51 @@ static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) - return NULL; - } - -+static int platform_clock_control(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *k, int event) -+{ -+ struct snd_soc_dapm_context *dapm = w->dapm; -+ struct snd_soc_card *card = dapm->card; -+ struct snd_soc_dai *codec_dai; -+ struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); -+ int ret; -+ -+ codec_dai = cht_get_codec_dai(card); -+ if (!codec_dai) { -+ dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n"); -+ return -EIO; -+ } -+ -+ if (SND_SOC_DAPM_EVENT_ON(event)) { -+ if (ctx->mclk) { -+ ret = clk_prepare_enable(ctx->mclk); -+ if (ret < 0) { -+ dev_err(card->dev, -+ "could not configure MCLK state"); -+ return ret; -+ } -+ } -+ } else { -+ -+ /* FIXME: if there is no clock can jack detection work ? */ -+ -+ if (ctx->mclk) { -+ clk_disable_unprepare(ctx->mclk); -+ } -+ } -+ -+ return 0; -+} -+ -+ - static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Int Mic", NULL), - SND_SOC_DAPM_SPK("Ext Spk", NULL), -+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, -+ platform_clock_control, SND_SOC_DAPM_PRE_PMU | -+ SND_SOC_DAPM_POST_PMD), - }; - - static const struct snd_soc_dapm_route cht_audio_map[] = { -@@ -72,6 +116,10 @@ static const struct snd_soc_dapm_route cht_audio_map[] = { - {"codec_in0", NULL, "ssp2 Rx" }, - {"codec_in1", NULL, "ssp2 Rx" }, - {"ssp2 Rx", NULL, "HiFi Capture"}, -+ {"Headphone", NULL, "Platform Clock"}, -+ {"Headset Mic", NULL, "Platform Clock"}, -+ {"Int Mic", NULL, "Platform Clock"}, -+ {"Ext Spk", NULL, "Platform Clock"}, - }; - - static const struct snd_kcontrol_new cht_mc_controls[] = { -@@ -153,6 +201,26 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) - if (ctx->ts3a227e_present) - snd_soc_jack_notifier_register(jack, &cht_jack_nb); - -+ if (ctx->mclk) { -+ /* -+ * The firmware might enable the clock at -+ * boot (this information may or may not -+ * be reflected in the enable clock register). -+ * To change the rate we must disable the clock -+ * first to cover these cases. Due to common -+ * clock framework restrictions that do not allow -+ * to disable a clock that has not been enabled, -+ * we need to enable the clock first. -+ */ -+ ret = clk_prepare_enable(ctx->mclk); -+ if (!ret) -+ clk_disable_unprepare(ctx->mclk); -+ -+ ret = clk_set_rate(ctx->mclk, CHT_PLAT_CLK_3_HZ); -+ -+ if (ret) -+ dev_err(runtime->dev, "unable to set MCLK rate\n"); -+ } - return ret; - } - -@@ -287,6 +355,18 @@ static struct snd_soc_card snd_soc_card_cht = { - .num_controls = ARRAY_SIZE(cht_mc_controls), - }; - -+static bool is_valleyview(void) -+{ -+ static const struct x86_cpu_id cpu_ids[] = { -+ { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */ -+ {} -+ }; -+ -+ if (!x86_match_cpu(cpu_ids)) -+ return false; -+ return true; -+} -+ - static int snd_cht_mc_probe(struct platform_device *pdev) - { - int ret_val = 0; -@@ -306,6 +386,17 @@ static int snd_cht_mc_probe(struct platform_device *pdev) - /* register the soc card */ - snd_soc_card_cht.dev = &pdev->dev; - snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); -+ -+ if (is_valleyview()) { -+ drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); -+ if (IS_ERR(drv->mclk)) { -+ dev_err(&pdev->dev, -+ "Failed to get MCLK from pmc_plt_clk_3: %ld\n", -+ PTR_ERR(drv->mclk)); -+ return PTR_ERR(drv->mclk); -+ } -+ } -+ - ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); - if (ret_val) { - dev_err(&pdev->dev, -diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c -index 16c94c45ce50..e792f9849f98 100644 ---- a/sound/soc/intel/boards/cht_bsw_rt5645.c -+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c -@@ -23,7 +23,11 @@ - #include <linux/module.h> - #include <linux/acpi.h> - #include <linux/platform_device.h> -+#include <linux/dmi.h> - #include <linux/slab.h> -+#include <asm/cpu_device_id.h> -+#include <asm/platform_sst_audio.h> -+#include <linux/clk.h> - #include <sound/pcm.h> - #include <sound/pcm_params.h> - #include <sound/soc.h> -@@ -33,7 +37,8 @@ - #include "../common/sst-acpi.h" - - #define CHT_PLAT_CLK_3_HZ 19200000 --#define CHT_CODEC_DAI "rt5645-aif1" -+#define CHT_CODEC_DAI1 "rt5645-aif1" -+#define CHT_CODEC_DAI2 "rt5645-aif2" - - struct cht_acpi_card { - char *codec_id; -@@ -45,15 +50,36 @@ struct cht_mc_private { - struct snd_soc_jack jack; - struct cht_acpi_card *acpi_card; - char codec_name[16]; -+ struct clk *mclk; - }; - -+#define CHT_RT5645_MAP(quirk) ((quirk) & 0xff) -+#define CHT_RT5645_SSP2_AIF2 BIT(16) /* default is using AIF1 */ -+#define CHT_RT5645_SSP0_AIF1 BIT(17) -+#define CHT_RT5645_SSP0_AIF2 BIT(18) -+ -+static unsigned long cht_rt5645_quirk = 0; -+ -+static void log_quirks(struct device *dev) -+{ -+ if (cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) -+ dev_info(dev, "quirk SSP2_AIF2 enabled"); -+ if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1) -+ dev_info(dev, "quirk SSP0_AIF1 enabled"); -+ if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2) -+ dev_info(dev, "quirk SSP0_AIF2 enabled"); -+} -+ - static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) - { - struct snd_soc_pcm_runtime *rtd; - - list_for_each_entry(rtd, &card->rtd_list, list) { -- if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, -- strlen(CHT_CODEC_DAI))) -+ if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI1, -+ strlen(CHT_CODEC_DAI1))) -+ return rtd->codec_dai; -+ if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI2, -+ strlen(CHT_CODEC_DAI2))) - return rtd->codec_dai; - } - return NULL; -@@ -65,6 +91,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct snd_soc_dai *codec_dai; -+ struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); - int ret; - - codec_dai = cht_get_codec_dai(card); -@@ -73,19 +100,30 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, - return -EIO; - } - -- if (!SND_SOC_DAPM_EVENT_OFF(event)) -- return 0; -+ if (SND_SOC_DAPM_EVENT_ON(event)) { -+ if (ctx->mclk) { -+ ret = clk_prepare_enable(ctx->mclk); -+ if (ret < 0) { -+ dev_err(card->dev, -+ "could not configure MCLK state"); -+ return ret; -+ } -+ } -+ } else { -+ /* Set codec sysclk source to its internal clock because codec PLL will -+ * be off when idle and MCLK will also be off when codec is -+ * runtime suspended. Codec needs clock for jack detection and button -+ * press. MCLK is turned off with clock framework or ACPI. -+ */ -+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_RCCLK, -+ 0, SND_SOC_CLOCK_IN); -+ if (ret < 0) { -+ dev_err(card->dev, "can't set codec sysclk: %d\n", ret); -+ return ret; -+ } - -- /* Set codec sysclk source to its internal clock because codec PLL will -- * be off when idle and MCLK will also be off by ACPI when codec is -- * runtime suspended. Codec needs clock for jack detection and button -- * press. -- */ -- ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_RCCLK, -- 0, SND_SOC_CLOCK_IN); -- if (ret < 0) { -- dev_err(card->dev, "can't set codec sysclk: %d\n", ret); -- return ret; -+ if (ctx->mclk) -+ clk_disable_unprepare(ctx->mclk); - } - - return 0; -@@ -97,7 +135,7 @@ static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { - SND_SOC_DAPM_MIC("Int Mic", NULL), - SND_SOC_DAPM_SPK("Ext Spk", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, -- platform_clock_control, SND_SOC_DAPM_POST_PMD), -+ platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - }; - - static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = { -@@ -109,12 +147,6 @@ static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = { - {"Headphone", NULL, "HPOR"}, - {"Ext Spk", NULL, "SPOL"}, - {"Ext Spk", NULL, "SPOR"}, -- {"AIF1 Playback", NULL, "ssp2 Tx"}, -- {"ssp2 Tx", NULL, "codec_out0"}, -- {"ssp2 Tx", NULL, "codec_out1"}, -- {"codec_in0", NULL, "ssp2 Rx" }, -- {"codec_in1", NULL, "ssp2 Rx" }, -- {"ssp2 Rx", NULL, "AIF1 Capture"}, - {"Headphone", NULL, "Platform Clock"}, - {"Headset Mic", NULL, "Platform Clock"}, - {"Int Mic", NULL, "Platform Clock"}, -@@ -130,16 +162,42 @@ static const struct snd_soc_dapm_route cht_rt5650_audio_map[] = { - {"Headphone", NULL, "HPOR"}, - {"Ext Spk", NULL, "SPOL"}, - {"Ext Spk", NULL, "SPOR"}, -+ {"Headphone", NULL, "Platform Clock"}, -+ {"Headset Mic", NULL, "Platform Clock"}, -+ {"Int Mic", NULL, "Platform Clock"}, -+ {"Ext Spk", NULL, "Platform Clock"}, -+}; -+ -+static const struct snd_soc_dapm_route cht_rt5645_ssp2_aif1_map[] = { - {"AIF1 Playback", NULL, "ssp2 Tx"}, - {"ssp2 Tx", NULL, "codec_out0"}, - {"ssp2 Tx", NULL, "codec_out1"}, - {"codec_in0", NULL, "ssp2 Rx" }, - {"codec_in1", NULL, "ssp2 Rx" }, - {"ssp2 Rx", NULL, "AIF1 Capture"}, -- {"Headphone", NULL, "Platform Clock"}, -- {"Headset Mic", NULL, "Platform Clock"}, -- {"Int Mic", NULL, "Platform Clock"}, -- {"Ext Spk", NULL, "Platform Clock"}, -+}; -+ -+static const struct snd_soc_dapm_route cht_rt5645_ssp2_aif2_map[] = { -+ {"AIF2 Playback", NULL, "ssp2 Tx"}, -+ {"ssp2 Tx", NULL, "codec_out0"}, -+ {"ssp2 Tx", NULL, "codec_out1"}, -+ {"codec_in0", NULL, "ssp2 Rx" }, -+ {"codec_in1", NULL, "ssp2 Rx" }, -+ {"ssp2 Rx", NULL, "AIF2 Capture"}, -+}; -+ -+static const struct snd_soc_dapm_route cht_rt5645_ssp0_aif1_map[] = { -+ {"AIF1 Playback", NULL, "ssp0 Tx"}, -+ {"ssp0 Tx", NULL, "modem_out"}, -+ {"modem_in", NULL, "ssp0 Rx" }, -+ {"ssp0 Rx", NULL, "AIF1 Capture"}, -+}; -+ -+static const struct snd_soc_dapm_route cht_rt5645_ssp0_aif2_map[] = { -+ {"AIF2 Playback", NULL, "ssp0 Tx"}, -+ {"ssp0 Tx", NULL, "modem_out"}, -+ {"modem_in", NULL, "ssp0 Rx" }, -+ {"ssp0 Rx", NULL, "AIF2 Capture"}, - }; - - static const struct snd_kcontrol_new cht_mc_controls[] = { -@@ -185,11 +243,25 @@ static int cht_aif1_hw_params(struct snd_pcm_substream *substream, - return 0; - } - -+/* uncomment when we have a real quirk -+static int cht_rt5645_quirk_cb(const struct dmi_system_id *id) -+{ -+ cht_rt5645_quirk = (unsigned long)id->driver_data; -+ return 1; -+} -+*/ -+ -+static const struct dmi_system_id cht_rt5645_quirk_table[] = { -+ { -+ }, -+}; -+ - static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) - { - int ret; - int jack_type; - struct snd_soc_codec *codec = runtime->codec; -+ struct snd_soc_card *card = runtime->card; - struct snd_soc_dai *codec_dai = runtime->codec_dai; - struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); - -@@ -201,6 +273,26 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) - RT5645_AD_STEREO_FILTER, - RT5645_CLK_SEL_I2S1_ASRC); - -+ if (cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) { -+ ret = snd_soc_dapm_add_routes(&card->dapm, -+ cht_rt5645_ssp2_aif2_map, -+ ARRAY_SIZE(cht_rt5645_ssp2_aif2_map)); -+ } else if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1) { -+ ret = snd_soc_dapm_add_routes(&card->dapm, -+ cht_rt5645_ssp0_aif1_map, -+ ARRAY_SIZE(cht_rt5645_ssp0_aif1_map)); -+ } else if (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2) { -+ ret = snd_soc_dapm_add_routes(&card->dapm, -+ cht_rt5645_ssp0_aif2_map, -+ ARRAY_SIZE(cht_rt5645_ssp0_aif2_map)); -+ } else { -+ ret = snd_soc_dapm_add_routes(&card->dapm, -+ cht_rt5645_ssp2_aif1_map, -+ ARRAY_SIZE(cht_rt5645_ssp2_aif1_map)); -+ } -+ if (ret) -+ return ret; -+ - /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); - if (ret < 0) { -@@ -225,12 +317,33 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) - - rt5645_set_jack_detect(codec, &ctx->jack, &ctx->jack, &ctx->jack); - -+ if (ctx->mclk) { -+ /* -+ * The firmware might enable the clock at -+ * boot (this information may or may not -+ * be reflected in the enable clock register). -+ * To change the rate we must disable the clock -+ * first to cover these cases. Due to common -+ * clock framework restrictions that do not allow -+ * to disable a clock that has not been enabled, -+ * we need to enable the clock first. -+ */ -+ ret = clk_prepare_enable(ctx->mclk); -+ if (!ret) -+ clk_disable_unprepare(ctx->mclk); -+ -+ ret = clk_set_rate(ctx->mclk, CHT_PLAT_CLK_3_HZ); -+ -+ if (ret) -+ dev_err(runtime->dev, "unable to set MCLK rate\n"); -+ } - return ret; - } - - static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) - { -+ int ret; - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *channels = hw_param_interval(params, -@@ -240,8 +353,39 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, - rate->min = rate->max = 48000; - channels->min = channels->max = 2; - -- /* set SSP2 to 24-bit */ -- params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); -+ if ((cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1) || -+ (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) { -+ -+ /* set SSP0 to 16-bit */ -+ params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); -+ -+ /* -+ * Default mode for SSP configuration is TDM 4 slot, override config -+ * with explicit setting to I2S 2ch 16-bit. The word length is set with -+ * dai_set_tdm_slot() since there is no other API exposed -+ */ -+ ret = snd_soc_dai_set_fmt(rtd->cpu_dai, -+ SND_SOC_DAIFMT_I2S | -+ SND_SOC_DAIFMT_NB_IF | -+ SND_SOC_DAIFMT_CBS_CFS -+ ); -+ if (ret < 0) { -+ dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); -+ return ret; -+ } -+ -+ ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 16); -+ if (ret < 0) { -+ dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); -+ return ret; -+ } -+ -+ } else { -+ -+ /* set SSP2 to 24-bit */ -+ params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); -+ -+ } - return 0; - } - -@@ -344,10 +488,31 @@ static struct snd_soc_card snd_soc_card_chtrt5650 = { - static struct cht_acpi_card snd_soc_cards[] = { - {"10EC5640", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645}, - {"10EC5645", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645}, -+ {"10EC5648", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645}, -+ {"10EC3270", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645}, - {"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650}, - }; - --static char cht_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */ -+static char cht_rt5645_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */ -+static char cht_rt5645_codec_aif_name[12]; /* = "rt5645-aif[1|2]" */ -+static char cht_rt5645_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ -+ -+static bool is_valleyview(void) -+{ -+ static const struct x86_cpu_id cpu_ids[] = { -+ { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */ -+ {} -+ }; -+ -+ if (!x86_match_cpu(cpu_ids)) -+ return false; -+ return true; -+} -+ -+struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ -+ u64 aif_value; /* 1: AIF1, 2: AIF2 */ -+ u64 mclock_value; /* usually 25MHz (0x17d7940), ignored */ -+}; - - static int snd_cht_mc_probe(struct platform_device *pdev) - { -@@ -358,22 +523,33 @@ static int snd_cht_mc_probe(struct platform_device *pdev) - struct sst_acpi_mach *mach; - const char *i2c_name = NULL; - int dai_index = 0; -+ bool found = false; -+ bool is_bytcr = false; - - drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); - if (!drv) - return -ENOMEM; - -+ mach = (&pdev->dev)->platform_data; -+ - for (i = 0; i < ARRAY_SIZE(snd_soc_cards); i++) { -- if (acpi_dev_found(snd_soc_cards[i].codec_id)) { -+ if (acpi_dev_found(snd_soc_cards[i].codec_id) && -+ (!strncmp(snd_soc_cards[i].codec_id, mach->id, 8))) { - dev_dbg(&pdev->dev, - "found codec %s\n", snd_soc_cards[i].codec_id); - card = snd_soc_cards[i].soc_card; - drv->acpi_card = &snd_soc_cards[i]; -+ found = true; - break; - } - } -+ -+ if (!found) { -+ dev_err(&pdev->dev, "No matching HID found in supported list\n"); -+ return -ENODEV; -+ } -+ - card->dev = &pdev->dev; -- mach = card->dev->platform_data; - sprintf(drv->codec_name, "i2c-%s:00", drv->acpi_card->codec_id); - - /* set correct codec name */ -@@ -386,9 +562,105 @@ static int snd_cht_mc_probe(struct platform_device *pdev) - /* fixup codec name based on HID */ - i2c_name = sst_acpi_find_name_from_hid(mach->id); - if (i2c_name != NULL) { -- snprintf(cht_rt5640_codec_name, sizeof(cht_rt5640_codec_name), -+ snprintf(cht_rt5645_codec_name, sizeof(cht_rt5645_codec_name), - "%s%s", "i2c-", i2c_name); -- cht_dailink[dai_index].codec_name = cht_rt5640_codec_name; -+ cht_dailink[dai_index].codec_name = cht_rt5645_codec_name; -+ } -+ -+ /* -+ * swap SSP0 if bytcr is detected -+ * (will be overridden if DMI quirk is detected) -+ */ -+ if (is_valleyview()) { -+ struct sst_platform_info *p_info = mach->pdata; -+ const struct sst_res_info *res_info = p_info->res_info; -+ -+ if (res_info->acpi_ipc_irq_index == 0) -+ is_bytcr = true; -+ } -+ -+ if (is_bytcr) { -+ /* -+ * Baytrail CR platforms may have CHAN package in BIOS, try -+ * to find relevant routing quirk based as done on Windows -+ * platforms. We have to read the information directly from the -+ * BIOS, at this stage the card is not created and the links -+ * with the codec driver/pdata are non-existent -+ */ -+ -+ struct acpi_chan_package chan_package; -+ -+ /* format specified: 2 64-bit integers */ -+ struct acpi_buffer format = {sizeof("NN"), "NN"}; -+ struct acpi_buffer state = {0, NULL}; -+ struct sst_acpi_package_context pkg_ctx; -+ bool pkg_found = false; -+ -+ state.length = sizeof(chan_package); -+ state.pointer = &chan_package; -+ -+ pkg_ctx.name = "CHAN"; -+ pkg_ctx.length = 2; -+ pkg_ctx.format = &format; -+ pkg_ctx.state = &state; -+ pkg_ctx.data_valid = false; -+ -+ pkg_found = sst_acpi_find_package_from_hid(mach->id, &pkg_ctx); -+ if (pkg_found) { -+ if (chan_package.aif_value == 1) { -+ dev_info(&pdev->dev, "BIOS Routing: AIF1 connected\n"); -+ cht_rt5645_quirk |= CHT_RT5645_SSP0_AIF1; -+ } else if (chan_package.aif_value == 2) { -+ dev_info(&pdev->dev, "BIOS Routing: AIF2 connected\n"); -+ cht_rt5645_quirk |= CHT_RT5645_SSP0_AIF2; -+ } else { -+ dev_info(&pdev->dev, "BIOS Routing isn't valid, ignored\n"); -+ pkg_found = false; -+ } -+ } -+ -+ if (!pkg_found) { -+ /* no BIOS indications, assume SSP0-AIF2 connection */ -+ cht_rt5645_quirk |= CHT_RT5645_SSP0_AIF2; -+ } -+ } -+ -+ /* check quirks before creating card */ -+ dmi_check_system(cht_rt5645_quirk_table); -+ log_quirks(&pdev->dev); -+ -+ if ((cht_rt5645_quirk & CHT_RT5645_SSP2_AIF2) || -+ (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) { -+ -+ /* fixup codec aif name */ -+ snprintf(cht_rt5645_codec_aif_name, -+ sizeof(cht_rt5645_codec_aif_name), -+ "%s", "rt5645-aif2"); -+ -+ cht_dailink[dai_index].codec_dai_name = -+ cht_rt5645_codec_aif_name; -+ } -+ -+ if ((cht_rt5645_quirk & CHT_RT5645_SSP0_AIF1) || -+ (cht_rt5645_quirk & CHT_RT5645_SSP0_AIF2)) { -+ -+ /* fixup cpu dai name name */ -+ snprintf(cht_rt5645_cpu_dai_name, -+ sizeof(cht_rt5645_cpu_dai_name), -+ "%s", "ssp0-port"); -+ -+ cht_dailink[dai_index].cpu_dai_name = -+ cht_rt5645_cpu_dai_name; -+ } -+ -+ if (is_valleyview()) { -+ drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); -+ if (IS_ERR(drv->mclk)) { -+ dev_err(&pdev->dev, -+ "Failed to get MCLK from pmc_plt_clk_3: %ld\n", -+ PTR_ERR(drv->mclk)); -+ return PTR_ERR(drv->mclk); -+ } - } - - snd_soc_card_set_drvdata(card, drv); -diff --git a/sound/soc/intel/boards/cht_cx2072x.c b/sound/soc/intel/boards/cht_cx2072x.c -new file mode 100644 -index 000000000000..30a97b201c9a ---- /dev/null -+++ b/sound/soc/intel/boards/cht_cx2072x.c -@@ -0,0 +1,453 @@ -+/* -+ * cht_cx207x.c - ASoc DPCM Machine driver for CherryTrail w/ CX2072x -+ * -+ * Copyright (C) 2016 Intel Corp -+ * Author: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.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; 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 <linux/init.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/acpi.h> -+#include <linux/device.h> -+#include <linux/dmi.h> -+#include <linux/slab.h> -+#include <asm/cpu_device_id.h> -+#include <asm/platform_sst_audio.h> -+#include <linux/clk.h> -+#include <sound/pcm.h> -+#include <sound/pcm_params.h> -+#include <sound/soc.h> -+#include <sound/jack.h> -+#include "../../codecs/cx2072x.h" -+#include "../atom/sst-atom-controls.h" -+#include "../common/sst-acpi.h" -+ -+ -+#define CHT_PLAT_CLK_3_HZ 19200000 -+ -+enum { -+ CHT_CX_DMIC_MAP, -+}; -+ -+#define CHT_CX_MAP(quirk) ((quirk) & 0xff) -+#define CHT_CX_MCLK_EN BIT(16) -+ -+ -+struct cht_mc_private { -+ struct clk *mclk; -+}; -+ -+static unsigned long cht_cx_quirk = CHT_CX_MCLK_EN; -+ -+#define BYT_CODEC_DAI1 "cx2072x-hifi" -+ -+static inline struct snd_soc_dai *byt_get_codec_dai(struct snd_soc_card *card) -+{ -+ struct snd_soc_pcm_runtime *rtd; -+ -+ list_for_each_entry(rtd, &card->rtd_list, list) { -+ if (!strncmp(rtd->codec_dai->name, BYT_CODEC_DAI1, -+ strlen(BYT_CODEC_DAI1))) -+ return rtd->codec_dai; -+ } -+ return NULL; -+} -+ -+static int platform_clock_control(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *k, int event) -+{ -+ struct snd_soc_dapm_context *dapm = w->dapm; -+ struct snd_soc_card *card = dapm->card; -+ struct snd_soc_dai *codec_dai; -+ struct cht_mc_private *priv = snd_soc_card_get_drvdata(card); -+ int ret; -+ -+ codec_dai = byt_get_codec_dai(card); -+ if (!codec_dai) { -+ dev_err(card->dev, -+ "Codec dai not found; Unable to set platform clock\n"); -+ return -EIO; -+ } -+ -+ if (SND_SOC_DAPM_EVENT_ON(event)) { -+ if ((cht_cx_quirk & CHT_CX_MCLK_EN) && priv->mclk) { -+ ret = clk_prepare_enable(priv->mclk); -+ if (ret < 0) { -+ dev_err(card->dev, -+ "could not configure MCLK state"); -+ return ret; -+ } -+ } -+ ret = snd_soc_dai_set_sysclk(codec_dai, CX2072X_MCLK_EXTERNAL_PLL, -+ 19200000, SND_SOC_CLOCK_IN); -+ } else { -+ /* -+ * Set codec clock source to internal clock before -+ * turning off the platform clock. Codec needs clock -+ * for Jack detection and button press -+ */ -+ -+ /* FIXME: what is the internal setting, if any? */ -+ ret = snd_soc_dai_set_sysclk(codec_dai, CX2072X_MCLK_EXTERNAL_PLL, -+ 19200000, SND_SOC_CLOCK_IN); -+ -+ if (!ret) { -+ if ((cht_cx_quirk & CHT_CX_MCLK_EN) && priv->mclk) -+ clk_disable_unprepare(priv->mclk); -+ } -+ } -+ -+ if (ret < 0) { -+ dev_err(card->dev, "can't set codec sysclk: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { -+ SND_SOC_DAPM_HP("Headphone", NULL), -+ SND_SOC_DAPM_MIC("Headset Mic", NULL), -+ SND_SOC_DAPM_MIC("Int Mic", NULL), -+ SND_SOC_DAPM_SPK("Ext Spk", NULL), -+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, -+ platform_clock_control, SND_SOC_DAPM_PRE_PMU | -+ SND_SOC_DAPM_POST_PMD), -+}; -+ -+static const struct snd_soc_dapm_route cht_audio_map[] = { -+ /* External Speakers: HFL, HFR */ -+ {"Headphone", NULL, "PORTA"}, -+ {"Ext Spk", NULL, "PORTG"}, -+ {"PORTC", NULL, "Int Mic"}, -+ /* Headset Mic: Headset Mic with bias */ -+ {"PORTD", NULL, "Headset Mic"}, -+ /*{"Headset Bias", NULL, "Headset Mic"},*/ -+ /*{"PortD Mic Bias", NULL, "Headset Mic"},*/ -+ -+ /* Headset Stereophone(Headphone): HSOL, HSOR */ -+ //{"Headphone", NULL, "HPL"}, -+ //{"Headphone", NULL, "HPR"}, -+ -+ {"Playback", NULL, "ssp2 Tx"}, -+ {"ssp2 Tx", NULL, "codec_out0"}, -+ {"ssp2 Tx", NULL, "codec_out1"}, -+ {"codec_in0", NULL, "ssp2 Rx"}, -+ {"codec_in1", NULL, "ssp2 Rx"}, -+ {"ssp2 Rx", NULL, "Capture"}, -+ {"ssp0 Tx", NULL, "modem_out"}, -+ {"modem_in", NULL, "ssp0 Rx"}, -+ {"Playback", NULL, "Platform Clock"}, -+ {"Capture", NULL, "Platform Clock"}, -+}; -+ -+static const struct snd_kcontrol_new cht_mc_controls[] = { -+ SOC_DAPM_PIN_SWITCH("Headphone"), -+ SOC_DAPM_PIN_SWITCH("Headset Mic"), -+ SOC_DAPM_PIN_SWITCH("Int Mic"), -+ SOC_DAPM_PIN_SWITCH("Ext Spk"), -+}; -+ -+static int cht_aif1_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_dai *codec_dai = rtd->codec_dai; -+ int ret; -+ -+ ret = snd_soc_dai_set_sysclk(codec_dai, CX2072X_MCLK_EXTERNAL_PLL, -+ 19200000, SND_SOC_CLOCK_IN); -+ if (ret < 0) { -+ dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret); -+ return ret; -+ } -+ -+ /* FIXME: No need PLL for conexant codec */ -+#if 0 -+ ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK, -+ CHT_PLAT_CLK_3_HZ, rate * 512); -+ if (ret < 0) { -+ dev_err(rtd->dev, "can't set codec pll: %d\n", ret); -+ return ret; -+ } -+#endif -+ -+ -+ return 0; -+} -+ -+static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) -+{ -+ int ret=0; -+ struct snd_soc_card *card = runtime->card; -+ struct cht_mc_private *priv = snd_soc_card_get_drvdata(runtime->card); -+ -+ card->dapm.idle_bias_off = true; -+ -+ /* FIXME: is this necessary */ -+// snd_soc_dapm_ignore_suspend(&codec->dapm, "PortD"); -+// snd_soc_dapm_enable_pin(&card->dapm, "Headset Mic"); -+// snd_soc_dapm_enable_pin(&card->dapm, "Headphone"); -+// snd_soc_dapm_enable_pin(&card->dapm, "Ext Spk"); -+// snd_soc_dapm_enable_pin(&card->dapm, "Int Mic"); -+ -+// snd_soc_dapm_sync(&card->dapm); -+ -+ if ((cht_cx_quirk & CHT_CX_MCLK_EN) && priv->mclk) { -+ /* -+ * The firmware might enable the clock at -+ * boot (this information may or may not -+ * be reflected in the enable clock register). -+ * To change the rate we must disable the clock -+ * first to cover these cases. Due to common -+ * clock framework restrictions that do not allow -+ * to disable a clock that has not been enabled, -+ * we need to enable the clock first. -+ */ -+ ret = clk_prepare_enable(priv->mclk); -+ if (!ret) -+ clk_disable_unprepare(priv->mclk); -+ -+ ret = clk_set_rate(priv->mclk, 19200000); -+ -+ if (ret) -+ dev_err(card->dev, "unable to set MCLK rate\n"); -+ } -+ -+ return ret; -+} -+ -+static const struct snd_soc_pcm_stream cht_dai_params = { -+ .formats = SNDRV_PCM_FMTBIT_S24_LE, -+ .rate_min = 48000, -+ .rate_max = 48000, -+ .channels_min = 2, -+ .channels_max = 2, -+}; -+ -+static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_interval *rate = hw_param_interval(params, -+ SNDRV_PCM_HW_PARAM_RATE); -+ struct snd_interval *channels = hw_param_interval(params, -+ SNDRV_PCM_HW_PARAM_CHANNELS); -+ int ret; -+ -+ /* The DSP will covert the FE rate to 48k, stereo, 24bits */ -+ rate->min = rate->max = 48000; -+ channels->min = channels->max = 2; -+ -+ /* set SSP2 to 24-bit */ -+ params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); -+ -+ /* -+ * Default mode for SSP configuration is TDM 4 slot, override config -+ * with explicit setting to I2S 2ch 24-bit. The word length is set with -+ * dai_set_tdm_slot() since there is no other API exposed -+ */ -+ ret = snd_soc_dai_set_fmt(rtd->cpu_dai, -+ SND_SOC_DAIFMT_I2S | -+ SND_SOC_DAIFMT_NB_IF | -+ SND_SOC_DAIFMT_CBS_CFS); -+ if (ret < 0) { -+ dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static const struct snd_soc_pcm_stream cht_cx_dai_params = { -+ .formats = SNDRV_PCM_FMTBIT_S24_LE, -+ .rate_min = 48000, -+ .rate_max = 48000, -+ .channels_min = 2, -+ .channels_max = 2, -+}; -+ -+static int cht_aif1_startup(struct snd_pcm_substream *substream) -+{ -+ return snd_pcm_hw_constraint_single(substream->runtime, -+ SNDRV_PCM_HW_PARAM_RATE, 48000); -+} -+ -+static struct snd_soc_ops cht_aif1_ops = { -+ .startup = cht_aif1_startup, -+}; -+ -+static struct snd_soc_ops cht_be_ssp2_ops = { -+ .hw_params = cht_aif1_hw_params, -+}; -+ -+static struct snd_soc_dai_link cht_dailink[] = { -+ [MERR_DPCM_AUDIO] = { -+ .name = "Audio Port", -+ .stream_name = "Audio", -+ .cpu_dai_name = "media-cpu-dai", -+ .codec_dai_name = "snd-soc-dummy-dai", -+ .codec_name = "snd-soc-dummy", -+ .platform_name = "sst-mfld-platform", -+ .nonatomic = true, -+ .dynamic = 1, -+ .dpcm_playback = 1, -+ .dpcm_capture = 1, -+ .ops = &cht_aif1_ops, -+ }, -+ [MERR_DPCM_DEEP_BUFFER] = { -+ .name = "Deep-Buffer Audio Port", -+ .stream_name = "Deep-Buffer Audio", -+ .cpu_dai_name = "deepbuffer-cpu-dai", -+ .codec_dai_name = "snd-soc-dummy-dai", -+ .codec_name = "snd-soc-dummy", -+ .platform_name = "sst-mfld-platform", -+ .nonatomic = true, -+ .dynamic = 1, -+ .dpcm_playback = 1, -+ .ops = &cht_aif1_ops, -+ }, -+ [MERR_DPCM_COMPR] = { -+ .name = "Compressed Port", -+ .stream_name = "Compress", -+ .cpu_dai_name = "compress-cpu-dai", -+ .codec_dai_name = "snd-soc-dummy-dai", -+ .codec_name = "snd-soc-dummy", -+ .platform_name = "sst-mfld-platform", -+ }, -+ /* CODEC<->CODEC link */ -+ /* back ends */ -+ { -+ .name = "SSP2-Codec", -+ .id = 1, -+ .cpu_dai_name = "ssp2-port", -+ .platform_name = "sst-mfld-platform", -+ .no_pcm = 1, -+ .codec_dai_name = "cx2072x-hifi", -+ .codec_name = "i2c-14F10720:00", -+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF -+ | SND_SOC_DAIFMT_CBS_CFS, -+ .init = cht_codec_init, -+ .be_hw_params_fixup = cht_codec_fixup, -+ .nonatomic = true, -+ .dpcm_playback = 1, -+ .dpcm_capture = 1, -+ .ops = &cht_be_ssp2_ops, -+ }, -+}; -+ -+/* SoC card */ -+static struct snd_soc_card chtcx2072x_card = { -+ .name = "chtcx2072x", -+ .dai_link = cht_dailink, -+ .num_links = ARRAY_SIZE(cht_dailink), -+ .dapm_widgets = cht_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets), -+ .dapm_routes = cht_audio_map, -+ .num_dapm_routes = ARRAY_SIZE(cht_audio_map), -+ .controls = cht_mc_controls, -+ .num_controls = ARRAY_SIZE(cht_mc_controls), -+}; -+ -+static char cht_cx_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */ -+ -+static bool is_valleyview(void) -+{ -+ static const struct x86_cpu_id cpu_ids[] = { -+ { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */ -+ {} -+ }; -+ -+ if (!x86_match_cpu(cpu_ids)) -+ return false; -+ return true; -+} -+ -+static int snd_cht_mc_probe(struct platform_device *pdev) -+{ -+ int ret_val = 0; -+ int i; -+ int dai_index; -+ struct cht_mc_private *drv; -+ struct sst_acpi_mach *mach; -+ const char *i2c_name = NULL; -+ -+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); -+ if (!drv) { -+ pr_err("allocation failed\n"); -+ return -ENOMEM; -+ } -+ -+ /* register the soc card */ -+ chtcx2072x_card.dev = &pdev->dev; -+ mach = chtcx2072x_card.dev->platform_data; -+ snd_soc_card_set_drvdata(&chtcx2072x_card, drv); -+ -+ /* fix index of codec dai */ -+ dai_index = MERR_DPCM_COMPR + 1; -+ for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { -+ if (!strcmp(cht_dailink[i].codec_name, "i2c-14F10720:00")) { -+ dai_index = i; -+ break; -+ } -+ } -+ -+ /* fixup codec name based on HID */ -+ i2c_name = sst_acpi_find_name_from_hid(mach->id); -+ if (i2c_name != NULL) { -+ snprintf(cht_cx_codec_name, sizeof(cht_cx_codec_name), -+ "%s%s", "i2c-", i2c_name); -+ -+ cht_dailink[dai_index].codec_name = cht_cx_codec_name; -+ } -+ -+ if ((cht_cx_quirk & CHT_CX_MCLK_EN) && (is_valleyview())) { -+ drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); -+ if (IS_ERR(drv->mclk)) { -+ dev_err(&pdev->dev, -+ "Failed to get MCLK from pmc_plt_clk_3: %ld\n", -+ PTR_ERR(drv->mclk)); -+ -+ return PTR_ERR(drv->mclk); -+ } -+ } -+ -+ ret_val = devm_snd_soc_register_card(&pdev->dev, &chtcx2072x_card); -+ -+ if (ret_val) { -+ dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", -+ ret_val); -+ return ret_val; -+ } -+ platform_set_drvdata(pdev, &chtcx2072x_card); -+ return ret_val; -+} -+ -+ -+ -+static struct platform_driver snd_cht_mc_driver = { -+ .driver = { -+ .name = "cht-cx2072x", -+ .pm = &snd_soc_pm_ops, -+ }, -+ .probe = snd_cht_mc_probe, -+}; -+module_platform_driver(snd_cht_mc_driver); -+ -+MODULE_DESCRIPTION("ASoC Intel(R) Cherrytrail Machine driver"); -+MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>"); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:cht-cx2072x"); -diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h -index 012742299dd5..214e000667ae 100644 ---- a/sound/soc/intel/common/sst-acpi.h -+++ b/sound/soc/intel/common/sst-acpi.h -@@ -15,14 +15,29 @@ - #include <linux/stddef.h> - #include <linux/acpi.h> - --/* translation fron HID to I2C name, needed for DAI codec_name */ -+struct sst_acpi_package_context { -+ char *name; /* package name */ -+ int length; /* number of elements */ -+ struct acpi_buffer *format; -+ struct acpi_buffer *state; -+ bool data_valid; -+}; -+ - #if IS_ENABLED(CONFIG_ACPI) -+/* translation fron HID to I2C name, needed for DAI codec_name */ - const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]); -+bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], -+ struct sst_acpi_package_context *ctx); - #else - static inline const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]) - { - return NULL; - } -+static inline bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], -+ struct sst_acpi_package_context *ctx) -+{ -+ return false; -+} - #endif - - /* acpi match */ -diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c -index 789843307a49..1070f3ad23e5 100644 ---- a/sound/soc/intel/common/sst-match-acpi.c -+++ b/sound/soc/intel/common/sst-match-acpi.c -@@ -77,5 +77,62 @@ struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines) - } - EXPORT_SYMBOL_GPL(sst_acpi_find_machine); - -+static acpi_status sst_acpi_find_package(acpi_handle handle, u32 level, -+ void *context, void **ret) -+{ -+ struct acpi_device *adev; -+ acpi_status status = AE_OK; -+ struct sst_acpi_package_context *pkg_ctx = context; -+ -+ pkg_ctx->data_valid = false; -+ -+ if (acpi_bus_get_device(handle, &adev)) -+ return AE_OK; -+ -+ if (adev->status.present && adev->status.functional) { -+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; -+ union acpi_object *myobj = NULL; -+ -+ status = acpi_evaluate_object_typed(handle, pkg_ctx->name, -+ NULL, &buffer, -+ ACPI_TYPE_PACKAGE); -+ if (ACPI_FAILURE(status)) -+ return AE_OK; -+ -+ myobj = buffer.pointer; -+ if (!myobj || myobj->package.count != pkg_ctx->length) { -+ kfree(buffer.pointer); -+ return AE_OK; -+ } -+ -+ status = acpi_extract_package(myobj, -+ pkg_ctx->format, pkg_ctx->state); -+ if (ACPI_FAILURE(status)) { -+ kfree(buffer.pointer); -+ return AE_OK; -+ } -+ -+ kfree(buffer.pointer); -+ pkg_ctx->data_valid = true; -+ return AE_CTRL_TERMINATE; -+ } -+ -+ return AE_OK; -+} -+ -+bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], -+ struct sst_acpi_package_context *ctx) -+{ -+ acpi_status status; -+ -+ status = acpi_get_devices(hid, sst_acpi_find_package, ctx, NULL); -+ -+ if (ACPI_FAILURE(status) || !ctx->data_valid) -+ return false; -+ -+ return true; -+} -+EXPORT_SYMBOL_GPL(sst_acpi_find_package_from_hid); -+ - MODULE_LICENSE("GPL v2"); - MODULE_DESCRIPTION("Intel Common ACPI Match module"); |