/* * Copyright (c) 2016 Samsung Electronics Co., Ltd. * http://www.samsung.com * * 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. */ #include #include #include #include #include #include extern struct device_node *acpm_mfd_node; static DEFINE_MUTEX(acpm_mfd_lock); int exynos_acpm_read_reg(u16 type, u8 reg, u8 *dest) { unsigned int channel_num, size; struct ipc_config config; unsigned int command[4] = {0,}; int ret = 0; mutex_lock(&acpm_mfd_lock); if (!acpm_ipc_request_channel(acpm_mfd_node, NULL, &channel_num, &size)) { config.cmd = command; config.cmd[0] = set_protocol(type, TYPE) | set_protocol(reg, REG); config.cmd[1] = set_protocol(FUNC_READ, FUNC); config.response = true; config.indirection = false; ACPM_MFD_PRINT("%s - addr: 0x%03x\n", __func__, set_protocol(type, TYPE) | set_protocol(reg, REG)); ret = acpm_ipc_send_data(channel_num, &config); if (ret) { pr_err(ACPM_MFD_PREFIX "%s - acpm_ipc_send_data fail.\n", __func__); goto err; } *dest = read_protocol(config.cmd[1], DEST); ret = read_protocol(config.cmd[1], RETURN); if (ret) { pr_err(ACPM_MFD_PREFIX "%s - APM's speedy_rx fail.\n", __func__); goto err; } ACPM_MFD_PRINT("%s - data = 0x%02x ret = 0x%02x\n", __func__, *dest, ret); acpm_ipc_release_channel(acpm_mfd_node, channel_num); } else { pr_err(ACPM_MFD_PREFIX "%s ipc request_channel fail, id:%u, size:%u\n", __func__, channel_num, size); ret = -EBUSY; } err: mutex_unlock(&acpm_mfd_lock); return ret; } int exynos_acpm_bulk_read(u16 type, u8 reg, int count, u8 *buf) { unsigned int channel_num, size; struct ipc_config config; unsigned int command[4] = {0,}; int i, ret = 0; mutex_lock(&acpm_mfd_lock); if (!acpm_ipc_request_channel(acpm_mfd_node, NULL, &channel_num, &size)) { config.cmd = command; config.cmd[0] = set_protocol(type, TYPE) | set_protocol(reg, REG); config.cmd[1] = set_protocol(FUNC_BULK_READ, FUNC) | set_protocol(count, CNT); config.response = true; config.indirection = false; ACPM_MFD_PRINT("%s - addr: 0x%03x\n", __func__, set_protocol(type, TYPE) | set_protocol(reg, REG)); ret = acpm_ipc_send_data(channel_num, &config); if (ret) { pr_err(ACPM_MFD_PREFIX "%s - acpm_ipc_send_data fail.\n", __func__); goto err; } ret = read_protocol(config.cmd[1], RETURN); if (ret) { pr_err(ACPM_MFD_PREFIX "%s - APM's speedy_rx fail.\n", __func__); goto err; } for (i = 0; i < count; i++) { if (i < 4) buf[i] = read_bulk_protocol(config.cmd[2], BULK_VAL, i); else buf[i] = read_bulk_protocol(config.cmd[3], BULK_VAL , i - 4); } acpm_ipc_release_channel(acpm_mfd_node, channel_num); } else { pr_err(ACPM_MFD_PREFIX "%s ipc request_channel fail, id:%u, size:%u\n", __func__, channel_num, size); ret = -EBUSY; } err: mutex_unlock(&acpm_mfd_lock); return ret; } int exynos_acpm_write_reg(u16 type, u8 reg, u8 value) { unsigned int channel_num, size; struct ipc_config config; unsigned int command[4] = {0,}; int ret = 0; mutex_lock(&acpm_mfd_lock); if (!acpm_ipc_request_channel(acpm_mfd_node, NULL, &channel_num, &size)) { config.cmd = command; config.cmd[0] = set_protocol(type, TYPE) | set_protocol(reg, REG); config.cmd[1] = set_protocol(FUNC_WRITE, FUNC) | set_protocol(value, WRITE_VAL); config.response = true; config.indirection = false; ACPM_MFD_PRINT("%s - addr: 0x%03x val: 0x%02x\n", __func__, set_protocol(type, TYPE) | set_protocol(reg, REG), value); ret = acpm_ipc_send_data(channel_num, &config); if (ret) { pr_err(ACPM_MFD_PREFIX "%s - acpm_ipc_send_data fail.\n", __func__); goto err; } ret = read_protocol(config.cmd[1], RETURN); if (ret) { pr_err(ACPM_MFD_PREFIX "%s - APM's speedy_tx fail.\n", __func__); goto err; } ACPM_MFD_PRINT("%s - read(ret) val: 0x%02x\n", __func__, ret); acpm_ipc_release_channel(acpm_mfd_node, channel_num); } else { pr_err(ACPM_MFD_PREFIX "%s ipc request_channel fail, id:%u, size:%u\n", __func__, channel_num, size); ret = -EBUSY; } err: mutex_unlock(&acpm_mfd_lock); return ret; } int exynos_acpm_bulk_write(u16 type, u8 reg, int count, u8 *buf) { unsigned int channel_num, size; struct ipc_config config; unsigned int command[4] = {0,}; int ret = 0; int i; mutex_lock(&acpm_mfd_lock); if (!acpm_ipc_request_channel(acpm_mfd_node, NULL, &channel_num, &size)) { config.cmd = command; config.cmd[0] = set_protocol(type, TYPE) | set_protocol(reg, REG); config.cmd[1] = set_protocol(FUNC_BULK_WRITE, FUNC) | set_protocol(count, CNT); config.response = true; config.indirection = false; ACPM_MFD_PRINT("%s - addr: 0x%03x\n cnt: 0x%02x\n", __func__, set_protocol(type, TYPE) | set_protocol(reg, REG), count); for (i = 0; i < count; i++) { if (i < 4) config.cmd[2] |= set_bulk_protocol(buf[i], BULK_VAL, i); else config.cmd[3] |= set_bulk_protocol(buf[i], BULK_VAL, i - 4); } ret = acpm_ipc_send_data(channel_num, &config); if (ret) { pr_err(ACPM_MFD_PREFIX "%s - acpm_ipc_send_data fail.\n", __func__); goto err; } ret = read_protocol(config.cmd[1], RETURN); if (ret) { pr_err(ACPM_MFD_PREFIX "%s - APM's speedy_tx fail.\n", __func__); goto err; } acpm_ipc_release_channel(acpm_mfd_node, channel_num); } else { pr_err(ACPM_MFD_PREFIX "%s ipc request_channel fail, id:%u, size:%u\n", __func__, channel_num, size); ret = -EBUSY; } err: mutex_unlock(&acpm_mfd_lock); return ret; } int exynos_acpm_update_reg(u16 type, u8 reg, u8 value, u8 mask) { unsigned int channel_num, size; struct ipc_config config; unsigned int command[4] = {0,}; int ret = 0; mutex_lock(&acpm_mfd_lock); if (!acpm_ipc_request_channel(acpm_mfd_node, NULL, &channel_num, &size)) { config.cmd = command; config.cmd[0] = set_protocol(type, TYPE) | set_protocol(reg, REG); config.cmd[1] = set_protocol(FUNC_UPDATE, FUNC) | set_protocol(value, UPDATE_VAL) | set_protocol(mask, UPDATE_MASK); config.response = true; config.indirection = false; ACPM_MFD_PRINT("%s - addr: 0x%03x val: 0x%02x mask: 0x%02x\n", __func__, set_protocol(type, TYPE) | set_protocol(reg, REG), value, mask); ret = acpm_ipc_send_data(channel_num, &config); if (ret) { pr_err(ACPM_MFD_PREFIX "%s - acpm_ipc_send_data fail.\n", __func__); goto err; } ret = read_protocol(config.cmd[1], RETURN); if (ret) { if (ret == 1) pr_err(ACPM_MFD_PREFIX "%s - APM's speedy_rx fail.\n", __func__); else if (ret == 2) pr_err(ACPM_MFD_PREFIX "%s - APM's speedy_tx fail.\n", __func__); goto err; } acpm_ipc_release_channel(acpm_mfd_node, channel_num); } else { pr_err(ACPM_MFD_PREFIX "%s ipc request_channel fail, id:%u, size:%u\n", __func__, channel_num, size); ret = -EBUSY; } err: mutex_unlock(&acpm_mfd_lock); return ret; }