#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/i2c.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/phy.h>
#include <linux/phy/phy.h>
#include <linux/slab.h>
#define DS125DF111_NUM_CH 2
#define DS125DF111_NUM_VCO_GROUP_REG 5
#define DS125DF111_CH_SELECT 0xff
#define DS125DF111_CH_SELECT_TARGET_MASK GENMASK(3, 0)
#define DS125DF111_CH_SELECT_EN BIT(2)
#define DS125DF111_CH_CTRL 0x00
#define DS125DF111_CH_CTRL_RESET BIT(2)
#define DS125DF111_CH_RST_SLEEP_US 10
#define DS125DF111_CH_RST_TIMEOUT_US 10000
#define DS125DF111_VCO_GROUP_BASE 0x60
#define DS125DF111_RATIOS 0x2f
#define DS125DF111_RATIOS_RATE_MASK GENMASK(7, 6)
#define DS125DF111_RATIOS_SUBRATE_MASK GENMASK(5, 4)
#define DS125DF111_RATIOS_MASK GENMASK(7, 4)
struct ds125df111_ch {
struct phy *phy;
struct ds125df111_priv *priv;
int idx;
};
struct ds125df111_priv {
struct ds125df111_ch ch[DS125DF111_NUM_CH];
struct i2c_client *client;
struct mutex mutex;
};
enum ds125df111_mode {
FREQ_1G,
FREQ_10G,
};
static const struct ds125df111_config {
u8 vco_group[DS125DF111_NUM_VCO_GROUP_REG];
u8 rate;
u8 subrate;
} ds125df111_cfg[] = {
[FREQ_1G] = {
.vco_group = {0x00, 0xB2, 0x00, 0xB2, 0xCC},
.rate = 0x1,
.subrate = 0x2,
},
[FREQ_10G] = {
.vco_group = {0x90, 0xB3, 0x90, 0xB3, 0xCD},
.rate = 0x1,
.subrate = 0x3,
},
};
static int ds125df111_rmw(struct ds125df111_priv *priv, u8 reg, u8 clr, u8 set)
{
struct i2c_client *i2c = priv->client;
int err;
u8 val;
err = i2c_smbus_read_byte_data(i2c, reg);
if (err < 0)
return err;
val = (u8)err;
val &= ~clr;
val |= set;
err = i2c_smbus_write_byte_data(i2c, reg, val);
if (err < 0)
return err;
return 0;
}
static int ds125df111_configure(struct phy *phy,
const struct ds125df111_config *cfg)
{
struct ds125df111_ch *ch = phy_get_drvdata(phy);
struct ds125df111_priv *priv = ch->priv;
struct i2c_client *i2c = priv->client;
struct device *dev = &phy->dev;
u8 ratios_val;
int err, i;
int val;
mutex_lock(&priv->mutex);
err = ds125df111_rmw(priv, DS125DF111_CH_SELECT,
DS125DF111_CH_SELECT_TARGET_MASK,
DS125DF111_CH_SELECT_EN | ch->idx);
if (err < 0) {
dev_err(dev, "Unable to select channel: %pe\n", ERR_PTR(err));
goto out;
}
err = ds125df111_rmw(priv, DS125DF111_CH_CTRL, 0,
DS125DF111_CH_CTRL_RESET);
if (err < 0) {
dev_err(dev, "Error resetting channel configuration: %pe\n",
ERR_PTR(err));
goto out;
}
err = read_poll_timeout(i2c_smbus_read_byte_data, val,
val < 0 || !(val & DS125DF111_CH_CTRL_RESET),
DS125DF111_CH_RST_SLEEP_US,
DS125DF111_CH_RST_TIMEOUT_US, false, i2c,
DS125DF111_CH_CTRL);
if (err) {
dev_err(dev, "Timed out waiting for channel reset: %pe\n",
ERR_PTR(err));
goto out;
}
if (val < 0) {
dev_err(dev, "Error reading reset status: %pe\n", ERR_PTR(val));
err = val;
goto out;
}
for (i = 0; i < DS125DF111_NUM_VCO_GROUP_REG; i++) {
err = i2c_smbus_write_byte_data(i2c,
DS125DF111_VCO_GROUP_BASE + i,
cfg->vco_group[i]);
if (err < 0) {
dev_err(dev, "Error programming VCO group: %pe\n",
ERR_PTR(err));
goto out;
}
}
ratios_val = FIELD_PREP(DS125DF111_RATIOS_RATE_MASK, cfg->rate) |
FIELD_PREP(DS125DF111_RATIOS_SUBRATE_MASK, cfg->subrate);
err = ds125df111_rmw(priv, DS125DF111_RATIOS, DS125DF111_RATIOS_MASK,
ratios_val);
if (err < 0) {
dev_err(dev, "Error programming the divide ratios: %pe\n",
ERR_PTR(err));
goto out;
}
out:
mutex_unlock(&priv->mutex);
return err;
}
static int ds125df111_set_mode(struct phy *phy, enum phy_mode mode, int submode)
{
const struct ds125df111_config *cfg;
if (mode != PHY_MODE_ETHERNET)
return -EINVAL;
switch (submode) {
case PHY_INTERFACE_MODE_10GBASER:
cfg = &ds125df111_cfg[FREQ_10G];
break;
case PHY_INTERFACE_MODE_1000BASEX:
case PHY_INTERFACE_MODE_SGMII:
cfg = &ds125df111_cfg[FREQ_1G];
break;
default:
return -EINVAL;
}
return ds125df111_configure(phy, cfg);
}
static int ds125df111_validate(struct phy *phy, enum phy_mode mode, int submode,
union phy_configure_opts *opts __always_unused)
{
if (mode != PHY_MODE_ETHERNET)
return -EINVAL;
switch (submode) {
case PHY_INTERFACE_MODE_10GBASER:
case PHY_INTERFACE_MODE_1000BASEX:
case PHY_INTERFACE_MODE_SGMII:
return 0;
default:
return -EINVAL;
}
}
static const struct phy_ops ds125df111_ops = {
.validate = ds125df111_validate,
.set_mode = ds125df111_set_mode,
.owner = THIS_MODULE,
};
static struct phy *ds125df111_xlate(struct device *dev,
const struct of_phandle_args *args)
{
struct ds125df111_priv *priv = dev_get_drvdata(dev);
u32 idx;
if (args->args_count != 1)
return ERR_PTR(-EINVAL);
idx = args->args[0];
if (idx >= DS125DF111_NUM_CH) {
dev_err(dev, "Maximum number of channels is %d\n",
DS125DF111_NUM_CH);
return ERR_PTR(-EINVAL);
}
return priv->ch[idx].phy;
}
static int ds125df111_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct phy_provider *provider;
struct ds125df111_priv *priv;
int i, err;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->client = client;
err = devm_mutex_init(dev, &priv->mutex);
if (err)
return err;
i2c_set_clientdata(client, priv);
for (i = 0; i < DS125DF111_NUM_CH; i++) {
struct ds125df111_ch *ch = &priv->ch[i];
struct phy *phy;
phy = devm_phy_create(dev, NULL, &ds125df111_ops);
if (IS_ERR(phy))
return PTR_ERR(phy);
ch->idx = i;
ch->priv = priv;
ch->phy = phy;
phy_set_drvdata(phy, ch);
}
provider = devm_of_phy_provider_register(dev, ds125df111_xlate);
return PTR_ERR_OR_ZERO(provider);
}
static const struct of_device_id ds125df111_dt_ids[] = {
{ .compatible = "ti,ds125df111", },
{}
};
MODULE_DEVICE_TABLE(of, ds125df111_dt_ids);
static struct i2c_driver ds125df111_driver = {
.driver = {
.name = "ds125df111",
.of_match_table = ds125df111_dt_ids,
},
.probe = ds125df111_probe,
};
module_i2c_driver(ds125df111_driver);
MODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>");
MODULE_DESCRIPTION("TI DS125DF111 Retimer driver");
MODULE_LICENSE("GPL");