Merge commit '3a8b94c5be2ca4a2a9dd5916074e2f466ebcc57f'

* commit '3a8b94c5be2ca4a2a9dd5916074e2f466ebcc57f':
  arm64: dts: rockchip: rv1126b: Remove dma for i2c0, i2c4 and i2c5
  dt-bindings: i2c: rockchip: add rockchip,rv1126b-i2c
  i2c: rk3x: Add dma feature
  arm64: dts: rockchip: rv1126b-evb: Change clock rates to 24M for fephy
  ethernet: stmmac: dwmac-rk: Correct clock input/output sel for RV1126B
  net: phy: rockchip-fephy: Add param to access group registers
  net: phy: rockchip-fephy: Fix for the correct names
  net: phy: rockchip-fephy: Add 24M clock rate setting
  net: phy: rockchip-fephy: Change off-energy level0 threshold between link up/down

Change-Id: I93555893bf14d5c358c0e583917daeae6295b483
This commit is contained in:
Tao Huang
2025-05-25 17:13:21 +08:00
8 changed files with 818 additions and 90 deletions

View File

@@ -21,6 +21,7 @@ properties:
compatible:
oneOf:
- const: rockchip,rv1108-i2c
- const: rockchip,rv1126b-i2c
- const: rockchip,rk3066-i2c
- const: rockchip,rk3188-i2c
- const: rockchip,rk3228-i2c

View File

@@ -325,7 +325,7 @@
compatible = "ethernet-phy-id0680.8101", "ethernet-phy-ieee802.3-c22";
reg = <2>;
clocks = <&cru CLK_MACPHY>;
clock-frequency = <50000000>;
clock-frequency = <24000000>;
resets = <&cru SRST_RESETN_MACPHY>;
pinctrl-names = "default";
pinctrl-0 = <&fephym1_pins>;

View File

@@ -320,7 +320,7 @@
compatible = "ethernet-phy-id0680.8101", "ethernet-phy-ieee802.3-c22";
reg = <2>;
clocks = <&cru CLK_MACPHY>;
clock-frequency = <50000000>;
clock-frequency = <24000000>;
resets = <&cru SRST_RESETN_MACPHY>;
pinctrl-names = "default";
pinctrl-0 = <&fephym2_pins>;

View File

@@ -129,7 +129,7 @@
compatible = "ethernet-phy-id0680.8101", "ethernet-phy-ieee802.3-c22";
reg = <2>;
clocks = <&cru CLK_MACPHY>;
clock-frequency = <50000000>;
clock-frequency = <24000000>;
resets = <&cru SRST_RESETN_MACPHY>;
phy-is-integrated;
};

View File

