<commit_before>/*
 * wm8775 - driver version 0.0.1
 *
 * Copyright (C) 2004 <NAME> <ivtv at eklund.to>
 *
 * Based on saa7115 driver
 *
 * Copyright (C) 2005 <NAME> <<EMAIL>>
 * - Cleanup
 * - V4L2 API update
 * - sound fixes
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/module.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
#include <media/wm8775.h>

MODULE_DESCRIPTION("wm8775 driver");
MODULE_AUTHOR("<NAME>, <NAME>");
MODULE_LICENSE("GPL");



/* ----------------------------------------------------------------------- */

enum {
	R7 = 7, R11 = 11,
	R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R23 = 23,
	TOT_REGS
};

#define ALC_HOLD 0x85 /* R17: use zero cross detection, ALC hold time 42.6 ms */
#define ALC_EN 0x100  /* R17: ALC enable */

struct wm8775_state {
	struct v4l2_subdev sd;
	struct v4l2_ctrl_handler hdl;
	struct v4l2_ctrl *mute;
	struct v4l2_ctrl *vol;
	struct v4l2_ctrl *bal;
	struct v4l2_ctrl *loud;
	u8 input;		/* Last selected input (0-0xf) */
};

static inline struct wm8775_state *to_state(struct v4l2_subdev *sd)
{
	return container_of(sd, struct wm8775_state, sd);
}

static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
{
	return &container_of(ctrl->handler, struct wm8775_state, hdl)->sd;
}

static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	int i;

	if (reg < 0 || reg >= TOT_REGS) {
		v4l2_err(sd, "Invalid register R%d\n", reg);
		return -1;
	}

	for (i = 0; i < 3; i++)
		if (i2c_smbus_write_byte_data(client,
				(reg << 1) | (val >> 8), val & 0xff) == 0)
			return 0;
	v4l2_err(sd, "I2C: cannot write %03x to register R%d\n", val, reg);
	return -1;
}

static void wm8775_set_audio(struct v4l2_subdev *sd, int quietly)
{
	struct wm8775_state *state = to_state(sd);
	u8 vol_l, vol_r;
	int muted = 0 != state->mute->val;
	u16 volume = (u16)state->vol->val;
	u16 balance = (u16)state->bal->val;

	/* normalize ( 65535 to 0 -> 255 to 0 (+24dB to -103dB) ) */
	vol_l = (min(65536 - balance, 32768) * volume) >> 23;
	vol_r = (min(balance, (u16)32768) * volume) >> 23;

	/* Mute */
	if (muted || quietly)
		wm8775_write(sd, R21, 0x0c0 | state->input);

	wm8775_write(sd, R14, vol_l | 0x100); /* 0x100= Left channel ADC zero cross enable */
	wm8775_write(sd, R15, vol_r | 0x100); /* 0x100= Right channel ADC zero cross enable */

	/* Un-mute */
	if (!muted)
		wm8775_write(sd, R21, state->input);
}

static int wm8775_s_routing(struct v4l2_subdev *sd,
			    u32 input, u32 output, u32 config)
{
	struct wm8775_state *state = to_state(sd);

	/* There are 4 inputs and one output. Zero or more inputs
	   are multiplexed together to the output. Hence there are
	   16 combinations.
	   If only one input is active (the normal case) then the
	   input values 1, 2, 4 or 8 should be used. */
	if (input > 15) {
		v4l2_err(sd, "Invalid input %d.\n", input);
		return -EINVAL;
	}
	state->input = input;
	if (!v4l2_ctrl_g_ctrl(state->mute))
		return 0;
	if (!v4l2_ctrl_g_ctrl(state->vol))
		return 0;
	if (!v4l2_ctrl_g_ctrl(state->bal))
		return 0;
	wm8775_set_audio(sd, 1);
	return 0;
}

static int wm8775_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct v4l2_subdev *sd = to_sd(ctrl);

	switch (ctrl->id) {
	case V4L2_CID_AUDIO_MUTE:
	case V4L2_CID_AUDIO_VOLUME:
	case V4L2_CID_AUDIO_BALANCE:
		wm8775_set_audio(sd, 0);
		return 0;
	case V4L2_CID_AUDIO_LOUDNESS:
		wm8775_write(sd, R17, (ctrl->val ? ALC_EN : 0) | ALC_HOLD);
		return 0;
	}
	return -EINVAL;
}

