blob: 08a7186768f434bed25b1f21d1e72ba127b5b6ff [file] [log] [blame]
#!/bin/bash
# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# TODO(thutt): Convert to /bin/sh from bash
# TODO(thutt): Lookup board configs by config file installed
# by private overlay.
# TODO(thutt): This scripts makes an assumption that all Arm-based boards use
# WM8903 and that the board will always have the same codec.
#
NAME=$(basename "${0}");
AMIXER=${AMIXER:-"/usr/bin/amixer"};
SLEEP_TIME=${SLEEP_TIME:-"0.5"}; # Seconds to sleep between GPIO checking.
HP_GPIO="185"; # Headphone GPIO.
HP_GPIO_DIR="/sys/class/gpio/gpio${HP_GPIO}";
# This represents the board this image is targeted for.
BOARD="$(cat /etc/lsb-release | grep CHROMEOS_RELEASE_BOARD | cut -d'=' -f2)"
# This is the codec chip we are currently using.
CODEC="$(cat /proc/asound/pcm | head -n1 | cut -d':' -f2 | awk '{print $1}')"
declare active_low; # inv: '0' or '1'.
declare machine_kind; # inv: An element of 'machine_to_codec'.
declare codec; # inv: ${machine_to_codec[${machine_kind}]}
function log ()
{
msg=${1};
logger "${NAME}: ${msg}.";
}
function failure ()
{
msg=${1};
log "Headphone jack cannot be monitored: ${msg}";
false || exit;
}
function get_gpio_attribute ()
{
attribute=${1}; # Pathname of GPIO attribute to read.
shift;
if [ -f "${attribute}" ] ; then
cat "${attribute}";
true && return;
else
echo "";
false || return;
fi;
}
function wm8903_set_output_headphones ()
{
${AMIXER} set 'Speaker' off &>/dev/null
${AMIXER} set 'Int Spk' off &>/dev/null
${AMIXER} set 'Headphone' on &>/dev/null
}
function wm8903_set_output_internal_speaker ()
{
${AMIXER} set 'Speaker' on &>/dev/null
${AMIXER} set 'Int Spk' on &>/dev/null
${AMIXER} set 'Headphone' off &>/dev/null
}
function wm8903_initialize ()
{
# Without enabling DACL, Kaen has no speaker output.
${AMIXER} set 'Speaker' 100% &>/dev/null
${AMIXER} set 'Headphone' 100% &>/dev/null
${AMIXER} set 'Digital' 100% &>/dev/null
${AMIXER} set "Left Speaker Mixer DACL" on &>/dev/null
${AMIXER} set "Right Speaker Mixer DACL" on &>/dev/null
${AMIXER} set 'ADC Input' 'DMIC' &>/dev/null
}
function initialize_codec ()
{
# Board type is found in /etc/lsb-release:
# tegra2_seaboard
# We need to support the audio config per board.
local machine_kind=$BOARD
# Codec type is found in /proc/asound/pcm
# TODO(thutt): We should support more than one codec, and
# support more than one codec per board. Current implementation
# is a stopgap.
codec=""
if [ "$CODEC" = "WM8903" ]; then
codec="wm8903"
fi
if [ -n "${codec}" ] ; then
init_fn="${codec}_initialize";
if declare -f ${init_fn} >/dev/null; then
${init_fn};
else
false;
fi;
else
false;
fi;
}
function multiplex ()
{
local hp_gpio_dir=${1};
local value_pathname="${hp_gpio_dir}/value";
local -a value;
value[1]="-"; # Force mismatch on first loop.
while true ; do
value[0]=${value[1]};
value[1]="$(get_gpio_attribute "${value_pathname}")";
if [ "${value[0]}" != "${value[1]}" ] ; then
# Headphone Jack has changed state.
case "${active_low}${value[1]}" in
"00" ) ${codec}_set_output_headphones; ;;
"01" ) ${codec}_set_output_internal_speaker; ;;
"10" ) ${codec}_set_output_internal_speaker; ;;
"11" ) ${codec}_set_output_headphones; ;;
* ) # Ignore invalid combos.
;;
esac;
fi;
sleep ${SLEEP_TIME};
done;
}
function main ()
{
local hp_gpio_dir=$(readlink --canonicalize "${HP_GPIO_DIR}");
if [ ! -d "${hp_gpio_dir}" ] ; then
failure "'${HP_GPIO_DIR}' does not exist";
fi;
active_low=$(get_gpio_attribute "${hp_gpio_dir}/active_low");
if [ -z "${active_low}" ] ; then
failure "Unable to determine active low or active high";
fi;
multiplex ${hp_gpio_dir}
}
if initialize_codec ; then
main;
else
log "Unknown machine / sound codec combo; headphone jack not managed."
fi;
true && exit;