@@ -1576,7 +1576,7 @@
};
i2c2: i2c@20800000 {
compatible = "rockchip,rv1126b-i2c", "rockchip,rk3399-i2c";
compatible = "rockchip,rv1126b-i2c";
reg = <0x20800000 0x1000>;
interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
@@ -2273,22 +2273,20 @@
};
i2c0: i2c@21100000 {
compatible = "rockchip,rv1126b-i2c", "rockchip,rk3399-i2c";
compatible = "rockchip,rv1126b-i2c";
reg = <0x21100000 0x1000>;
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&cru CLK_I2C0>, <&cru PCLK_I2C0>;
clock-names = "i2c", "pclk";
dmas = <&dmac 29>, <&dmac 28>;
dma-names = "tx", "rx";
pinctrl-names = "default";
pinctrl-0 = <&i2c0m0_pins>;
status = "disabled";
};
i2c1: i2c@21110000 {
compatible = "rockchip,rv1126b-i2c", "rockchip,rk3399-i2c";
compatible = "rockchip,rv1126b-i2c";
reg = <0x21110000 0x1000>;
interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
@@ -2303,7 +2301,7 @@
};
i2c3: i2c@21120000 {
compatible = "rockchip,rv1126b-i2c", "rockchip,rk3399-i2c";
compatible = "rockchip,rv1126b-i2c";
reg = <0x21120000 0x1000>;
interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
@@ -2318,30 +2316,26 @@
};
i2c4: i2c@21130000 {
compatible = "rockchip,rv1126b-i2c", "rockchip,rk3399-i2c";
compatible = "rockchip,rv1126b-i2c";
reg = <0x21130000 0x1000>;
interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&cru CLK_I2C4>, <&cru PCLK_I2C4>;
clock-names = "i2c", "pclk";
dmas = <&dmac 37>, <&dmac 36>;
dma-names = "tx", "rx";
pinctrl-names = "default";
pinctrl-0 = <&i2c4m0_pins>;
status = "disabled";
};
i2c5: i2c@21140000 {
compatible = "rockchip,rv1126b-i2c", "rockchip,rk3399-i2c";
compatible = "rockchip,rv1126b-i2c";
reg = <0x21140000 0x1000>;
interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&cru CLK_I2C5>, <&cru PCLK_I2C5>;
clock-names = "i2c", "pclk";
dmas = <&dmac 39>, <&dmac 38>;
dma-names = "tx", "rx";
pinctrl-names = "default";
pinctrl-0 = <&i2c5m0_pins>;
status = "disabled";

View File

@@ -7,6 +7,8 @@
*/
#include <linux/acpi.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
@@ -41,6 +43,10 @@
#define REG_IPD 0x1c /* interrupt pending */
#define REG_FCNT 0x20 /* finished count */
#define REG_SCL_OE_DB 0x24 /* Slave hold scl debounce */
#define REG_DMA_SADDR 0x80 /* DMA Addr register for TX */
#define REG_DMA_TXDATA 0x88 /* DMA TXDATA register */
#define REG_DMA_RXDATA 0x8c /* DMA RXDATA register */
#define REG_DMA_CONF 0x90 /* DMA conf register */
#define REG_CON1 0x228 /* control register1 */
/* Data buffer offsets */
@@ -62,6 +68,7 @@ enum {
#define REG_CON_STOP BIT(4)
#define REG_CON_LASTACK BIT(5) /* 1: send NACK after last received byte */
#define REG_CON_ACTACK BIT(6) /* 1: stop if NACK is received */
#define REG_CON_CLEAN_DMA BIT(7) /* 1: clean DMA conf */
#define REG_CON_TUNING_MASK GENMASK_ULL(15, 8)
@@ -90,7 +97,7 @@ enum {
#define REG_INT_STOP BIT(5) /* STOP condition generated */
#define REG_INT_NAKRCV BIT(6) /* NACK received */
#define REG_INT_SLV_HDSCL BIT(7) /* slave hold scl */
#define REG_INT_ALL 0xff
#define REG_INT_ALL 0x3ff
/* Disable i2c all irqs */
#define IEN_ALL_DISABLE 0
@@ -104,9 +111,23 @@ enum {
#define REG_CON1_TRANSFER_AUTO_STOP BIT(1)
#define REG_CON1_NACK_AUTO_STOP BIT(2)
/* DMA */
#define DMA_ENABLE_DMA_TX (BIT(16) | BIT(0))
#define DMA_ENABLE_DMA_RX (BIT(16 + 1) | BIT(1))
#define DMA_DISABLE_DMA_TX (BIT(16))
#define DMA_DISABLE_DMA_RX (BIT(16 + 1))
#define DMA_ENABLE_RK_DMA (BIT(16 + 2) | BIT(2))
#define DMA_FLUSH_TXRX (BIT(16 + 4) | BIT(4))
#define DMA_TX_SLAVE_ADDR_OFFSET 0
#define DMA_TX_SLAVE_ADDR1_OFFSE 8 /* for 10bit addr */
#define DMA_TX_SLAVE_ADDR_VALID BIT(16)
#define DMA_TX_SLAVE_ADDR1_VALID BIT(17) /* for 10bit addr */
/* Constants */
#define WAIT_TIMEOUT 200 /* ms */
#define DEFAULT_SCL_RATE (100 * 1000) /* Hz */
#define WAIT_TIMEOUT 200 /* ms */
#define DEFAULT_SCL_RATE (100 * 1000) /* Hz */
#define TX_IDLE_WAIT_TIMEOUT 10 /* ms */
/**
* struct i2c_spec_values - I2C specification values for various modes
@@ -186,15 +207,22 @@ enum rk3x_i2c_state {
STATE_STOP
};
enum rk3x_i2c_xfer_mode {
RK_I2C_FIFO,
RK_I2C_DMA
};
/**
* struct rk3x_i2c_soc_data - SOC-specific data
* @grf_offset: offset inside the grf regmap for setting the i2c type
* @calc_timings: Callback function for i2c timing information calculated
* @dma_control: DMA initialize or release function for some Socs support DMA
*/
struct rk3x_i2c_soc_data {
int grf_offset;
int (*calc_timings)(unsigned long, struct i2c_timings *,
struct rk3x_i2c_calced_timings *);
void (*dma_control)(struct platform_device *pdev, bool init);
};
/**
@@ -232,6 +260,12 @@ struct rk3x_i2c {
struct clk *clk;
struct clk *pclk;
struct notifier_block clk_rate_nb;
phys_addr_t dma_addr_rx;
phys_addr_t dma_addr_tx;
struct dma_chan *dma_rx;
struct dma_chan *dma_tx;
struct scatterlist sg;
enum dma_data_direction dma_direction;
bool autostop_supported;
struct reset_control *reset;
@@ -251,12 +285,15 @@ struct rk3x_i2c {
u8 addr;
unsigned int mode;
bool is_last_msg;
void *dma_buf;
/* I2C state machine */
enum rk3x_i2c_state state;
unsigned int processed;
int error;
unsigned int suspended:1;
enum rk3x_i2c_xfer_mode xfer_mode;
bool stop_after_dma;
struct notifier_block i2c_restart_nb;
bool system_restarting;
@@ -342,16 +379,250 @@ out:
return false;
}
/**
* rk3x_i2c_start - Generate a START condition, which triggers a REG_INT_START interrupt.
* @i2c: target controller data
*/
static void rk3x_i2c_start(struct rk3x_i2c *i2c)
static void rk3x_i2c_dma_unmap(struct rk3x_i2c *i2c)
{
struct dma_chan *chan = i2c->dma_direction == DMA_FROM_DEVICE
? i2c->dma_rx : i2c->dma_tx;
dma_unmap_single(chan->device->dev, sg_dma_address(&i2c->sg),
i2c->msg->len, i2c->dma_direction);
i2c->dma_direction = DMA_NONE;
}
static void rk3x_i2c_cleanup_dma(struct rk3x_i2c *i2c)
{
if (i2c->dma_direction == DMA_NONE)
return;
else if (i2c->dma_direction == DMA_FROM_DEVICE)
dmaengine_terminate_all(i2c->dma_rx);
else if (i2c->dma_direction == DMA_TO_DEVICE)
dmaengine_terminate_all(i2c->dma_tx);
rk3x_i2c_dma_unmap(i2c);
}
static inline bool
rk3x_i2c_wait_for_tx_idle(struct rk3x_i2c *i2c)
{
u32 ipd;
if (!readl_relaxed_poll_timeout(i2c->regs + REG_IPD, ipd,
ipd & REG_INT_STOP, 100,
TX_IDLE_WAIT_TIMEOUT * 1000))
return true;
dev_warn(i2c->dev, "i2c controller is in busy state!\n");
return false;
}
static void rk3x_i2c_complete_dma(struct rk3x_i2c *i2c, unsigned long time_left)
{
/* if it is no error happen, copy to rx buf */
if (!i2c->error && time_left > 0) {
/* if it is dma tx, make sure tx is completed */
if (!rk3x_i2c_wait_for_tx_idle(i2c))
i2c->error = -EBUSY;
else
i2c->stop_after_dma = true;
}
rk3x_i2c_cleanup_dma(i2c);
i2c_put_dma_safe_msg_buf(i2c->dma_buf, i2c->msg,
i2c->stop_after_dma);
}
static void rk3x_i2c_handle_dma_xfer_stop(struct rk3x_i2c *i2c)
{
u32 con = i2c_readl(i2c, REG_CON);
/* disable start bit */
con &= ~REG_CON_START;
i2c_writel(i2c, con, REG_CON);
if (!i2c->error)
i2c->state = STATE_IDLE;
rk3x_i2c_clean_ipd(i2c);
i2c->dma_buf = NULL;
i2c->msg = NULL;
}
static void rk3x_i2c_dma_irq_callback(void *data)
{
struct rk3x_i2c *i2c = (struct rk3x_i2c *)data;
i2c->busy = false;
/* signal rk3x_i2c_xfer that we are finished */
rk3x_i2c_wake_up(i2c);
}
static int rk3x_i2c_prepate_dma_sg(struct rk3x_i2c *i2c, void *dma_buf)
{
struct dma_async_tx_descriptor *rxdesc = NULL, *txdesc = NULL;
u32 val = DMA_FLUSH_TXRX | DMA_ENABLE_RK_DMA;
bool read = i2c->msg->flags & I2C_M_RD;
dma_cookie_t cookie;
dma_addr_t dma_addr;
if (i2c->mode == REG_CON_MOD_TX) {
val |= DMA_ENABLE_DMA_TX | DMA_DISABLE_DMA_RX;
i2c_writel(i2c, val, REG_DMA_CONF);
val = ((i2c->addr & 0x7f) << 1) | DMA_TX_SLAVE_ADDR_VALID;
i2c_writel(i2c, val, REG_DMA_SADDR);
} else {
val |= DMA_ENABLE_DMA_RX | DMA_DISABLE_DMA_TX;
i2c_writel(i2c, val, REG_DMA_CONF);
}
if (read) {
dma_addr = dma_map_single(i2c->dma_rx->device->dev,
dma_buf, i2c->msg->len,
DMA_FROM_DEVICE);
if (dma_mapping_error(i2c->dma_rx->device->dev, dma_addr)) {
dev_err(i2c->dev, "dma rx map failed\n");
return -EINVAL;
}
} else {
dma_addr = dma_map_single(i2c->dma_tx->device->dev,
dma_buf, i2c->msg->len,
DMA_TO_DEVICE);
if (dma_mapping_error(i2c->dma_tx->device->dev, dma_addr)) {
dev_err(i2c->dev, "dma tx map failed\n");
return -EINVAL;
}
}
sg_dma_len(&i2c->sg) = i2c->msg->len;
sg_dma_address(&i2c->sg) = dma_addr;
if (read) {
struct dma_slave_config rxconf = {
.direction = DMA_DEV_TO_MEM,
.src_addr = i2c->dma_addr_rx,
.src_addr_width = 4,
.src_maxburst = 4,
};
i2c->dma_direction = DMA_FROM_DEVICE;
dmaengine_slave_config(i2c->dma_rx, &rxconf);
rxdesc = dmaengine_prep_slave_sg(i2c->dma_rx, &i2c->sg,
1, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT);
if (!rxdesc) {
if (txdesc)
dmaengine_terminate_sync(i2c->dma_tx);
return -EINVAL;
}
rxdesc->callback = rk3x_i2c_dma_irq_callback;
rxdesc->callback_param = i2c;
cookie = dmaengine_submit(rxdesc);
if (dma_submit_error(cookie)) {
dev_err(i2c->dev, "submitting dma rx failed\n");
rk3x_i2c_cleanup_dma(i2c);
return -EINVAL;
}
dma_async_issue_pending(i2c->dma_rx);
} else {
struct dma_slave_config txconf = {
.direction = DMA_MEM_TO_DEV,
.dst_addr = i2c->dma_addr_tx,
.dst_addr_width = 4,
.dst_maxburst = 4,
};
i2c->dma_direction = DMA_TO_DEVICE;
dmaengine_slave_config(i2c->dma_tx, &txconf);
txdesc = dmaengine_prep_slave_sg(i2c->dma_tx, &i2c->sg,
1, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT);
if (!txdesc) {
if (rxdesc)
dmaengine_terminate_sync(i2c->dma_rx);
return -EINVAL;
}
txdesc->callback = rk3x_i2c_dma_irq_callback;
txdesc->callback_param = i2c;
cookie = dmaengine_submit(txdesc);
if (dma_submit_error(cookie)) {
dev_err(i2c->dev, "submitting dma tx failed\n");
rk3x_i2c_cleanup_dma(i2c);
return -EINVAL;
}
dma_async_issue_pending(i2c->dma_tx);
}
return 0;
}
static void rk3x_i2c_start_dma(struct rk3x_i2c *i2c, void *dma_buf)
{
u32 con = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
u32 con1 = 0;
i2c->xfer_mode = RK_I2C_DMA;
/* use dma should enable autostop, it is also the last msg */
if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
con1 = REG_CON1_NACK_AUTO_STOP | REG_CON1_AUTO_STOP;
con1 |= REG_CON1_TRANSFER_AUTO_STOP | REG_CON1_AUTO_STOP;
i2c_writel(i2c, con1, REG_CON1);
i2c->state = STATE_STOP;
/* only enable nack irq for dma mode */
i2c_writel(i2c, REG_INT_NAKRCV, REG_IEN);
rk3x_i2c_prepate_dma_sg(i2c, dma_buf);
/* enable adapter with correct mode, send START condition */
con |= REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START | REG_CON_LASTACK;
/* if we want to react to NACK, set ACTACK bit */
if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
con |= REG_CON_ACTACK;
i2c_writel(i2c, con, REG_CON);
/* enable transition */
if (i2c->mode == REG_CON_MOD_TX)
/* Add one byte for device addr */
i2c_writel(i2c, i2c->msg->len + 1, REG_MTXCNT);
else
i2c_writel(i2c, i2c->msg->len, REG_MRXCNT);
}
static u8 *rk3x_i2c_get_dma_safe_msg_buf(struct i2c_msg *msg, unsigned int threshold)
{
void *buf;
/* also skip 0-length msgs for bogus thresholds of 0 */
if (!threshold)
pr_debug("rk3x i2c DMA buffer for addr=0x%02x with length 0 is bogus\n",
msg->addr);
if (msg->len < threshold || msg->len == 0)
return NULL;
pr_debug("rk3x i2c using bounce buffer for addr=0x%02x, len=%d\n",
msg->addr, msg->len);
if (msg->flags & I2C_M_RD)
return kzalloc(ALIGN(msg->len, cache_line_size()), GFP_KERNEL);
buf = kzalloc(ALIGN(msg->len, cache_line_size()), GFP_KERNEL);
memcpy(buf, msg->buf, msg->len);
return buf;
}
static void rk3x_i2c_start_fifo(struct rk3x_i2c *i2c)
{
u32 val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
bool auto_stop = rk3x_i2c_auto_stop(i2c);
int length = 0;
i2c->xfer_mode = RK_I2C_FIFO;
/* enable appropriate interrupts */
if (i2c->mode == REG_CON_MOD_TX) {
if (!auto_stop) {
@@ -368,7 +639,7 @@ static void rk3x_i2c_start(struct rk3x_i2c *i2c)
}
/* enable adapter with correct mode, send START condition */
val |= REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
val |= REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START | REG_CON_CLEAN_DMA;
/* if we want to react to NACK, set ACTACK bit */
if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
@@ -383,6 +654,25 @@ static void rk3x_i2c_start(struct rk3x_i2c *i2c)
rk3x_i2c_prepare_read(i2c);
}
/**
* rk3x_i2c_start - Generate a START condition, which triggers a REG_INT_START interrupt.
* @i2c: target controller data
*/
static void rk3x_i2c_start(struct rk3x_i2c *i2c, bool polling)
{
/* DMA or FIFO */
if (i2c->dma_tx && i2c->dma_rx && !polling) {
if (i2c->msg->flags & I2C_M_RD)
i2c->dma_buf = rk3x_i2c_get_dma_safe_msg_buf(i2c->msg, 65);
else
i2c->dma_buf = rk3x_i2c_get_dma_safe_msg_buf(i2c->msg, 64);
if (i2c->dma_buf)
return rk3x_i2c_start_dma(i2c, i2c->dma_buf);
}
rk3x_i2c_start_fifo(i2c);
}
/**
* rk3x_i2c_stop - Generate a STOP condition, which triggers a REG_INT_STOP interrupt.
* @i2c: target controller data
@@ -1171,6 +1461,8 @@ static int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num)
i2c->busy = true;
i2c->processed = 0;
i2c->error = 0;
i2c->xfer_mode = RK_I2C_FIFO;
i2c->stop_after_dma = false;
rk3x_i2c_clean_ipd(i2c);
if (i2c->autostop_supported)
@@ -1261,21 +1553,29 @@ static int rk3x_i2c_xfer_common(struct i2c_adapter *adap,
spin_unlock_irqrestore(&i2c->lock, flags);
if (!polling) {
rk3x_i2c_start(i2c);
rk3x_i2c_start(i2c, polling);
timeout = wait_event_timeout(i2c->wait, !i2c->busy,
msecs_to_jiffies(xfer_time));
} else {
disable_irq(i2c->irq);
rk3x_i2c_start(i2c);
rk3x_i2c_start(i2c, polling);
timeout = rk3x_i2c_wait_xfer_poll(i2c, xfer_time);
enable_irq(i2c->irq);
}
/* 'stop_after_dma' tells if DMA xfer was complete */
if (i2c->xfer_mode == RK_I2C_DMA)
rk3x_i2c_complete_dma(i2c, timeout);
spin_lock_irqsave(&i2c->lock, flags);
/* Handles states of the I2C controller itself for DMA xfer mode */
if (i2c->xfer_mode == RK_I2C_DMA)
rk3x_i2c_handle_dma_xfer_stop(i2c);
if (timeout == 0) {
ipd = i2c_readl(i2c, REG_IPD);
dev_err(i2c->dev, "timeout, ipd: 0x%02x, state: %d\n",
@@ -1450,6 +1750,38 @@ static u32 rk3x_i2c_func(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
}
static void rk3x_i2c_dma_control(struct platform_device *pdev, bool init)
{
struct rk3x_i2c *i2c = platform_get_drvdata(pdev);
if (init) {
struct resource *res;
i2c->dma_tx = dma_request_chan(&pdev->dev, "tx");
if (IS_ERR(i2c->dma_tx)) {
dev_dbg(&pdev->dev, "Failed to request TX DMA channel\n");
i2c->dma_tx = NULL;
}
i2c->dma_rx = dma_request_chan(&pdev->dev, "rx");
if (IS_ERR(i2c->dma_rx)) {
dev_dbg(&pdev->dev, "Failed to request RX DMA channel\n");
i2c->dma_rx = NULL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (i2c->dma_tx)
i2c->dma_addr_tx = res->start + REG_DMA_TXDATA;
if (i2c->dma_rx)
i2c->dma_addr_rx = res->start + REG_DMA_RXDATA;
} else {
if (i2c->dma_rx)
dma_release_channel(i2c->dma_rx);
if (i2c->dma_tx)
dma_release_channel(i2c->dma_tx);
}
}
static const struct i2c_algorithm rk3x_i2c_algorithm = {
.master_xfer = rk3x_i2c_xfer,
.master_xfer_atomic = rk3x_i2c_xfer_polling,
@@ -1471,6 +1803,12 @@ static const struct rk3x_i2c_soc_data rk3066_soc_data = {
.calc_timings = rk3x_i2c_v0_calc_timings,
};
static const struct rk3x_i2c_soc_data rv1126b_soc_data = {
.grf_offset = -1,
.calc_timings = rk3x_i2c_v1_calc_timings,
.dma_control = rk3x_i2c_dma_control,
};
static const struct rk3x_i2c_soc_data rk3188_soc_data = {
.grf_offset = 0x0a4,
.calc_timings = rk3x_i2c_v0_calc_timings,
@@ -1500,6 +1838,10 @@ static const struct of_device_id rk3x_i2c_match[] = {
.compatible = "rockchip,rv1126-i2c",
.data = &rv1126_soc_data
},
{
.compatible = "rockchip,rv1126b-i2c",
.data = &rv1126b_soc_data
},
{
.compatible = "rockchip,rk3066-i2c",
.data = &rk3066_soc_data
@@ -1720,6 +2062,9 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
goto err_clk_notifier;
}
if (i2c->soc_data->dma_control)
i2c->soc_data->dma_control(pdev, true);
ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret < 0)
goto err_register_restart_handler;
@@ -1727,6 +2072,8 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
return 0;
err_register_restart_handler:
if (i2c->soc_data->dma_control)
i2c->soc_data->dma_control(pdev, false);
unregister_restart_handler(&i2c->i2c_restart_nb);
err_clk_notifier:
clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
@@ -1743,6 +2090,9 @@ static int rk3x_i2c_remove(struct platform_device *pdev)
i2c_del_adapter(&i2c->adap);
if (i2c->soc_data->dma_control)
i2c->soc_data->dma_control(pdev, false);
unregister_restart_handler(&i2c->i2c_restart_nb);
clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
clk_unprepare(i2c->pclk);

View File

@@ -2557,8 +2557,8 @@ static const struct rk_gmac_ops rv1126_ops = {
#define RV1126B_RK_MACPHY_DISABLE 0
#define RV1126B_RK_MACPHY_ENABLE BIT(31)
#define RV1126B_RK_MACPHY_EXTCLK_SEL_OUTPUT 0
#define RV1126B_RK_MACPHY_EXTCLK_SEL_INPUT BIT(8)
#define RV1126B_RK_MACPHY_EXTCLK_SEL_INPUT 0
#define RV1126B_RK_MACPHY_EXTCLK_SEL_OUTPUT BIT(8)
#define RV1126B_RK_MACPHY_CLK_24M 0
#define RV1126B_RK_MACPHY_CLK_50M BIT(11)
@@ -2686,23 +2686,18 @@ static void rv1126b_integrated_phy_power(struct rk_priv_data *priv, bool up)
value = RV1126B_RK_MACPHY_CLK_50M;
else
value = RV1126B_RK_MACPHY_CLK_24M;
value |= priv->clock_input ? RV1126B_RK_MACPHY_EXTCLK_SEL_INPUT :
RV1126B_RK_MACPHY_EXTCLK_SEL_OUTPUT;
regmap_write(priv->grf, RV1126B_VI_GRF_RK_MACPHY_CON2, value);
regmap_write(priv->grf, RV1126B_VI_GRF_RK_MACPHY_CON0,
RV1126B_RK_MACPHY_PHY_ID | RV1126B_RK_MACPHY_PHY_ADDR);
value = RV1126B_RK_MACPHY_PHY_REVISION | RV1126B_RK_MACPHY_PHY_MODEL |
RV1126B_RK_MACPHY_ENABLE;
regmap_write(priv->grf, RV1126B_VI_GRF_RK_MACPHY_CON1, value);
usleep_range(200, 220);
reset_control_deassert(priv->phy_reset);
regmap_write(priv->grf, RV1126B_VI_GRF_RK_MACPHY_CON1,
RV1126B_RK_MACPHY_DISABLE);
usleep_range(100, 120);
regmap_write(priv->grf, RV1126B_VI_GRF_RK_MACPHY_CON1, value);
reset_control_deassert(priv->phy_reset);
} else {
regmap_write(priv->grf, RV1126B_VI_GRF_RK_MACPHY_CON1,
RV1126B_RK_MACPHY_DISABLE);

View File

@@ -13,12 +13,13 @@
#include <linux/mii.h>
#include <linux/netdevice.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/phy.h>
#define INTERNAL_FEPHY_ID 0x06808101
#define MII_INTERNAL_CTRL_STATUS 17
#define SMI_ADDR_TSTCNTL 20
#define SMI_ADDR_CFGCNTL 20
#define SMI_ADDR_TSTREAD1 21
#define SMI_ADDR_TSTREAD2 22
#define SMI_ADDR_TSTWRITE 23
@@ -33,62 +34,54 @@
#define MII_SPEED_10 BIT(2)
#define MII_SPEED_100 BIT(3)
#define TSTCNTL_WRITE_ADDR 0
#define TSTCNTL_READ_ADDR 5
#define TSTCNTL_BANK_SEL 11
#define TSTCNTL_RD (BIT(15) | BIT(10))
#define TSTCNTL_WR (BIT(14) | BIT(10))
#define CFGCNTL_WRITE_ADDR 0
#define CFGCNTL_READ_ADDR 5
#define CFGCNTL_GROUP_SEL 11
#define CFGCNTL_RD (BIT(15) | BIT(10))
#define CFGCNTL_WR (BIT(14) | BIT(10))
#define TSTCNTL_WRITE(bank, reg) (TSTCNTL_WR | ((bank) << TSTCNTL_BANK_SEL) \
| ((reg) << TSTCNTL_WRITE_ADDR))
#define TSTCNTL_READ(bank, reg) (TSTCNTL_RD | ((bank) << TSTCNTL_BANK_SEL) \
| ((reg) << TSTCNTL_READ_ADDR))
#define TSTMODE_ENABLE 0x400
#define TSTMODE_DISABLE 0x0
#define CFGCNTL_WRITE(group, reg) (CFGCNTL_WR | ((group) << CFGCNTL_GROUP_SEL) \
| ((reg) << CFGCNTL_WRITE_ADDR))
#define CFGCNTL_READ(group, reg) (CFGCNTL_RD | ((group) << CFGCNTL_GROUP_SEL) \
| ((reg) << CFGCNTL_READ_ADDR))
#define GAIN_PRE GENMASK(5, 2)
#define WR_ADDR_A7CFG 0x18
enum {
BANK_DSP0 = 0,
BANK_WOL,
BANK_BIST = 3,
BANK_AFE,
BANK_DSP1
GROUP_CFG0 = 0,
GROUP_WOL,
GROUP_CFG0_READ,
GROUP_BIST,
GROUP_AFE,
GROUP_CFG1
};
struct rockchip_fephy_priv {
struct phy_device *phydev;
unsigned int clk_rate;
int old_link;
int wol_irq;
int current_group;
};
static int rockchip_fephy_init_tstmode(struct phy_device *phydev)
static int rockchip_fephy_group_read(struct phy_device *phydev, u8 group, u32 reg)
{
int ret;
ret = phy_write(phydev, SMI_ADDR_TSTCNTL, TSTMODE_DISABLE);
ret = phy_write(phydev, SMI_ADDR_CFGCNTL, CFGCNTL_READ(group, reg));
if (ret)
return ret;
ret = phy_write(phydev, SMI_ADDR_TSTCNTL, TSTMODE_ENABLE);
if (ret)
return ret;
ret = phy_write(phydev, SMI_ADDR_TSTCNTL, TSTMODE_DISABLE);
if (ret)
return ret;
return phy_write(phydev, SMI_ADDR_TSTCNTL, TSTMODE_ENABLE);
if (group)
return phy_read(phydev, SMI_ADDR_TSTREAD1);
else
return (phy_read(phydev, SMI_ADDR_TSTREAD1) |
(phy_read(phydev, SMI_ADDR_TSTREAD2) << 16));
}
static int rockchip_fephy_close_tstmode(struct phy_device *phydev)
{
/* Back to basic register bank */
return phy_write(phydev, SMI_ADDR_TSTCNTL, TSTMODE_DISABLE);
}
static int rockchip_fephy_bank_write(struct phy_device *phydev, u8 bank,
u32 reg, u16 val)
static int rockchip_fephy_group_write(struct phy_device *phydev, u8 group,
u32 reg, u16 val)
{
int ret;
@@ -96,11 +89,12 @@ static int rockchip_fephy_bank_write(struct phy_device *phydev, u8 bank,
if (ret)
return ret;
return phy_write(phydev, SMI_ADDR_TSTCNTL, TSTCNTL_WRITE(bank, reg));
return phy_write(phydev, SMI_ADDR_CFGCNTL, CFGCNTL_WRITE(group, reg));
}
static int rockchip_fephy_config_init(struct phy_device *phydev)
{
struct rockchip_fephy_priv *priv = phydev->priv;
int ret;
/* LED Control, default:0x7f */
@@ -108,23 +102,32 @@ static int rockchip_fephy_config_init(struct phy_device *phydev)
if (ret)
return ret;
ret = rockchip_fephy_init_tstmode(phydev);
if (ret)
return ret;
/* off-energy level0 threshold */
ret = rockchip_fephy_bank_write(phydev, BANK_DSP0, 0xa, 0x6664);
ret = rockchip_fephy_group_write(phydev, GROUP_CFG0, 0xa, 0x6664);
if (ret)
return ret;
/* 100M amplitude control */
ret = rockchip_fephy_bank_write(phydev, BANK_DSP0, 0x18, 0xc);
ret = rockchip_fephy_group_write(phydev, GROUP_CFG0, 0x18, 0xc);
if (ret)
return ret;
ret = rockchip_fephy_close_tstmode(phydev);
if (ret)
return ret;
if (priv->clk_rate == 24000000) {
int sel;
/* pll cp cur sel */
sel = rockchip_fephy_group_read(phydev, GROUP_AFE, 0x3);
if (sel < 0)
return sel;
ret = rockchip_fephy_group_write(phydev, GROUP_AFE, 0x3, sel | 0x2);
if (ret)
return ret;
/* pll lpf res sel */
ret = rockchip_fephy_group_write(phydev, GROUP_CFG0, 0x1a, 0x6);
if (ret)
return ret;
}
return ret;
}
@@ -134,27 +137,53 @@ static int rockchip_fephy_config_aneg(struct phy_device *phydev)
return genphy_config_aneg(phydev);
}
static void rockchip_feph_link_change_notify(struct phy_device *phydev)
{
struct rockchip_fephy_priv *priv = phydev->priv;
int ret;
if (priv->old_link && !phydev->link) {
priv->old_link = 0;
ret = rockchip_fephy_group_write(phydev, GROUP_CFG0, 0xa, 0x6664);
if (ret)
return;
} else if (!priv->old_link && phydev->link) {
int gain;
priv->old_link = 1;
/* read gain level */
gain = rockchip_fephy_group_read(phydev, GROUP_CFG0, 0x0);
if (gain < 0)
return;
if (!(gain & GAIN_PRE)) {
ret = rockchip_fephy_group_write(phydev, GROUP_CFG0, 0xa, 0x6666);
if (ret)
return;
}
}
}
static int rockchip_fephy_wol_enable(struct phy_device *phydev)
{
struct net_device *ndev = phydev->attached_dev;
int ret;
ret = rockchip_fephy_bank_write(phydev, BANK_WOL, 0x0,
((u16)ndev->dev_addr[4] << 8) + ndev->dev_addr[5]);
ret = rockchip_fephy_group_write(phydev, GROUP_WOL, 0x0,
((u16)ndev->dev_addr[4] << 8) + ndev->dev_addr[5]);
if (ret)
return ret;
ret = rockchip_fephy_bank_write(phydev, BANK_WOL, 0x1,
((u16)ndev->dev_addr[2] << 8) + ndev->dev_addr[3]);
ret = rockchip_fephy_group_write(phydev, GROUP_WOL, 0x1,
((u16)ndev->dev_addr[2] << 8) + ndev->dev_addr[3]);
if (ret)
return ret;
ret = rockchip_fephy_bank_write(phydev, BANK_WOL, 0x2,
((u16)ndev->dev_addr[0] << 8) + ndev->dev_addr[1]);
ret = rockchip_fephy_group_write(phydev, GROUP_WOL, 0x2,
((u16)ndev->dev_addr[0] << 8) + ndev->dev_addr[1]);
if (ret)
return ret;
ret = rockchip_fephy_bank_write(phydev, BANK_WOL, 0x3, 0xf);
ret = rockchip_fephy_group_write(phydev, GROUP_WOL, 0x3, 0xf);
if (ret)
return ret;
@@ -170,7 +199,7 @@ static int rockchip_fephy_wol_disable(struct phy_device *phydev)
{
int ret;
ret = rockchip_fephy_bank_write(phydev, BANK_WOL, 0x3, 0x0);
ret = rockchip_fephy_group_write(phydev, GROUP_WOL, 0x3, 0x0);
if (ret)
return ret;
@@ -192,6 +221,355 @@ static irqreturn_t rockchip_fephy_wol_irq_thread(int irq, void *dev_id)
return IRQ_HANDLED;
}
static void rockchip_fephy_dump_cfg1_group_regs(struct phy_device *phydev, int group, char *buf)
{
int reg = 0, val = 0;
for (reg = 0; reg < 18; reg++) {
val = rockchip_fephy_group_read(phydev, GROUP_CFG1, reg);
if (val < 0) {
pr_err("group%d %2d read error: %d\n", group, reg, val);
return;
}
if (buf)
sprintf(buf, "%sgroup%d %2d: 0x%x\n", buf, group, reg, val);
else
pr_info("group%d reg_%02d: 0x%x\n", group, reg, val);
}
}
static void rockchip_fephy_dump_afe_group_regs(struct phy_device *phydev, int group, char *buf)
{
int reg = 0, val = 0;
for (reg = 0; reg < 32; reg++) {
val = rockchip_fephy_group_read(phydev, GROUP_AFE, reg);
if (val < 0) {
pr_err("group%d %2d read error: %d\n", group, reg, val);
return;
}
if (buf)
sprintf(buf, "%sgroup%d %2d: 0x%x\n", buf, group, reg, val);
else
pr_info("group%d reg_%02d: 0x%x\n", group, reg, val);
}
}
static void rockchip_fephy_dump_bist_group_regs(struct phy_device *phydev, int group, char *buf)
{
int reg = 0, val = 0;
for (reg = 0; reg < 32; reg++) {
val = rockchip_fephy_group_read(phydev, GROUP_BIST, reg);
if (val < 0) {
pr_err("group%d %2d read error: %d\n", group, reg, val);
return;
}
if (buf)
sprintf(buf, "%sgroup%d %2d: 0x%x\n", buf, group, reg, val);
else
pr_info("group%d reg_%02d: 0x%x\n", group, reg, val);
}
}
static void rockchip_fephy_dump_cfg_read_group_regs(struct phy_device *phydev, int group, char *buf)
{
int reg = 0, val = 0;
for (reg = 0; reg < 32; reg++) {
val = rockchip_fephy_group_read(phydev, GROUP_CFG0_READ, reg);
if (val < 0) {
pr_err("group%d %2d read error: %d\n", group, reg, val);
return;
}
if (buf)
sprintf(buf, "%sgroup%d %2d: 0x%x\n", buf, group, reg, val);
else
pr_info("group%d reg_%02d: 0x%x\n", group, reg, val);
}
}
static void rockchip_fephy_dump_wol_group_regs(struct phy_device *phydev, int group, char *buf)
{
int reg = 0, val = 0;
for (reg = 0; reg < 13; reg++) {
val = rockchip_fephy_group_read(phydev, GROUP_WOL, reg);
if (val < 0) {
pr_err("group%d %2d read error: %d\n", group, reg, val);
return;
}
if (buf)
sprintf(buf, "%sgroup%d %2d: 0x%x\n", buf, group, reg, val);
else
pr_info("group%d reg_%02d: 0x%x\n", group, reg, val);
}
}
static void rockchip_fephy_dump_cfg_group_regs(struct phy_device *phydev, int group, char *buf)
{
int reg = 0, val = 0;
for (reg = 0; reg < 32; reg++) {
val = rockchip_fephy_group_read(phydev, GROUP_CFG0, reg);
if (val < 0) {
pr_err("group%d %2d read error: %d\n", group, reg, val);
return;
}
if (buf)
sprintf(buf, "%sgroup%d %2d: 0x%x\n", buf, group, reg, val);
else
pr_info("group%d reg_%02d: 0x%x\n", group, reg, val);
}
}
static void rockchip_fephy_phy_read_priv_reg(struct phy_device *phydev, int group, int reg)
{
int val = 0;
switch (group) {
case GROUP_CFG0: /* CFG0 register group */
val = rockchip_fephy_group_read(phydev, GROUP_CFG0, reg);
if (val < 0) {
pr_err("group%d %2d read error: %d\n", group, reg, val);
return;
}
pr_info("read group%d reg_%02d: 0x%x\n", group, reg, val);
break;
case GROUP_WOL: /* WOL register group */
val = rockchip_fephy_group_read(phydev, GROUP_WOL, reg);
if (val < 0) {
pr_err("group%d %2d read error: %d\n", group, reg, val);
return;
}
pr_info("read group%d reg_%02d: 0x%x\n", group, reg, val);
break;
case GROUP_CFG0_READ: /* CFG0_read register group */
val = rockchip_fephy_group_read(phydev, GROUP_CFG0_READ, reg);
if (val < 0) {
pr_err("group%d %2d read error: %d\n", group, reg, val);
return;
}
pr_info("read group%d reg_%02d: 0x%x\n", group, reg, val);
break;
case GROUP_BIST: /* BIST register group */
val = rockchip_fephy_group_read(phydev, GROUP_BIST, reg);
if (val < 0) {
pr_err("group%d %2d read error: %d\n", group, reg, val);
return;
}
pr_info("read group%d reg_%02d: 0x%x\n", group, reg, val);
break;
case GROUP_AFE: /* AFE register group */
val = rockchip_fephy_group_read(phydev, GROUP_AFE, reg);
if (val < 0) {
pr_err("group%d %2d read error: %d\n", group, reg, val);
return;
}
pr_info("read group%d reg_%02d: 0x%x\n", group, reg, val);
break;
case GROUP_CFG1: /* CFG1 register group */
val = rockchip_fephy_group_read(phydev, GROUP_CFG1, reg);
if (val < 0) {
pr_err("group%d %2d read error: %d\n", group, reg, val);
return;
}
pr_info("read group%d reg_%02d: 0x%x\n", group, reg, val);
break;
default:
pr_err("error group num: %d\n", group);
break;
}
}
static void
rockchip_fephy_phy_write_priv_reg(struct phy_device *phydev, int group, int reg, int rval)
{
int val = 0;
switch (group) {
case GROUP_CFG0: /* CFG0 register group */
val = rockchip_fephy_group_write(phydev, GROUP_CFG0, reg, rval);
if (val) {
pr_err("group%d %2d write error: %d\n", group, reg, val);
return;
}
pr_info("write group%d reg_%02d: 0x%x\n", group, reg, val);
break;
case GROUP_WOL: /* WOL register group */
val = rockchip_fephy_group_write(phydev, GROUP_WOL, reg, rval);
if (val) {
pr_err("group%d %2d write error: %d\n", group, reg, val);
return;
}
pr_info("write group%d reg_%02d: 0x%x\n", group, reg, val);
break;
case GROUP_CFG0_READ: /* CFG0_read register group */
val = rockchip_fephy_group_write(phydev, GROUP_CFG0_READ, reg, rval);
if (val) {
pr_err("group%d %2d write error: %d\n", group, reg, val);
return;
}
pr_info("write group%d reg_%02d: 0x%x\n", group, reg, val);
break;
case GROUP_BIST: /* BIST register group */
val = rockchip_fephy_group_write(phydev, GROUP_BIST, reg, rval);
if (val) {
pr_err("group%d %2d write error: %d\n", group, reg, val);
return;
}
pr_info("write group%d reg_%02d: 0x%x\n", group, reg, val);
break;
case GROUP_AFE: /* AFE register group */
val = rockchip_fephy_group_write(phydev, GROUP_AFE, reg, rval);
if (val) {
pr_err("group%d %2d write error: %d\n", group, reg, val);
return;
}
pr_info("write group%d reg_%02d: 0x%x\n", group, reg, val);
break;
case GROUP_CFG1: /* CFG1 register group */
val = rockchip_fephy_group_write(phydev, GROUP_CFG1, reg, rval);
if (val) {
pr_err("group%d %2d write error: %d\n", group, reg, val);
return;
}
pr_info("write group%d reg_%02d: 0x%x\n", group, reg, val);
break;
default:
pr_err("error group num: %d\n", group);
break;
}
}
static ssize_t
phy_param_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct phy_device *phydev = to_phy_device(dev);
struct rockchip_fephy_priv *priv = phydev->priv;
switch (priv->current_group) {
case GROUP_CFG0:
rockchip_fephy_dump_cfg_group_regs(phydev, GROUP_CFG0, buf);
break;
case GROUP_WOL:
rockchip_fephy_dump_wol_group_regs(phydev, GROUP_WOL, buf);
break;
case GROUP_CFG0_READ:
rockchip_fephy_dump_cfg_read_group_regs(phydev, GROUP_CFG0_READ, buf);
break;
case GROUP_BIST:
rockchip_fephy_dump_bist_group_regs(phydev, GROUP_BIST, buf);
break;
case GROUP_AFE:
rockchip_fephy_dump_afe_group_regs(phydev, GROUP_AFE, buf);
break;
case GROUP_CFG1:
rockchip_fephy_dump_cfg1_group_regs(phydev, GROUP_CFG1, buf);
break;
default:
pr_err("error group num: %d\n", priv->current_group);
break;
}
return strlen(buf);
}
static ssize_t phy_param_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct phy_device *phydev = to_phy_device(dev);
struct rockchip_fephy_priv *priv = phydev->priv;
int arg1 = 0, arg2 = 0, arg3 = 0, ret;
char *buff, *p, *para;
char *argv[4];
int argc;
char cmd;
buff = kstrdup(buf, GFP_KERNEL);
if (!buff)
return -EINVAL;
p = buff;
for (argc = 0; argc < 4; argc++) {
para = strsep(&p, " ");
if (!para) {
argv[argc] = NULL;
continue;
}
argv[argc] = para;
}
if (argc < 1 || argc > 4)
goto end;
if (argv[1]) {
ret = kstrtoint(argv[1], 0, &arg1);
if (ret)
pr_err("kstrtoint failed\n");
}
if (argv[2]) {
ret = kstrtoint(argv[2], 0, &arg2);
if (ret)
pr_err("kstrtoint failed\n");
}
if (argv[3]) {
ret = kstrtoint(argv[3], 0, &arg3);
if (ret)
pr_err("kstrtoint failed\n");
}
cmd = argv[0][0];
switch (cmd) {
case 'R':
rockchip_fephy_phy_read_priv_reg(phydev, arg1, arg2);
priv->current_group = arg1;
break;
case 'W':
rockchip_fephy_phy_write_priv_reg(phydev, arg1, arg2, arg3);
priv->current_group = arg1;
break;
case 'd':
priv->current_group = GROUP_CFG0;
rockchip_fephy_dump_cfg_group_regs(phydev, GROUP_CFG0, NULL);
break;
case 'w':
priv->current_group = GROUP_WOL;
rockchip_fephy_dump_wol_group_regs(phydev, GROUP_WOL, NULL);
break;
case 'p':
priv->current_group = GROUP_CFG0_READ;
rockchip_fephy_dump_cfg_read_group_regs(phydev, GROUP_CFG0_READ, NULL);
break;
case 'b':
priv->current_group = GROUP_BIST;
rockchip_fephy_dump_bist_group_regs(phydev, GROUP_BIST, NULL);
break;
case 'a':
priv->current_group = GROUP_AFE;
rockchip_fephy_dump_afe_group_regs(phydev, GROUP_AFE, NULL);
break;
case 's':
priv->current_group = GROUP_CFG1;
rockchip_fephy_dump_cfg1_group_regs(phydev, GROUP_CFG1, NULL);
break;
case 'r':
priv->current_group = GROUP_CFG0;
if (phydev && phydev->drv->soft_reset)
phydev->drv->soft_reset(phydev);
break;
default:
goto end;
}
return count;
end:
kfree(buff);
return 0;
}
static DEVICE_ATTR_RW(phy_param);
static int rockchip_fephy_probe(struct phy_device *phydev)
{
struct rockchip_fephy_priv *priv;
@@ -202,6 +580,9 @@ static int rockchip_fephy_probe(struct phy_device *phydev)
return -ENOMEM;
phydev->priv = priv;
if (device_property_read_u32(&phydev->mdio.dev, "clock-frequency", &priv->clk_rate))
priv->clk_rate = 24000000;
priv->wol_irq = platform_get_irq_byname_optional(to_platform_device(&phydev->mdio.dev),
"wol_irq");
if (priv->wol_irq == -EPROBE_DEFER)
@@ -220,6 +601,11 @@ static int rockchip_fephy_probe(struct phy_device *phydev)
}
priv->phydev = phydev;
ret = device_create_file(&phydev->mdio.dev, &dev_attr_phy_param);
if (ret)
goto irq_err;
return 0;
irq_err:
@@ -229,6 +615,7 @@ irq_err:
static void rockchip_fephy_remove(struct phy_device *phydev)
{
device_remove_file(&phydev->mdio.dev, &dev_attr_phy_param);
}
static int rockchip_fephy_suspend(struct phy_device *phydev)
@@ -263,6 +650,7 @@ static struct phy_driver rockchip_fephy_driver[] = {
/* PHY_BASIC_FEATURES */
.features = PHY_BASIC_FEATURES,
.flags = 0,
.link_change_notify = rockchip_feph_link_change_notify,
.soft_reset = genphy_soft_reset,
.config_init = rockchip_fephy_config_init,
.config_aneg = rockchip_fephy_config_aneg,