static int wm8775_log_status(struct v4l2_subdev *sd)
{
	struct wm8775_state *state = to_state(sd);
<commit_msg>[media] wm8775: fix broken audio routing<commit_after>/*
 * wm8775 - driver version 0.0.1
 *
 * Copyright (C) 2004 <NAME> <ivtv at eklund.to>
 *
 * Based on saa7115 driver
 *
 * Copyright (C) 2005 <NAME> <<EMAIL>>
 * - Cleanup
 * - V4L2 API update
 * - sound fixes
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <linux/module.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
#include <media/wm8775.h>

MODULE_DESCRIPTION("wm8775 driver");
MODULE_AUTHOR("<NAME>, <NAME>");
MODULE_LICENSE("GPL");



/* ----------------------------------------------------------------------- */

enum {
	R7 = 7, R11 = 11,
	R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R23 = 23,
	TOT_REGS
};

#define ALC_HOLD 0x85 /* R17: use zero cross detection, ALC hold time 42.6 ms */
#define ALC_EN 0x100  /* R17: ALC enable */

struct wm8775_state {
	struct v4l2_subdev sd;
	struct v4l2_ctrl_handler hdl;
	struct v4l2_ctrl *mute;
	struct v4l2_ctrl *vol;
	struct v4l2_ctrl *bal;
	struct v4l2_ctrl *loud;
	u8 input;		/* Last selected input (0-0xf) */
};

static inline struct wm8775_state *to_state(struct v4l2_subdev *sd)
{
	return container_of(sd, struct wm8775_state, sd);
}

static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
{
	return &container_of(ctrl->handler, struct wm8775_state, hdl)->sd;
}

static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	int i;

	if (reg < 0 || reg >= TOT_REGS) {
		v4l2_err(sd, "Invalid register R%d\n", reg);
		return -1;
	}

	for (i = 0; i < 3; i++)
		if (i2c_smbus_write_byte_data(client,
				(reg << 1) | (val >> 8), val & 0xff) == 0)
			return 0;
	v4l2_err(sd, "I2C: cannot write %03x to register R%d\n", val, reg);
	return -1;
}

static void wm8775_set_audio(struct v4l2_subdev *sd, int quietly)
{
	struct wm8775_state *state = to_state(sd);
	u8 vol_l, vol_r;
	int muted = 0 != state->mute->val;
	u16 volume = (u16)state->vol->val;
	u16 balance = (u16)state->bal->val;

	/* normalize ( 65535 to 0 -> 255 to 0 (+24dB to -103dB) ) */
	vol_l = (min(65536 - balance, 32768) * volume) >> 23;
	vol_r = (min(balance, (u16)32768) * volume) >> 23;

	/* Mute */
	if (muted || quietly)
		wm8775_write(sd, R21, 0x0c0 | state->input);

	wm8775_write(sd, R14, vol_l | 0x100); /* 0x100= Left channel ADC zero cross enable */
	wm8775_write(sd, R15, vol_r | 0x100); /* 0x100= Right channel ADC zero cross enable */

	/* Un-mute */
	if (!muted)
		wm8775_write(sd, R21, state->input);
}

static int wm8775_s_routing(struct v4l2_subdev *sd,
			    u32 input, u32 output, u32 config)
{
	struct wm8775_state *state = to_state(sd);

	/* There are 4 inputs and one output. Zero or more inputs
	   are multiplexed together to the output. Hence there are
	   16 combinations.
	   If only one input is active (the normal case) then the
	   input values 1, 2, 4 or 8 should be used. */
	if (input > 15) {
		v4l2_err(sd, "Invalid input %d.\n", input);
		return -EINVAL;
	}
	state->input = input;
	if (v4l2_ctrl_g_ctrl(state->mute))
		return 0;
	if (!v4l2_ctrl_g_ctrl(state->vol))
		return 0;
	wm8775_set_audio(sd, 1);
	return 0;
}

static int wm8775_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct v4l2_subdev *sd = to_sd(ctrl);

	switch (ctrl->id) {
	case V4L2_CID_AUDIO_MUTE:
	case V4L2_CID_AUDIO_VOLUME:
	case V4L2_CID_AUDIO_BALANCE:
		wm8775_set_audio(sd, 0);
		return 0;
	case V4L2_CID_AUDIO_LOUDNESS:
		wm8775_write(sd, R17, (ctrl->val ? ALC_EN : 0) | ALC_HOLD);
		return 0;
	}
	return -EINVAL;
}

static int wm8775_log_status(struct v4l2_subdev *sd)
{
	struct wm8775_state *state = to_state(sd);

{'fraction_non_alphanumeric': 0.14058956916099774, 'fraction_numerical': 0.07607709750566893, 'mean_word_length': 3.6377497371188223, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 86, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6581774', 'n_tokens_mistral': 3929, 'n_tokens_neox': 3508, 'n_words': 1033}