162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2010 ASIX Electronics Corporation
462306a36Sopenharmony_ci * Copyright (c) 2020 Samsung Electronics Co., Ltd.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * ASIX AX88796C SPI Fast Ethernet Linux driver
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#define pr_fmt(fmt)	"ax88796c: " fmt
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/string.h>
1262306a36Sopenharmony_ci#include <linux/spi/spi.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "ax88796c_spi.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ciconst u8 ax88796c_rx_cmd_buf[5] = {AX_SPICMD_READ_RXQ, 0xFF, 0xFF, 0xFF, 0xFF};
1762306a36Sopenharmony_ciconst u8 ax88796c_tx_cmd_buf[4] = {AX_SPICMD_WRITE_TXQ, 0xFF, 0xFF, 0xFF};
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/* driver bus management functions */
2062306a36Sopenharmony_ciint axspi_wakeup(struct axspi_data *ax_spi)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	int ret;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	ax_spi->cmd_buf[0] = AX_SPICMD_EXIT_PWD;	/* OP */
2562306a36Sopenharmony_ci	ret = spi_write(ax_spi->spi, ax_spi->cmd_buf, 1);
2662306a36Sopenharmony_ci	if (ret)
2762306a36Sopenharmony_ci		dev_err(&ax_spi->spi->dev, "%s() failed: ret = %d\n", __func__, ret);
2862306a36Sopenharmony_ci	return ret;
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ciint axspi_read_status(struct axspi_data *ax_spi, struct spi_status *status)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	int ret;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	/* OP */
3662306a36Sopenharmony_ci	ax_spi->cmd_buf[0] = AX_SPICMD_READ_STATUS;
3762306a36Sopenharmony_ci	ret = spi_write_then_read(ax_spi->spi, ax_spi->cmd_buf, 1, (u8 *)status, 3);
3862306a36Sopenharmony_ci	if (ret)
3962306a36Sopenharmony_ci		dev_err(&ax_spi->spi->dev, "%s() failed: ret = %d\n", __func__, ret);
4062306a36Sopenharmony_ci	else
4162306a36Sopenharmony_ci		le16_to_cpus(&status->isr);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	return ret;
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ciint axspi_read_rxq(struct axspi_data *ax_spi, void *data, int len)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	struct spi_transfer *xfer = ax_spi->spi_rx_xfer;
4962306a36Sopenharmony_ci	int ret;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	memcpy(ax_spi->cmd_buf, ax88796c_rx_cmd_buf, 5);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	xfer->tx_buf = ax_spi->cmd_buf;
5462306a36Sopenharmony_ci	xfer->rx_buf = NULL;
5562306a36Sopenharmony_ci	xfer->len = ax_spi->comp ? 2 : 5;
5662306a36Sopenharmony_ci	xfer->bits_per_word = 8;
5762306a36Sopenharmony_ci	spi_message_add_tail(xfer, &ax_spi->rx_msg);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	xfer++;
6062306a36Sopenharmony_ci	xfer->rx_buf = data;
6162306a36Sopenharmony_ci	xfer->tx_buf = NULL;
6262306a36Sopenharmony_ci	xfer->len = len;
6362306a36Sopenharmony_ci	xfer->bits_per_word = 8;
6462306a36Sopenharmony_ci	spi_message_add_tail(xfer, &ax_spi->rx_msg);
6562306a36Sopenharmony_ci	ret = spi_sync(ax_spi->spi, &ax_spi->rx_msg);
6662306a36Sopenharmony_ci	if (ret)
6762306a36Sopenharmony_ci		dev_err(&ax_spi->spi->dev, "%s() failed: ret = %d\n", __func__, ret);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	return ret;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ciint axspi_write_txq(const struct axspi_data *ax_spi, void *data, int len)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	return spi_write(ax_spi->spi, data, len);
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ciu16 axspi_read_reg(struct axspi_data *ax_spi, u8 reg)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	int ret;
8062306a36Sopenharmony_ci	int len = ax_spi->comp ? 3 : 4;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	ax_spi->cmd_buf[0] = 0x03;	/* OP code read register */
8362306a36Sopenharmony_ci	ax_spi->cmd_buf[1] = reg;	/* register address */
8462306a36Sopenharmony_ci	ax_spi->cmd_buf[2] = 0xFF;	/* dumy cycle */
8562306a36Sopenharmony_ci	ax_spi->cmd_buf[3] = 0xFF;	/* dumy cycle */
8662306a36Sopenharmony_ci	ret = spi_write_then_read(ax_spi->spi,
8762306a36Sopenharmony_ci				  ax_spi->cmd_buf, len,
8862306a36Sopenharmony_ci				  ax_spi->rx_buf, 2);
8962306a36Sopenharmony_ci	if (ret) {
9062306a36Sopenharmony_ci		dev_err(&ax_spi->spi->dev,
9162306a36Sopenharmony_ci			"%s() failed: ret = %d\n", __func__, ret);
9262306a36Sopenharmony_ci		return 0xFFFF;
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	le16_to_cpus((u16 *)ax_spi->rx_buf);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	return *(u16 *)ax_spi->rx_buf;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ciint axspi_write_reg(struct axspi_data *ax_spi, u8 reg, u16 value)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	int ret;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	memset(ax_spi->cmd_buf, 0, sizeof(ax_spi->cmd_buf));
10562306a36Sopenharmony_ci	ax_spi->cmd_buf[0] = AX_SPICMD_WRITE_REG;	/* OP code read register */
10662306a36Sopenharmony_ci	ax_spi->cmd_buf[1] = reg;			/* register address */
10762306a36Sopenharmony_ci	ax_spi->cmd_buf[2] = value;
10862306a36Sopenharmony_ci	ax_spi->cmd_buf[3] = value >> 8;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	ret = spi_write(ax_spi->spi, ax_spi->cmd_buf, 4);
11162306a36Sopenharmony_ci	if (ret)
11262306a36Sopenharmony_ci		dev_err(&ax_spi->spi->dev, "%s() failed: ret = %d\n", __func__, ret);
11362306a36Sopenharmony_ci	return ret;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
116