* [PATCH v2 13/13] net: ethernet: ti: cpts: fix overflow check period
From: Grygorii Strashko @ 2016-11-28 23:03 UTC (permalink / raw)
To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
Cc: Sekhar Nori, linux-kernel, linux-omap, Rob Herring, devicetree,
Murali Karicheri, Wingman Kwok, Grygorii Strashko, John Stultz,
Thomas Gleixner
In-Reply-To: <20161128230337.6731-1-grygorii.strashko@ti.com>
The CPTS drivers uses 8sec period for overflow checking with
assumption that CPTS retclk will not exceed 500MHz. But that's not
true on some TI platforms (Kesytone 2). As result, it is possible that
CPTS counter will overflow more than once between two readings.
Hence, fix it by selecting overflow check period dynamically as
max_sec_before_overflow/2, where
max_sec_before_overflow = max_counter_val / rftclk_freq.
Cc: John Stultz <john.stultz@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
drivers/net/ethernet/ti/cpts.c | 10 +++++++---
drivers/net/ethernet/ti/cpts.h | 4 +---
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index 4761d8c..c96a94a 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -245,7 +245,7 @@ static void cpts_overflow_check(struct work_struct *work)
cpts_ptp_gettime(&cpts->info, &ts);
pr_debug("cpts overflow check at %lld.%09lu\n", ts.tv_sec, ts.tv_nsec);
- schedule_delayed_work(&cpts->overflow_work, CPTS_OVERFLOW_PERIOD);
+ schedule_delayed_work(&cpts->overflow_work, cpts->ov_check_period);
}
static int cpts_match(struct sk_buff *skb, unsigned int ptp_class,
@@ -379,8 +379,7 @@ int cpts_register(struct cpts *cpts)
}
cpts->phc_index = ptp_clock_index(cpts->clock);
- schedule_delayed_work(&cpts->overflow_work, CPTS_OVERFLOW_PERIOD);
-
+ schedule_delayed_work(&cpts->overflow_work, cpts->ov_check_period);
return 0;
err_ptp:
@@ -421,6 +420,11 @@ static void cpts_calc_mult_shift(struct cpts *cpts)
if (maxsec > 600 && cpts->cc.mask > UINT_MAX)
maxsec = 600;
+ /* Calc overflow check period (maxsec / 2) */
+ cpts->ov_check_period = (HZ * maxsec) / 2;
+ dev_info(cpts->dev, "cpts: overflow check period %lu (jiffies)\n",
+ cpts->ov_check_period);
+
if (cpts->cc_mult || cpts->cc.shift)
return;
diff --git a/drivers/net/ethernet/ti/cpts.h b/drivers/net/ethernet/ti/cpts.h
index 5da23af..c96eca2 100644
--- a/drivers/net/ethernet/ti/cpts.h
+++ b/drivers/net/ethernet/ti/cpts.h
@@ -97,9 +97,6 @@ enum {
CPTS_EV_TX, /* Ethernet Transmit Event */
};
-/* This covers any input clock up to about 500 MHz. */
-#define CPTS_OVERFLOW_PERIOD (HZ * 8)
-
#define CPTS_FIFO_DEPTH 16
#define CPTS_MAX_EVENTS 32
@@ -127,6 +124,7 @@ struct cpts {
struct list_head events;
struct list_head pool;
struct cpts_event pool_data[CPTS_MAX_EVENTS];
+ unsigned long ov_check_period;
};
void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb);
--
2.10.1
^ permalink raw reply related
* [PATCH v2 12/13] net: ethernet: ti: cpts: calc mult and shift from refclk freq
From: Grygorii Strashko @ 2016-11-28 23:03 UTC (permalink / raw)
To: David S. Miller, netdev-u79uwXL29TY76Z2rM5mHXA, Mugunthan V N,
Richard Cochran
Cc: Sekhar Nori, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
devicetree-u79uwXL29TY76Z2rM5mHXA, Murali Karicheri, Wingman Kwok,
Grygorii Strashko, John Stultz, Thomas Gleixner
In-Reply-To: <20161128230337.6731-1-grygorii.strashko-l0cyMroinI0@public.gmane.org>
The cyclecounter mult and shift values can be calculated based on the
CPTS rfclk frequency and timekeepnig framework provides required algos
and API's.
Hence, calc mult and shift basing on CPTS rfclk frequency if both
cpts_clock_shift and cpts_clock_mult properties are not provided in DT (the
basis of calculation algorithm is borrowed from
__clocksource_update_freq_scale() commit 7d2f944a2b83 ("clocksource:
Provide a generic mult/shift factor calculation")). After this change
cpts_clock_shift and cpts_clock_mult DT properties will become optional.
Cc: John Stultz <john.stultz-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Thomas Gleixner <tglx-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>
Signed-off-by: Grygorii Strashko <grygorii.strashko-l0cyMroinI0@public.gmane.org>
---
Documentation/devicetree/bindings/net/cpsw.txt | 8 +++--
drivers/net/ethernet/ti/cpts.c | 50 ++++++++++++++++++++++----
2 files changed, 49 insertions(+), 9 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
index 5ad439f..ebda7c9 100644
--- a/Documentation/devicetree/bindings/net/cpsw.txt
+++ b/Documentation/devicetree/bindings/net/cpsw.txt
@@ -20,8 +20,6 @@ Required properties:
- slaves : Specifies number for slaves
- active_slave : Specifies the slave to use for time stamping,
ethtool and SIOCGMIIPHY
-- cpts_clock_mult : Numerator to convert input clock ticks into nanoseconds
-- cpts_clock_shift : Denominator to convert input clock ticks into nanoseconds
Optional properties:
- ti,hwmods : Must be "cpgmac0"
@@ -35,7 +33,11 @@ Optional properties:
For example in dra72x-evm, pcf gpio has to be
driven low so that cpsw slave 0 and phy data
lines are connected via mux.
-
+- cpts_clock_mult : Numerator to convert input clock ticks into nanoseconds
+- cpts_clock_shift : Denominator to convert input clock ticks into nanoseconds
+ Mult and shift will be calculated basing on CPTS
+ rftclk frequency if both cpts_clock_shift and
+ cpts_clock_mult properties are not provided.
Slave Properties:
Required properties:
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index da3339b..4761d8c 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -406,18 +406,54 @@ void cpts_unregister(struct cpts *cpts)
}
EXPORT_SYMBOL_GPL(cpts_unregister);
+static void cpts_calc_mult_shift(struct cpts *cpts)
+{
+ u64 frac, maxsec, ns;
+ u32 freq, mult, shift;
+
+ freq = clk_get_rate(cpts->refclk);
+
+ /* Calc the maximum number of seconds which we can run before
+ * wrapping around.
+ */
+ maxsec = cpts->cc.mask;
+ do_div(maxsec, freq);
+ if (maxsec > 600 && cpts->cc.mask > UINT_MAX)
+ maxsec = 600;
+
+ if (cpts->cc_mult || cpts->cc.shift)
+ return;
+
+ clocks_calc_mult_shift(&mult, &shift, freq, NSEC_PER_SEC, maxsec);
+
+ cpts->cc_mult = mult;
+ cpts->cc.mult = mult;
+ cpts->cc.shift = shift;
+
+ frac = 0;
+ ns = cyclecounter_cyc2ns(&cpts->cc, freq, cpts->cc.mask, &frac);
+
+ dev_info(cpts->dev,
+ "CPTS: ref_clk_freq:%u calc_mult:%u calc_shift:%u error:%lld nsec/sec\n",
+ freq, cpts->cc_mult, cpts->cc.shift, (ns - NSEC_PER_SEC));
+}
+
static int cpts_of_parse(struct cpts *cpts, struct device_node *node)
{
int ret = -EINVAL;
u32 prop;
- if (of_property_read_u32(node, "cpts_clock_mult", &prop))
- goto of_error;
- cpts->cc_mult = prop;
+ cpts->cc_mult = 0;
+ if (!of_property_read_u32(node, "cpts_clock_mult", &prop))
+ cpts->cc_mult = prop;
+
+ cpts->cc.shift = 0;
+ if (!of_property_read_u32(node, "cpts_clock_shift", &prop))
+ cpts->cc.shift = prop;
- if (of_property_read_u32(node, "cpts_clock_shift", &prop))
- goto of_error;
- cpts->cc.shift = prop;
+ if ((cpts->cc_mult && !cpts->cc.shift) ||
+ (!cpts->cc_mult && cpts->cc.shift))
+ goto of_error;
return 0;
@@ -460,6 +496,8 @@ struct cpts *cpts_create(struct device *dev, void __iomem *regs,
cpts->cc.mask = CLOCKSOURCE_MASK(32);
cpts->info = cpts_info;
+ cpts_calc_mult_shift(cpts);
+
return cpts;
}
EXPORT_SYMBOL_GPL(cpts_create);
--
2.10.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v2 11/13] clocksource: export the clocks_calc_mult_shift to use by timestamp code
From: Grygorii Strashko @ 2016-11-28 23:03 UTC (permalink / raw)
To: David S. Miller, netdev-u79uwXL29TY76Z2rM5mHXA, Mugunthan V N,
Richard Cochran
Cc: Sekhar Nori, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
devicetree-u79uwXL29TY76Z2rM5mHXA, Murali Karicheri, Wingman Kwok,
John Stultz, Thomas Gleixner, Grygorii Strashko
In-Reply-To: <20161128230337.6731-1-grygorii.strashko-l0cyMroinI0@public.gmane.org>
From: Murali Karicheri <m-karicheri2-l0cyMroinI0@public.gmane.org>
The CPSW CPTS driver is capable of doing timestamping on tx/rx packets and
requires to know mult and shift factors for timestamp conversion from raw
value to nanoseconds (ptp clock). Now these mult and shift factors are
calculated manually and provided through DT, which makes very hard to
support of a lot number of platforms, especially if CPTS refclk is not the
same for some kind of boards and depends on efuse settings (Keystone 2
platforms). Hence, export clocks_calc_mult_shift() to allow drivers like
CPSW CPTS (and other ptp drivesr) to benefit from automaitc calculation of
mult and shift factors.
Cc: John Stultz <john.stultz-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Thomas Gleixner <tglx-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>
Signed-off-by: Murali Karicheri <m-karicheri2-l0cyMroinI0@public.gmane.org>
Signed-off-by: Grygorii Strashko <grygorii.strashko-l0cyMroinI0@public.gmane.org>
---
kernel/time/clocksource.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 7e4fad7..150242c 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -89,6 +89,7 @@ clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 maxsec)
*mult = tmp;
*shift = sft;
}
+EXPORT_SYMBOL_GPL(clocks_calc_mult_shift);
/*[Clocksource internal variables]---------
* curr_clocksource:
--
2.10.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v2 10/13] net: ethernet: ti: cpts: drop excessive writes to CTRL and INT_EN regs
From: Grygorii Strashko @ 2016-11-28 23:03 UTC (permalink / raw)
To: David S. Miller, netdev-u79uwXL29TY76Z2rM5mHXA, Mugunthan V N,
Richard Cochran
Cc: Sekhar Nori, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
devicetree-u79uwXL29TY76Z2rM5mHXA, Murali Karicheri, Wingman Kwok,
Grygorii Strashko
In-Reply-To: <20161128230337.6731-1-grygorii.strashko-l0cyMroinI0@public.gmane.org>
CPTS module and IRQs are always enabled when CPTS is registered,
before starting overflow check work, and disabled during
deregistration, when overflow check work has been canceled already.
So, It doesn't require to (re)enable CPTS module and IRQs in
cpts_overflow_check().
Signed-off-by: Grygorii Strashko <grygorii.strashko-l0cyMroinI0@public.gmane.org>
---
drivers/net/ethernet/ti/cpts.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index 1b766eb..da3339b 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -243,8 +243,6 @@ static void cpts_overflow_check(struct work_struct *work)
struct timespec64 ts;
struct cpts *cpts = container_of(work, struct cpts, overflow_work.work);
- cpts_write32(cpts, CPTS_EN, control);
- cpts_write32(cpts, TS_PEND_EN, int_enable);
cpts_ptp_gettime(&cpts->info, &ts);
pr_debug("cpts overflow check at %lld.%09lu\n", ts.tv_sec, ts.tv_nsec);
schedule_delayed_work(&cpts->overflow_work, CPTS_OVERFLOW_PERIOD);
--
2.10.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v2 09/13] net: ethernet: ti: cpts: clean up event list if event pool is empty
From: Grygorii Strashko @ 2016-11-28 23:03 UTC (permalink / raw)
To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
Cc: Sekhar Nori, linux-kernel, linux-omap, Rob Herring, devicetree,
Murali Karicheri, Wingman Kwok, Grygorii Strashko
In-Reply-To: <20161128230337.6731-1-grygorii.strashko@ti.com>
From: WingMan Kwok <w-kwok2@ti.com>
When a CPTS user does not exit gracefully by disabling cpts
timestamping and leaving a joined multicast group, the system
continues to receive and timestamps the ptp packets which eventually
occupy all the event list entries. When this happns, the added code
tries to remove some list entries which are expired.
Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
drivers/net/ethernet/ti/cpts.c | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index e743361..1b766eb 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -57,6 +57,26 @@ static int cpts_fifo_pop(struct cpts *cpts, u32 *high, u32 *low)
return -1;
}
+static int cpts_purge_events(struct cpts *cpts)
+{
+ struct list_head *this, *next;
+ struct cpts_event *event;
+ int removed = 0;
+
+ list_for_each_safe(this, next, &cpts->events) {
+ event = list_entry(this, struct cpts_event, list);
+ if (event_expired(event)) {
+ list_del_init(&event->list);
+ list_add(&event->list, &cpts->pool);
+ ++removed;
+ }
+ }
+
+ if (removed)
+ dev_dbg(cpts->dev, "cpts: event pool cleaned up %d\n", removed);
+ return removed ? 0 : -1;
+}
+
/*
* Returns zero if matching event type was found.
*/
@@ -69,10 +89,12 @@ static int cpts_fifo_read(struct cpts *cpts, int match)
for (i = 0; i < CPTS_FIFO_DEPTH; i++) {
if (cpts_fifo_pop(cpts, &hi, &lo))
break;
- if (list_empty(&cpts->pool)) {
- pr_err("cpts: event pool is empty\n");
+
+ if (list_empty(&cpts->pool) && cpts_purge_events(cpts)) {
+ dev_err(cpts->dev, "cpts: event pool empty\n");
return -1;
}
+
event = list_first_entry(&cpts->pool, struct cpts_event, list);
event->tmo = jiffies + 2;
event->high = hi;
--
2.10.1
^ permalink raw reply related
* [PATCH v2 08/13] net: ethernet: ti: cpts: move dt props parsing to cpts driver
From: Grygorii Strashko @ 2016-11-28 23:03 UTC (permalink / raw)
To: David S. Miller, netdev-u79uwXL29TY76Z2rM5mHXA, Mugunthan V N,
Richard Cochran
Cc: Sekhar Nori, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
devicetree-u79uwXL29TY76Z2rM5mHXA, Murali Karicheri, Wingman Kwok,
Grygorii Strashko
In-Reply-To: <20161128230337.6731-1-grygorii.strashko-l0cyMroinI0@public.gmane.org>
Move DT properties parsing into CPTS driver to simplify CPSW
code and CPTS driver porting on other SoC in the future
(like Keystone 2) - with this change it will not be required
to add the same DT parsing code in Keystone 2 NETCP driver.
Signed-off-by: Grygorii Strashko <grygorii.strashko-l0cyMroinI0@public.gmane.org>
---
drivers/net/ethernet/ti/cpsw.c | 16 +---------------
drivers/net/ethernet/ti/cpsw.h | 2 --
drivers/net/ethernet/ti/cpts.c | 29 ++++++++++++++++++++++++++---
drivers/net/ethernet/ti/cpts.h | 5 +++--
4 files changed, 30 insertions(+), 22 deletions(-)
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 6c28ef1..ae1ec6a 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -2312,18 +2312,6 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
}
data->active_slave = prop;
- if (of_property_read_u32(node, "cpts_clock_mult", &prop)) {
- dev_err(&pdev->dev, "Missing cpts_clock_mult property in the DT.\n");
- return -EINVAL;
- }
- data->cpts_clock_mult = prop;
-
- if (of_property_read_u32(node, "cpts_clock_shift", &prop)) {
- dev_err(&pdev->dev, "Missing cpts_clock_shift property in the DT.\n");
- return -EINVAL;
- }
- data->cpts_clock_shift = prop;
-
data->slave_data = devm_kzalloc(&pdev->dev, data->slaves
* sizeof(struct cpsw_slave_data),
GFP_KERNEL);
@@ -2789,9 +2777,7 @@ static int cpsw_probe(struct platform_device *pdev)
goto clean_dma_ret;
}
- cpsw->cpts = cpts_create(cpsw->dev, cpts_regs,
- cpsw->data.cpts_clock_mult,
- cpsw->data.cpts_clock_shift);
+ cpsw->cpts = cpts_create(cpsw->dev, cpts_regs, cpsw->dev->of_node);
if (IS_ERR(cpsw->cpts)) {
ret = PTR_ERR(cpsw->cpts);
goto clean_ale_ret;
diff --git a/drivers/net/ethernet/ti/cpsw.h b/drivers/net/ethernet/ti/cpsw.h
index 16b54c6..6c3037a 100644
--- a/drivers/net/ethernet/ti/cpsw.h
+++ b/drivers/net/ethernet/ti/cpsw.h
@@ -31,8 +31,6 @@ struct cpsw_platform_data {
u32 channels; /* number of cpdma channels (symmetric) */
u32 slaves; /* number of slave cpgmac ports */
u32 active_slave; /* time stamping, ethtool and SIOCGMIIPHY slave */
- u32 cpts_clock_mult; /* convert input clock ticks to nanoseconds */
- u32 cpts_clock_shift; /* convert input clock ticks to nanoseconds */
u32 ale_entries; /* ale table size */
u32 bd_ram_size; /*buffer descriptor ram size */
u32 mac_control; /* Mac control register */
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index ec3f702..e743361 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -386,10 +386,31 @@ void cpts_unregister(struct cpts *cpts)
}
EXPORT_SYMBOL_GPL(cpts_unregister);
+static int cpts_of_parse(struct cpts *cpts, struct device_node *node)
+{
+ int ret = -EINVAL;
+ u32 prop;
+
+ if (of_property_read_u32(node, "cpts_clock_mult", &prop))
+ goto of_error;
+ cpts->cc_mult = prop;
+
+ if (of_property_read_u32(node, "cpts_clock_shift", &prop))
+ goto of_error;
+ cpts->cc.shift = prop;
+
+ return 0;
+
+of_error:
+ dev_err(cpts->dev, "CPTS: Missing property in the DT.\n");
+ return ret;
+}
+
struct cpts *cpts_create(struct device *dev, void __iomem *regs,
- u32 mult, u32 shift)
+ struct device_node *node)
{
struct cpts *cpts;
+ int ret;
if (!regs || !dev)
return ERR_PTR(-EINVAL);
@@ -403,6 +424,10 @@ struct cpts *cpts_create(struct device *dev, void __iomem *regs,
spin_lock_init(&cpts->lock);
INIT_DELAYED_WORK(&cpts->overflow_work, cpts_overflow_check);
+ ret = cpts_of_parse(cpts, node);
+ if (ret)
+ return ERR_PTR(ret);
+
cpts->refclk = devm_clk_get(dev, "cpts");
if (IS_ERR(cpts->refclk)) {
dev_err(dev, "Failed to get cpts refclk\n");
@@ -413,8 +438,6 @@ struct cpts *cpts_create(struct device *dev, void __iomem *regs,
cpts->cc.read = cpts_systim_read;
cpts->cc.mask = CLOCKSOURCE_MASK(32);
- cpts->cc.shift = shift;
- cpts->cc_mult = mult;
cpts->info = cpts_info;
return cpts;
diff --git a/drivers/net/ethernet/ti/cpts.h b/drivers/net/ethernet/ti/cpts.h
index e7d857c..5da23af 100644
--- a/drivers/net/ethernet/ti/cpts.h
+++ b/drivers/net/ethernet/ti/cpts.h
@@ -27,6 +27,7 @@
#include <linux/clocksource.h>
#include <linux/device.h>
#include <linux/list.h>
+#include <linux/of.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/skbuff.h>
#include <linux/timecounter.h>
@@ -133,7 +134,7 @@ void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb);
int cpts_register(struct cpts *cpts);
void cpts_unregister(struct cpts *cpts);
struct cpts *cpts_create(struct device *dev, void __iomem *regs,
- u32 mult, u32 shift);
+ struct device_node *node);
void cpts_release(struct cpts *cpts);
static inline void cpts_rx_enable(struct cpts *cpts, int enable)
@@ -168,7 +169,7 @@ static inline void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb)
static inline
struct cpts *cpts_create(struct device *dev, void __iomem *regs,
- u32 mult, u32 shift)
+ struct device_node *node)
{
return NULL;
}
--
2.10.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v2 07/13] net: ethernet: ti: cpts: rework initialization/deinitialization
From: Grygorii Strashko @ 2016-11-28 23:03 UTC (permalink / raw)
To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
Cc: Sekhar Nori, linux-kernel, linux-omap, Rob Herring, devicetree,
Murali Karicheri, Wingman Kwok, Grygorii Strashko
In-Reply-To: <20161128230337.6731-1-grygorii.strashko@ti.com>
The current implementation CPTS initialization and deinitialization
(represented by cpts_register/unregister()) does too many static
initialization from .ndo_open(), which is reasonable to do once at probe
time instead, and also require caller to allocate memory for struct cpts,
which is internal for CPTS driver in general.
This patch splits CPTS initialization and deinitialization on two parts:
- static initializtion cpts_create()/cpts_release() which expected to be
executed when parent driver is probed/removed;
- dynamic part cpts_register/unregister() which expected to be executed
when network device is opened/closed.
As result, current code of CPTS parent driver - CPSW - will be simplified
(and it also will allow simplify adding support for Keystone 2 devices in
the future), plus more initialization errors will be catched earlier. In
addition, this change allows to clean up cpts.h for the case when CPTS is
disabled.
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
drivers/net/ethernet/ti/cpsw.c | 24 +++++-----
drivers/net/ethernet/ti/cpts.c | 102 ++++++++++++++++++++++++-----------------
drivers/net/ethernet/ti/cpts.h | 26 +++++++++--
3 files changed, 95 insertions(+), 57 deletions(-)
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index a6a93ad..6c28ef1 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -1406,9 +1406,7 @@ static int cpsw_ndo_open(struct net_device *ndev)
if (ret < 0)
goto err_cleanup;
- if (cpts_register(cpsw->dev, cpsw->cpts,
- cpsw->data.cpts_clock_mult,
- cpsw->data.cpts_clock_shift))
+ if (cpts_register(cpsw->cpts))
dev_err(priv->dev, "error registering cpts device\n");
}
@@ -2596,6 +2594,7 @@ static int cpsw_probe(struct platform_device *pdev)
struct cpdma_params dma_params;
struct cpsw_ale_params ale_params;
void __iomem *ss_regs;
+ void __iomem *cpts_regs;
struct resource *res, *ss_res;
const struct of_device_id *of_id;
struct gpio_descs *mode;
@@ -2623,12 +2622,6 @@ static int cpsw_probe(struct platform_device *pdev)
priv->dev = &ndev->dev;
priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG);
cpsw->rx_packet_max = max(rx_packet_max, 128);
- cpsw->cpts = devm_kzalloc(&pdev->dev, sizeof(struct cpts), GFP_KERNEL);
- if (!cpsw->cpts) {
- dev_err(&pdev->dev, "error allocating cpts\n");
- ret = -ENOMEM;
- goto clean_ndev_ret;
- }
mode = devm_gpiod_get_array_optional(&pdev->dev, "mode", GPIOD_OUT_LOW);
if (IS_ERR(mode)) {
@@ -2716,7 +2709,7 @@ static int cpsw_probe(struct platform_device *pdev)
switch (cpsw->version) {
case CPSW_VERSION_1:
cpsw->host_port_regs = ss_regs + CPSW1_HOST_PORT_OFFSET;
- cpsw->cpts->reg = ss_regs + CPSW1_CPTS_OFFSET;
+ cpts_regs = ss_regs + CPSW1_CPTS_OFFSET;
cpsw->hw_stats = ss_regs + CPSW1_HW_STATS;
dma_params.dmaregs = ss_regs + CPSW1_CPDMA_OFFSET;
dma_params.txhdp = ss_regs + CPSW1_STATERAM_OFFSET;
@@ -2730,7 +2723,7 @@ static int cpsw_probe(struct platform_device *pdev)
case CPSW_VERSION_3:
case CPSW_VERSION_4:
cpsw->host_port_regs = ss_regs + CPSW2_HOST_PORT_OFFSET;
- cpsw->cpts->reg = ss_regs + CPSW2_CPTS_OFFSET;
+ cpts_regs = ss_regs + CPSW2_CPTS_OFFSET;
cpsw->hw_stats = ss_regs + CPSW2_HW_STATS;
dma_params.dmaregs = ss_regs + CPSW2_CPDMA_OFFSET;
dma_params.txhdp = ss_regs + CPSW2_STATERAM_OFFSET;
@@ -2796,6 +2789,14 @@ static int cpsw_probe(struct platform_device *pdev)
goto clean_dma_ret;
}
+ cpsw->cpts = cpts_create(cpsw->dev, cpts_regs,
+ cpsw->data.cpts_clock_mult,
+ cpsw->data.cpts_clock_shift);
+ if (IS_ERR(cpsw->cpts)) {
+ ret = PTR_ERR(cpsw->cpts);
+ goto clean_ale_ret;
+ }
+
ndev->irq = platform_get_irq(pdev, 1);
if (ndev->irq < 0) {
dev_err(priv->dev, "error getting irq resource\n");
@@ -2911,6 +2912,7 @@ static int cpsw_remove(struct platform_device *pdev)
unregister_netdev(cpsw->slaves[1].ndev);
unregister_netdev(ndev);
+ cpts_release(cpsw->cpts);
cpsw_ale_destroy(cpsw->ale);
cpdma_ctlr_destroy(cpsw->dma);
cpsw_remove_dt(pdev);
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index 9ad0998..ec3f702 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -228,24 +228,6 @@ static void cpts_overflow_check(struct work_struct *work)
schedule_delayed_work(&cpts->overflow_work, CPTS_OVERFLOW_PERIOD);
}
-static void cpts_clk_init(struct device *dev, struct cpts *cpts)
-{
- if (!cpts->refclk) {
- cpts->refclk = devm_clk_get(dev, "cpts");
- if (IS_ERR(cpts->refclk)) {
- dev_err(dev, "Failed to get cpts refclk\n");
- cpts->refclk = NULL;
- return;
- }
- }
- clk_prepare_enable(cpts->refclk);
-}
-
-static void cpts_clk_release(struct cpts *cpts)
-{
- clk_disable_unprepare(cpts->refclk);
-}
-
static int cpts_match(struct sk_buff *skb, unsigned int ptp_class,
u16 ts_seqid, u8 ts_msgtype)
{
@@ -352,34 +334,24 @@ void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb)
}
EXPORT_SYMBOL_GPL(cpts_tx_timestamp);
-int cpts_register(struct device *dev, struct cpts *cpts,
- u32 mult, u32 shift)
+int cpts_register(struct cpts *cpts)
{
int err, i;
- cpts->info = cpts_info;
- spin_lock_init(&cpts->lock);
-
- cpts->cc.read = cpts_systim_read;
- cpts->cc.mask = CLOCKSOURCE_MASK(32);
- cpts->cc_mult = mult;
- cpts->cc.mult = mult;
- cpts->cc.shift = shift;
-
INIT_LIST_HEAD(&cpts->events);
INIT_LIST_HEAD(&cpts->pool);
for (i = 0; i < CPTS_MAX_EVENTS; i++)
list_add(&cpts->pool_data[i].list, &cpts->pool);
- cpts_clk_init(dev, cpts);
+ clk_enable(cpts->refclk);
+
cpts_write32(cpts, CPTS_EN, control);
cpts_write32(cpts, TS_PEND_EN, int_enable);
+ cpts->cc.mult = cpts->cc_mult;
timecounter_init(&cpts->tc, &cpts->cc, ktime_to_ns(ktime_get_real()));
- INIT_DELAYED_WORK(&cpts->overflow_work, cpts_overflow_check);
-
- cpts->clock = ptp_clock_register(&cpts->info, dev);
+ cpts->clock = ptp_clock_register(&cpts->info, cpts->dev);
if (IS_ERR(cpts->clock)) {
err = PTR_ERR(cpts->clock);
cpts->clock = NULL;
@@ -392,26 +364,74 @@ int cpts_register(struct device *dev, struct cpts *cpts,
return 0;
err_ptp:
- if (cpts->refclk)
- cpts_clk_release(cpts);
+ clk_disable(cpts->refclk);
return err;
}
EXPORT_SYMBOL_GPL(cpts_register);
void cpts_unregister(struct cpts *cpts)
{
- if (cpts->clock) {
- ptp_clock_unregister(cpts->clock);
- cancel_delayed_work_sync(&cpts->overflow_work);
- }
+ if (WARN_ON(!cpts->clock))
+ return;
+
+ cancel_delayed_work_sync(&cpts->overflow_work);
+
+ ptp_clock_unregister(cpts->clock);
+ cpts->clock = NULL;
cpts_write32(cpts, 0, int_enable);
cpts_write32(cpts, 0, control);
- if (cpts->refclk)
- cpts_clk_release(cpts);
+ clk_disable(cpts->refclk);
}
EXPORT_SYMBOL_GPL(cpts_unregister);
+struct cpts *cpts_create(struct device *dev, void __iomem *regs,
+ u32 mult, u32 shift)
+{
+ struct cpts *cpts;
+
+ if (!regs || !dev)
+ return ERR_PTR(-EINVAL);
+
+ cpts = devm_kzalloc(dev, sizeof(*cpts), GFP_KERNEL);
+ if (!cpts)
+ return ERR_PTR(-ENOMEM);
+
+ cpts->dev = dev;
+ cpts->reg = (struct cpsw_cpts __iomem *)regs;
+ spin_lock_init(&cpts->lock);
+ INIT_DELAYED_WORK(&cpts->overflow_work, cpts_overflow_check);
+
+ cpts->refclk = devm_clk_get(dev, "cpts");
+ if (IS_ERR(cpts->refclk)) {
+ dev_err(dev, "Failed to get cpts refclk\n");
+ return ERR_PTR(PTR_ERR(cpts->refclk));
+ }
+
+ clk_prepare(cpts->refclk);
+
+ cpts->cc.read = cpts_systim_read;
+ cpts->cc.mask = CLOCKSOURCE_MASK(32);
+ cpts->cc.shift = shift;
+ cpts->cc_mult = mult;
+ cpts->info = cpts_info;
+
+ return cpts;
+}
+EXPORT_SYMBOL_GPL(cpts_create);
+
+void cpts_release(struct cpts *cpts)
+{
+ if (!cpts)
+ return;
+
+ if (WARN_ON(!cpts->clock))
+ return;
+
+ clk_unprepare(cpts->refclk);
+}
+EXPORT_SYMBOL_GPL(cpts_release);
+
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("TI CPTS ALE driver");
diff --git a/drivers/net/ethernet/ti/cpts.h b/drivers/net/ethernet/ti/cpts.h
index 29a1e80c..e7d857c 100644
--- a/drivers/net/ethernet/ti/cpts.h
+++ b/drivers/net/ethernet/ti/cpts.h
@@ -20,6 +20,8 @@
#ifndef _TI_CPTS_H_
#define _TI_CPTS_H_
+#if IS_ENABLED(CONFIG_TI_CPTS)
+
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clocksource.h>
@@ -108,10 +110,10 @@ struct cpts_event {
};
struct cpts {
+ struct device *dev;
struct cpsw_cpts __iomem *reg;
int tx_enable;
int rx_enable;
-#if IS_ENABLED(CONFIG_TI_CPTS)
struct ptp_clock_info info;
struct ptp_clock *clock;
spinlock_t lock; /* protects time registers */
@@ -124,14 +126,15 @@ struct cpts {
struct list_head events;
struct list_head pool;
struct cpts_event pool_data[CPTS_MAX_EVENTS];
-#endif
};
-#if IS_ENABLED(CONFIG_TI_CPTS)
void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb);
void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb);
-int cpts_register(struct device *dev, struct cpts *cpts, u32 mult, u32 shift);
+int cpts_register(struct cpts *cpts);
void cpts_unregister(struct cpts *cpts);
+struct cpts *cpts_create(struct device *dev, void __iomem *regs,
+ u32 mult, u32 shift);
+void cpts_release(struct cpts *cpts);
static inline void cpts_rx_enable(struct cpts *cpts, int enable)
{
@@ -154,6 +157,8 @@ static inline bool cpts_is_tx_enabled(struct cpts *cpts)
}
#else
+struct cpts;
+
static inline void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb)
{
}
@@ -161,8 +166,19 @@ static inline void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb)
{
}
+static inline
+struct cpts *cpts_create(struct device *dev, void __iomem *regs,
+ u32 mult, u32 shift)
+{
+ return NULL;
+}
+
+static inline void cpts_release(struct cpts *cpts)
+{
+}
+
static inline int
-cpts_register(struct device *dev, struct cpts *cpts, u32 mult, u32 shift)
+cpts_register(struct cpts *cpts)
{
return 0;
}
--
2.10.1
^ permalink raw reply related
* [PATCH v2 06/13] net: ethernet: ti: cpts: disable cpts when unregistered
From: Grygorii Strashko @ 2016-11-28 23:03 UTC (permalink / raw)
To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
Cc: Sekhar Nori, linux-kernel, linux-omap, Rob Herring, devicetree,
Murali Karicheri, Wingman Kwok, Grygorii Strashko
In-Reply-To: <20161128230337.6731-1-grygorii.strashko@ti.com>
The cpts now is left enabled after unregistration.
Hence, disable it in cpts_unregister().
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
drivers/net/ethernet/ti/cpts.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index cb851a7..9ad0998 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -404,6 +404,10 @@ void cpts_unregister(struct cpts *cpts)
ptp_clock_unregister(cpts->clock);
cancel_delayed_work_sync(&cpts->overflow_work);
}
+
+ cpts_write32(cpts, 0, int_enable);
+ cpts_write32(cpts, 0, control);
+
if (cpts->refclk)
cpts_clk_release(cpts);
}
--
2.10.1
^ permalink raw reply related
* [PATCH v2 05/13] net: ethernet: ti: cpts: fix registration order
From: Grygorii Strashko @ 2016-11-28 23:03 UTC (permalink / raw)
To: David S. Miller, netdev-u79uwXL29TY76Z2rM5mHXA, Mugunthan V N,
Richard Cochran
Cc: Sekhar Nori, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
devicetree-u79uwXL29TY76Z2rM5mHXA, Murali Karicheri, Wingman Kwok,
Grygorii Strashko
In-Reply-To: <20161128230337.6731-1-grygorii.strashko-l0cyMroinI0@public.gmane.org>
The ptp clock registered before spinlock, which is protecting it, and
before timecounter and cyclecounter initialization in cpts_register().
So, ensure that ptp clock is registered the last, after everything
else is done.
Signed-off-by: Grygorii Strashko <grygorii.strashko-l0cyMroinI0@public.gmane.org>
---
drivers/net/ethernet/ti/cpts.c | 24 ++++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index 101e17b..cb851a7 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -356,15 +356,8 @@ int cpts_register(struct device *dev, struct cpts *cpts,
u32 mult, u32 shift)
{
int err, i;
- unsigned long flags;
cpts->info = cpts_info;
- cpts->clock = ptp_clock_register(&cpts->info, dev);
- if (IS_ERR(cpts->clock)) {
- err = PTR_ERR(cpts->clock);
- cpts->clock = NULL;
- return err;
- }
spin_lock_init(&cpts->lock);
cpts->cc.read = cpts_systim_read;
@@ -382,15 +375,26 @@ int cpts_register(struct device *dev, struct cpts *cpts,
cpts_write32(cpts, CPTS_EN, control);
cpts_write32(cpts, TS_PEND_EN, int_enable);
- spin_lock_irqsave(&cpts->lock, flags);
timecounter_init(&cpts->tc, &cpts->cc, ktime_to_ns(ktime_get_real()));
- spin_unlock_irqrestore(&cpts->lock, flags);
INIT_DELAYED_WORK(&cpts->overflow_work, cpts_overflow_check);
- schedule_delayed_work(&cpts->overflow_work, CPTS_OVERFLOW_PERIOD);
+ cpts->clock = ptp_clock_register(&cpts->info, dev);
+ if (IS_ERR(cpts->clock)) {
+ err = PTR_ERR(cpts->clock);
+ cpts->clock = NULL;
+ goto err_ptp;
+ }
cpts->phc_index = ptp_clock_index(cpts->clock);
+
+ schedule_delayed_work(&cpts->overflow_work, CPTS_OVERFLOW_PERIOD);
+
return 0;
+
+err_ptp:
+ if (cpts->refclk)
+ cpts_clk_release(cpts);
+ return err;
}
EXPORT_SYMBOL_GPL(cpts_register);
--
2.10.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v2 04/13] net: ethernet: ti: cpts: fix unbalanced clk api usage in cpts_register/unregister
From: Grygorii Strashko @ 2016-11-28 23:03 UTC (permalink / raw)
To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
Cc: Sekhar Nori, linux-kernel, linux-omap, Rob Herring, devicetree,
Murali Karicheri, Wingman Kwok, Grygorii Strashko
In-Reply-To: <20161128230337.6731-1-grygorii.strashko@ti.com>
There are two issues with TI CPTS code which are reproducible when TI
CPSW ethX device passes few up/down iterations:
- cpts refclk prepare counter continuously incremented after each
up/down iteration;
- devm_clk_get(dev, "cpts") is called many times.
Hence, fix these issues by using clk_disable_unprepare() in
cpts_clk_release() and skipping devm_clk_get() if cpts refclk has been
acquired already.
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
drivers/net/ethernet/ti/cpts.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index b26d6fe..101e17b 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -230,18 +230,20 @@ static void cpts_overflow_check(struct work_struct *work)
static void cpts_clk_init(struct device *dev, struct cpts *cpts)
{
- cpts->refclk = devm_clk_get(dev, "cpts");
- if (IS_ERR(cpts->refclk)) {
- dev_err(dev, "Failed to get cpts refclk\n");
- cpts->refclk = NULL;
- return;
+ if (!cpts->refclk) {
+ cpts->refclk = devm_clk_get(dev, "cpts");
+ if (IS_ERR(cpts->refclk)) {
+ dev_err(dev, "Failed to get cpts refclk\n");
+ cpts->refclk = NULL;
+ return;
+ }
}
clk_prepare_enable(cpts->refclk);
}
static void cpts_clk_release(struct cpts *cpts)
{
- clk_disable(cpts->refclk);
+ clk_disable_unprepare(cpts->refclk);
}
static int cpts_match(struct sk_buff *skb, unsigned int ptp_class,
--
2.10.1
^ permalink raw reply related
* [PATCH v2 03/13] net: ethernet: ti: cpsw: minimize direct access to struct cpts
From: Grygorii Strashko @ 2016-11-28 23:03 UTC (permalink / raw)
To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
Cc: Sekhar Nori, linux-kernel, linux-omap, Rob Herring, devicetree,
Murali Karicheri, Wingman Kwok, Grygorii Strashko
In-Reply-To: <20161128230337.6731-1-grygorii.strashko@ti.com>
This will provide more flexibility in changing CPTS internals and also
required for further changes.
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
drivers/net/ethernet/ti/cpsw.c | 28 +++++++++++++++-------------
drivers/net/ethernet/ti/cpts.h | 39 +++++++++++++++++++++++++++++++++++++++
2 files changed, 54 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index f65a4e8..a6a93ad 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -1481,7 +1481,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
}
if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
- cpsw->cpts->tx_enable)
+ cpts_is_tx_enabled(cpsw->cpts))
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
skb_tx_timestamp(skb);
@@ -1520,7 +1520,8 @@ static void cpsw_hwtstamp_v1(struct cpsw_common *cpsw)
struct cpsw_slave *slave = &cpsw->slaves[cpsw->data.active_slave];
u32 ts_en, seq_id;
- if (!cpsw->cpts->tx_enable && !cpsw->cpts->rx_enable) {
+ if (!cpts_is_tx_enabled(cpsw->cpts) &&
+ !cpts_is_rx_enabled(cpsw->cpts)) {
slave_write(slave, 0, CPSW1_TS_CTL);
return;
}
@@ -1528,10 +1529,10 @@ static void cpsw_hwtstamp_v1(struct cpsw_common *cpsw)
seq_id = (30 << CPSW_V1_SEQ_ID_OFS_SHIFT) | ETH_P_1588;
ts_en = EVENT_MSG_BITS << CPSW_V1_MSG_TYPE_OFS;
- if (cpsw->cpts->tx_enable)
+ if (cpts_is_tx_enabled(cpsw->cpts))
ts_en |= CPSW_V1_TS_TX_EN;
- if (cpsw->cpts->rx_enable)
+ if (cpts_is_rx_enabled(cpsw->cpts))
ts_en |= CPSW_V1_TS_RX_EN;
slave_write(slave, ts_en, CPSW1_TS_CTL);
@@ -1554,20 +1555,20 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)
case CPSW_VERSION_2:
ctrl &= ~CTRL_V2_ALL_TS_MASK;
- if (cpsw->cpts->tx_enable)
+ if (cpts_is_tx_enabled(cpsw->cpts))
ctrl |= CTRL_V2_TX_TS_BITS;
- if (cpsw->cpts->rx_enable)
+ if (cpts_is_rx_enabled(cpsw->cpts))
ctrl |= CTRL_V2_RX_TS_BITS;
break;
case CPSW_VERSION_3:
default:
ctrl &= ~CTRL_V3_ALL_TS_MASK;
- if (cpsw->cpts->tx_enable)
+ if (cpts_is_tx_enabled(cpsw->cpts))
ctrl |= CTRL_V3_TX_TS_BITS;
- if (cpsw->cpts->rx_enable)
+ if (cpts_is_rx_enabled(cpsw->cpts))
ctrl |= CTRL_V3_RX_TS_BITS;
break;
}
@@ -1603,7 +1604,7 @@ static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
switch (cfg.rx_filter) {
case HWTSTAMP_FILTER_NONE:
- cpts->rx_enable = 0;
+ cpts_rx_enable(cpts, 0);
break;
case HWTSTAMP_FILTER_ALL:
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
@@ -1619,14 +1620,14 @@ static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
- cpts->rx_enable = 1;
+ cpts_rx_enable(cpts, 1);
cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
break;
default:
return -ERANGE;
}
- cpts->tx_enable = cfg.tx_type == HWTSTAMP_TX_ON;
+ cpts_tx_enable(cpts, cfg.tx_type == HWTSTAMP_TX_ON);
switch (cpsw->version) {
case CPSW_VERSION_1:
@@ -1655,8 +1656,9 @@ static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
return -EOPNOTSUPP;
cfg.flags = 0;
- cfg.tx_type = cpts->tx_enable ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
- cfg.rx_filter = (cpts->rx_enable ?
+ cfg.tx_type = cpts_is_tx_enabled(cpts) ?
+ HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
+ cfg.rx_filter = (cpts_is_rx_enabled(cpts) ?
HWTSTAMP_FILTER_PTP_V2_EVENT : HWTSTAMP_FILTER_NONE);
return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
diff --git a/drivers/net/ethernet/ti/cpts.h b/drivers/net/ethernet/ti/cpts.h
index 416ba2c..29a1e80c 100644
--- a/drivers/net/ethernet/ti/cpts.h
+++ b/drivers/net/ethernet/ti/cpts.h
@@ -132,6 +132,27 @@ void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb);
void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb);
int cpts_register(struct device *dev, struct cpts *cpts, u32 mult, u32 shift);
void cpts_unregister(struct cpts *cpts);
+
+static inline void cpts_rx_enable(struct cpts *cpts, int enable)
+{
+ cpts->rx_enable = enable;
+}
+
+static inline bool cpts_is_rx_enabled(struct cpts *cpts)
+{
+ return !!cpts->rx_enable;
+}
+
+static inline void cpts_tx_enable(struct cpts *cpts, int enable)
+{
+ cpts->tx_enable = enable;
+}
+
+static inline bool cpts_is_tx_enabled(struct cpts *cpts)
+{
+ return !!cpts->tx_enable;
+}
+
#else
static inline void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb)
{
@@ -149,6 +170,24 @@ cpts_register(struct device *dev, struct cpts *cpts, u32 mult, u32 shift)
static inline void cpts_unregister(struct cpts *cpts)
{
}
+
+static inline void cpts_rx_enable(struct cpts *cpts, int enable)
+{
+}
+
+static inline bool cpts_is_rx_enabled(struct cpts *cpts)
+{
+ return false;
+}
+
+static inline void cpts_tx_enable(struct cpts *cpts, int enable)
+{
+}
+
+static inline bool cpts_is_tx_enabled(struct cpts *cpts)
+{
+ return false;
+}
#endif
--
2.10.1
^ permalink raw reply related
* [PATCH v2 02/13] net: ethernet: ti: allow cpts to be built separately
From: Grygorii Strashko @ 2016-11-28 23:03 UTC (permalink / raw)
To: David S. Miller, netdev-u79uwXL29TY76Z2rM5mHXA, Mugunthan V N,
Richard Cochran
Cc: Sekhar Nori, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
devicetree-u79uwXL29TY76Z2rM5mHXA, Murali Karicheri, Wingman Kwok,
Grygorii Strashko
In-Reply-To: <20161128230337.6731-1-grygorii.strashko-l0cyMroinI0@public.gmane.org>
TI CPTS IP is used as part of TI OMAP CPSW driver, but it's also
present as part of NETCP on TI Keystone 2 SoCs. So, It's required
to enable build of CPTS for both this drivers and this can be
achieved by allowing CPTS to be built separately.
Hence, allow cpts to be built separately and convert it to be
a module as both CPSW and NETCP drives can be built as modules.
Signed-off-by: Grygorii Strashko <grygorii.strashko-l0cyMroinI0@public.gmane.org>
---
drivers/net/ethernet/ti/Kconfig | 2 +-
drivers/net/ethernet/ti/Makefile | 3 ++-
drivers/net/ethernet/ti/cpsw.c | 22 +++++++++++++++++-----
drivers/net/ethernet/ti/cpts.c | 15 +++++++--------
drivers/net/ethernet/ti/cpts.h | 18 ++++++++++++++----
5 files changed, 41 insertions(+), 19 deletions(-)
diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
index 9904d74..ff7f518 100644
--- a/drivers/net/ethernet/ti/Kconfig
+++ b/drivers/net/ethernet/ti/Kconfig
@@ -74,7 +74,7 @@ config TI_CPSW
will be called cpsw.
config TI_CPTS
- bool "TI Common Platform Time Sync (CPTS) Support"
+ tristate "TI Common Platform Time Sync (CPTS) Support"
depends on TI_CPSW
select PTP_1588_CLOCK
---help---
diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
index d420d94..1e7c10b 100644
--- a/drivers/net/ethernet/ti/Makefile
+++ b/drivers/net/ethernet/ti/Makefile
@@ -12,8 +12,9 @@ obj-$(CONFIG_TI_DAVINCI_MDIO) += davinci_mdio.o
obj-$(CONFIG_TI_DAVINCI_CPDMA) += davinci_cpdma.o
obj-$(CONFIG_TI_CPSW_PHY_SEL) += cpsw-phy-sel.o
obj-$(CONFIG_TI_CPSW_ALE) += cpsw_ale.o
+obj-$(CONFIG_TI_CPTS) += cpts.o
obj-$(CONFIG_TI_CPSW) += ti_cpsw.o
-ti_cpsw-y := cpsw.o cpts.o
+ti_cpsw-y := cpsw.o
obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o
keystone_netcp-y := netcp_core.o
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 58947aa..f65a4e8 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -1513,7 +1513,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
return NETDEV_TX_BUSY;
}
-#ifdef CONFIG_TI_CPTS
+#if IS_ENABLED(CONFIG_TI_CPTS)
static void cpsw_hwtstamp_v1(struct cpsw_common *cpsw)
{
@@ -1661,7 +1661,16 @@ static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
}
+#else
+static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
+{
+ return -EOPNOTSUPP;
+}
+static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
+{
+ return -EOPNOTSUPP;
+}
#endif /*CONFIG_TI_CPTS*/
static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
@@ -1674,12 +1683,10 @@ static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
return -EINVAL;
switch (cmd) {
-#ifdef CONFIG_TI_CPTS
case SIOCSHWTSTAMP:
return cpsw_hwtstamp_set(dev, req);
case SIOCGHWTSTAMP:
return cpsw_hwtstamp_get(dev, req);
-#endif
}
if (!cpsw->slaves[slave_no].phy)
@@ -1935,10 +1942,10 @@ static void cpsw_set_msglevel(struct net_device *ndev, u32 value)
priv->msg_enable = value;
}
+#if IS_ENABLED(CONFIG_TI_CPTS)
static int cpsw_get_ts_info(struct net_device *ndev,
struct ethtool_ts_info *info)
{
-#ifdef CONFIG_TI_CPTS
struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
info->so_timestamping =
@@ -1955,7 +1962,12 @@ static int cpsw_get_ts_info(struct net_device *ndev,
info->rx_filters =
(1 << HWTSTAMP_FILTER_NONE) |
(1 << HWTSTAMP_FILTER_PTP_V2_EVENT);
+ return 0;
+}
#else
+static int cpsw_get_ts_info(struct net_device *ndev,
+ struct ethtool_ts_info *info)
+{
info->so_timestamping =
SOF_TIMESTAMPING_TX_SOFTWARE |
SOF_TIMESTAMPING_RX_SOFTWARE |
@@ -1963,9 +1975,9 @@ static int cpsw_get_ts_info(struct net_device *ndev,
info->phc_index = -1;
info->tx_types = 0;
info->rx_filters = 0;
-#endif
return 0;
}
+#endif
static int cpsw_get_settings(struct net_device *ndev,
struct ethtool_cmd *ecmd)
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index a42c449..b26d6fe 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -31,8 +31,6 @@
#include "cpts.h"
-#ifdef CONFIG_TI_CPTS
-
#define cpts_read32(c, r) readl_relaxed(&c->reg->r)
#define cpts_write32(c, v, r) writel_relaxed(v, &c->reg->r)
@@ -334,6 +332,7 @@ void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb)
memset(ssh, 0, sizeof(*ssh));
ssh->hwtstamp = ns_to_ktime(ns);
}
+EXPORT_SYMBOL_GPL(cpts_rx_timestamp);
void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb)
{
@@ -349,13 +348,11 @@ void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb)
ssh.hwtstamp = ns_to_ktime(ns);
skb_tstamp_tx(skb, &ssh);
}
-
-#endif /*CONFIG_TI_CPTS*/
+EXPORT_SYMBOL_GPL(cpts_tx_timestamp);
int cpts_register(struct device *dev, struct cpts *cpts,
u32 mult, u32 shift)
{
-#ifdef CONFIG_TI_CPTS
int err, i;
unsigned long flags;
@@ -391,18 +388,20 @@ int cpts_register(struct device *dev, struct cpts *cpts,
schedule_delayed_work(&cpts->overflow_work, CPTS_OVERFLOW_PERIOD);
cpts->phc_index = ptp_clock_index(cpts->clock);
-#endif
return 0;
}
+EXPORT_SYMBOL_GPL(cpts_register);
void cpts_unregister(struct cpts *cpts)
{
-#ifdef CONFIG_TI_CPTS
if (cpts->clock) {
ptp_clock_unregister(cpts->clock);
cancel_delayed_work_sync(&cpts->overflow_work);
}
if (cpts->refclk)
cpts_clk_release(cpts);
-#endif
}
+EXPORT_SYMBOL_GPL(cpts_unregister);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TI CPTS ALE driver");
diff --git a/drivers/net/ethernet/ti/cpts.h b/drivers/net/ethernet/ti/cpts.h
index 69a46b9..416ba2c 100644
--- a/drivers/net/ethernet/ti/cpts.h
+++ b/drivers/net/ethernet/ti/cpts.h
@@ -111,7 +111,7 @@ struct cpts {
struct cpsw_cpts __iomem *reg;
int tx_enable;
int rx_enable;
-#ifdef CONFIG_TI_CPTS
+#if IS_ENABLED(CONFIG_TI_CPTS)
struct ptp_clock_info info;
struct ptp_clock *clock;
spinlock_t lock; /* protects time registers */
@@ -127,9 +127,11 @@ struct cpts {
#endif
};
-#ifdef CONFIG_TI_CPTS
+#if IS_ENABLED(CONFIG_TI_CPTS)
void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb);
void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb);
+int cpts_register(struct device *dev, struct cpts *cpts, u32 mult, u32 shift);
+void cpts_unregister(struct cpts *cpts);
#else
static inline void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb)
{
@@ -137,9 +139,17 @@ static inline void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb)
static inline void cpts_tx_timestamp(struct cpts *cpts, struct sk_buff *skb)
{
}
+
+static inline int
+cpts_register(struct device *dev, struct cpts *cpts, u32 mult, u32 shift)
+{
+ return 0;
+}
+
+static inline void cpts_unregister(struct cpts *cpts)
+{
+}
#endif
-int cpts_register(struct device *dev, struct cpts *cpts, u32 mult, u32 shift);
-void cpts_unregister(struct cpts *cpts);
#endif
--
2.10.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v2 01/13] net: ethernet: ti: cpts: switch to readl/writel_relaxed()
From: Grygorii Strashko @ 2016-11-28 23:03 UTC (permalink / raw)
To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
Cc: Sekhar Nori, linux-kernel, linux-omap, Rob Herring, devicetree,
Murali Karicheri, Wingman Kwok, Grygorii Strashko
In-Reply-To: <20161128230337.6731-1-grygorii.strashko@ti.com>
Switch to readl/writel_relaxed() APIs, because this is recommended
API and the CPTS IP is reused on Keystone 2 SoCs
where LE/BE modes are supported.
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
drivers/net/ethernet/ti/cpts.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index 85a55b4..a42c449 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -33,8 +33,8 @@
#ifdef CONFIG_TI_CPTS
-#define cpts_read32(c, r) __raw_readl(&c->reg->r)
-#define cpts_write32(c, v, r) __raw_writel(v, &c->reg->r)
+#define cpts_read32(c, r) readl_relaxed(&c->reg->r)
+#define cpts_write32(c, v, r) writel_relaxed(v, &c->reg->r)
static int event_expired(struct cpts_event *event)
{
--
2.10.1
^ permalink raw reply related
* [PATCH v2 00/13] net: ethernet: ti: cpts: update and fixes
From: Grygorii Strashko @ 2016-11-28 23:03 UTC (permalink / raw)
To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
Cc: Sekhar Nori, linux-kernel, linux-omap, Rob Herring, devicetree,
Murali Karicheri, Wingman Kwok, Grygorii Strashko
It is preparation series intended to clean up and optimize TI CPTS driver to
facilitate further integration with other TI's SoCs like Keystone 2.
Changes in v2:
- patch "net: ethernet: ti: cpts: rework initialization/deinitialization"
was split on 4 patches
- applied comments from Richard Cochran
- dropped patch
"net: ethernet: ti: cpts: add return value to tx and rx timestamp funcitons"
- new patches added:
"net: ethernet: ti: cpts: drop excessive writes to CTRL and INT_EN regs"
and "clocksource: export the clocks_calc_mult_shift to use by timestamp code"
Link on v1:
http://www.spinics.net/lists/linux-omap/msg131925.html
Grygorii Strashko (11):
net: ethernet: ti: cpts: switch to readl/writel_relaxed()
net: ethernet: ti: allow cpts to be built separately
net: ethernet: ti: cpsw: minimize direct access to struct cpts
net: ethernet: ti: cpts: fix unbalanced clk api usage in cpts_register/unregister
net: ethernet: ti: cpts: fix registration order
net: ethernet: ti: cpts: disable cpts when unregistered
net: ethernet: ti: cpts: rework initialization/deinitialization
net: ethernet: ti: cpts: move dt props parsing to cpts driver
net: ethernet: ti: cpts: drop excessive writes to CTRL and INT_EN regs
net: ethernet: ti: cpts: calc mult and shift from refclk freq
net: ethernet: ti: cpts: fix overflow check period
Murali Karicheri (1):
clocksource: export the clocks_calc_mult_shift to use by timestamp code
WingMan Kwok (1):
net: ethernet: ti: cpts: clean up event list if event pool is empty
Documentation/devicetree/bindings/net/cpsw.txt | 8 +-
drivers/net/ethernet/ti/Kconfig | 2 +-
drivers/net/ethernet/ti/Makefile | 3 +-
drivers/net/ethernet/ti/cpsw.c | 84 ++++-----
drivers/net/ethernet/ti/cpsw.h | 2 -
drivers/net/ethernet/ti/cpts.c | 232 ++++++++++++++++++-------
drivers/net/ethernet/ti/cpts.h | 80 ++++++++-
kernel/time/clocksource.c | 1 +
8 files changed, 297 insertions(+), 115 deletions(-)
--
2.10.1
^ permalink raw reply
* Re: [PATCH v2 3/4] dt-bindings: phy: Add support for QMP phy
From: Stephen Boyd @ 2016-11-28 22:55 UTC (permalink / raw)
To: Vivek Gautam
Cc: kishon-l0cyMroinI0, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1479816163-5260-4-git-send-email-vivek.gautam-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
On 11/22, Vivek Gautam wrote:
> diff --git a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
> new file mode 100644
> index 0000000..ffb173b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
> @@ -0,0 +1,74 @@
> +Qualcomm QMP PHY
> +----------------
> +
> +QMP phy controller supports physical layer functionality for a number of
> +controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB.
> +
> +Required properties:
> + - compatible: compatible list, contains:
> + "qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996,
> + "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996.
> + - reg: list of offset and length pair of the PHY register sets.
> + at index 0: offset and length of register set for PHY common
> + serdes block.
> + from index 1 - N: offset and length of register set for each lane,
> + for N number of phy lanes (ports).
> + - lane-offsets: array of offsets to tx, rx and pcs blocks for phy lanes.
> + - #phy-cells: must be 1
> + - Cell after phy phandle should be the port (lane) number.
> + - clocks: a list of phandles and clock-specifier pairs,
> + one for each entry in clock-names.
> + - clock-names: must be "cfg_ahb" for phy config clock,
> + "aux" for phy aux clock,
> + "ref_clk" for 19.2 MHz ref clk,
> + "ref_clk_src" for reference clock source,
We typically leave "clk" out of clk names because it's redundant.
> + "pipe<port-number>" for pipe clock specific to
> + each port/lane (Optional).
The pipe clocks are orphaned right now. We should add an output
clock from the phy to go into the controller and back into the
phy if I recall correctly. The phy should be a clock provider
itself so it can output the pipe clock source into GCC and back
into the phy and controller.
> + - resets: a list of phandles and reset controller specifier pairs,
> + one for each entry in reset-names.
> + - reset-names: must be "phy" for reset of phy block,
> + "common" for phy common block reset,
> + "cfg" for phy's ahb cfg block reset (Optional).
> + "port<port-number>" for reset specific to
> + each port/lane (Optional).
> + - vdda-phy-supply: Phandle to a regulator supply to PHY core block.
> + - vdda-pll-supply: Phandle to 1.8V regulator supply to PHY refclk pll block.
> +
> +Optional properties:
> + - vddp-ref-clk-supply: Phandle to a regulator supply to any specific refclk
> + pll block.
> +
> +Example:
> + pcie_phy: pciephy@34000 {
pcie-phy or just phy as the node name?
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v2 1/4] dt-bindings: phy: Add support for QUSB2 phy
From: Stephen Boyd @ 2016-11-28 22:49 UTC (permalink / raw)
To: Vivek Gautam
Cc: kishon-l0cyMroinI0, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1479816163-5260-2-git-send-email-vivek.gautam-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
On 11/22, Vivek Gautam wrote:
> diff --git a/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt b/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
> new file mode 100644
> index 0000000..38c8b30
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
> @@ -0,0 +1,55 @@
> +Optional properties:
> + - nvmem-cells: a list of phandles to nvmem cells that contain fused
> + tuning parameters for qusb2 phy, one for each entry
> + in nvmem-cell-names.
> + - nvmem-cell-names: must be "tune2_hstx_trim_efuse" for cell containing
Do we really need efuse in the name? Seems redundant given this
is already an nvmem.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v2 2/2] eeprom: Add IDT 89HPESx driver bindings file
From: Serge Semin @ 2016-11-28 22:38 UTC (permalink / raw)
To: gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A, andrew-g2DYL2Zd6BY,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8
Cc: Sergey.Semin-vHJ8rsvMqnUPfZBKTuL5GA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Serge Semin
In-Reply-To: <1480372701-30560-1-git-send-email-fancer.lancer-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
See cover-letter for changelog
Signed-off-by: Serge Semin <fancer.lancer-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
.../devicetree/bindings/misc/idt_89hpesx.txt | 41 ++++++++++++++++++++++
1 file changed, 41 insertions(+)
create mode 100644 Documentation/devicetree/bindings/misc/idt_89hpesx.txt
diff --git a/Documentation/devicetree/bindings/misc/idt_89hpesx.txt b/Documentation/devicetree/bindings/misc/idt_89hpesx.txt
index 0000000..469cc93
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/idt_89hpesx.txt
@@ -0,0 +1,41 @@
+EEPROM / CSR SMBus-slave interface of IDT 89HPESx devices
+
+Required properties:
+ - compatible : should be "<manufacturer>,<type>"
+ Basically there is only one manufacturer: idt, but some
+ compatible devices may be produced in future. Following devices
+ are supported: 89hpes8nt2, 89hpes12nt3, 89hpes24nt6ag2,
+ 89hpes32nt8ag2, 89hpes32nt8bg2, 89hpes12nt12g2, 89hpes16nt16g2,
+ 89hpes24nt24g2, 89hpes32nt24ag2, 89hpes32nt24bg2;
+ 89hpes12n3, 89hpes12n3a, 89hpes24n3, 89hpes24n3a;
+ 89hpes32h8, 89hpes32h8g2, 89hpes48h12, 89hpes48h12g2,
+ 89hpes48h12ag2, 89hpes16h16, 89hpes22h16, 89hpes22h16g2,
+ 89hpes34h16, 89hpes34h16g2, 89hpes64h16, 89hpes64h16g2,
+ 89hpes64h16ag2;
+ 89hpes12t3g2, 89hpes24t3g2, 89hpes16t4, 89hpes4t4g2,
+ 89hpes10t4g2, 89hpes16t4g2, 89hpes16t4ag2, 89hpes5t5,
+ 89hpes6t5, 89hpes8t5, 89hpes8t5a, 89hpes24t6, 89hpes6t6g2,
+ 89hpes24t6g2, 89hpes16t7, 89hpes32t8, 89hpes32t8g2,
+ 89hpes48t12, 89hpes48t12g2.
+ Current implementation of the driver doesn't have any device-
+ specific functionalities. But since each of them differs
+ by registers mapping, CSRs read/write restrictions can be
+ added in future.
+ - reg : I2C address of the IDT 89HPES device.
+
+Optional properties:
+ - read-only : Parameterless property disables writes to the EEPROM
+ - idt,eesize : Size of EEPROM device connected to IDT 89HPES i2c-master bus
+ (default value is 4096 bytes if option isn't specified)
+ - idt,eeaddr : Custom address of EEPROM device
+ (If not specified IDT 89HPESx device will try to communicate
+ with EEPROM sited by default address - 0x50)
+
+Example:
+ idt_pcie_sw@60 {
+ compatible = "idt,89hpes12nt3";
+ reg = <0x60>;
+ read-only;
+ idt,eesize = <65536>;
+ idt,eeaddr = <0x50>;
+ };
--
2.6.6
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v2 1/2] eeprom: Add IDT 89HPESx EEPROM/CSR driver
From: Serge Semin @ 2016-11-28 22:38 UTC (permalink / raw)
To: gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A, andrew-g2DYL2Zd6BY,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8
Cc: Sergey.Semin-vHJ8rsvMqnUPfZBKTuL5GA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Serge Semin
In-Reply-To: <1480372701-30560-1-git-send-email-fancer.lancer-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
See cover-letter for changelog
Signed-off-by: Serge Semin <fancer.lancer-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/misc/eeprom/Kconfig | 10 +
drivers/misc/eeprom/Makefile | 1 +
drivers/misc/eeprom/idt_89hpesx.c | 1577 +++++++++++++++++++++++++++++++++++++
3 files changed, 1588 insertions(+)
create mode 100644 drivers/misc/eeprom/idt_89hpesx.c
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index c4e41c2..de58762 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -100,4 +100,14 @@ config EEPROM_DIGSY_MTC_CFG
If unsure, say N.
+config EEPROM_IDT_89HPESX
+ tristate "IDT 89HPESx PCIe-swtiches EEPROM / CSR support"
+ depends on I2C && SYSFS
+ help
+ Enable this driver to get read/write access to EEPROM / CSRs
+ over IDT PCIe-swtich i2c-slave interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called idt_89hpesx.
+
endmenu
diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile
index fc1e81d..90a5262 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_EEPROM_MAX6875) += max6875.o
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o
obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o
+obj-$(CONFIG_EEPROM_IDT_89HPESX) += idt_89hpesx.o
diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c
index 0000000..00cbbec
--- /dev/null
+++ b/drivers/misc/eeprom/idt_89hpesx.c
@@ -0,0 +1,1577 @@
+/*
+ * This file is provided under a GPLv2 license. When using or
+ * redistributing this file, you may do so under that license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright (C) 2016 T-Platforms. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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, it can be found <http://www.gnu.org/licenses/>.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * IDT PCIe-switch NTB Linux driver
+ *
+ * Contact Information:
+ * Serge Semin <fancer.lancer-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>, <Sergey.Semin-vHJ8rsvMqnUPfZBKTuL5GA@public.gmane.org>
+ */
+/*
+ * NOTE of the IDT 89HPESx SMBus-slave interface driver
+ * This driver primarily is developed to have an access to EEPROM device of
+ * IDT PCIe-switches. IDT provides a simple SMBus interface to perform IO-
+ * operations from/to EEPROM, which is located at private (so called Master)
+ * SMBus of switches. Using that interface this the driver creates a simple
+ * binary sysfs-file in the device directory:
+ * /sys/bus/i2c/devices/<bus>-<devaddr>/eeprom
+ * In case if read-only flag is specified in the dts-node of device desription,
+ * User-space applications won't be able to write to the EEPROM sysfs-node.
+ * Additionally IDT 89HPESx SMBus interface has an ability to write/read
+ * data of device CSRs. This driver exposes debugf-file to perform simple IO
+ * operations using that ability for just basic debug purpose. Particularly
+ * next file is created in the specific debugfs-directory:
+ * /sys/kernel/debug/idt_csr/
+ * Format of the debugfs-node is:
+ * $ cat /sys/kernel/debug/idt_csr/<bus>-<devaddr>/<devname>;
+ * <CSR address>:<CSR value>
+ * So reading the content of the file gives current CSR address and it value.
+ * If User-space application wishes to change current CSR address,
+ * it can just write a proper value to the sysfs-file:
+ * $ echo "<CSR address>" > /sys/kernel/debug/idt_csr/<bus>-<devaddr>/<devname>
+ * If it wants to change the CSR value as well, the format of the write
+ * operation is:
+ * $ echo "<CSR address>:<CSR value>" > \
+ * /sys/kernel/debug/idt_csr/<bus>-<devaddr>/<devname>;
+ * CSR address and value can be any of hexadecimal, decimal or octal format.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+#include <linux/debugfs.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of.h>
+#include <linux/i2c.h>
+#include <linux/pci_ids.h>
+#include <linux/delay.h>
+
+#define IDT_NAME "89hpesx"
+#define IDT_89HPESX_DESC "IDT 89HPESx SMBus-slave interface driver"
+#define IDT_89HPESX_VER "1.0"
+
+MODULE_DESCRIPTION(IDT_89HPESX_DESC);
+MODULE_VERSION(IDT_89HPESX_VER);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("T-platforms");
+
+/*
+ * csr_dbgdir - CSR read/write operations Debugfs directory
+ */
+static struct dentry *csr_dbgdir;
+
+/*
+ * struct idt_89hpesx_dev - IDT 89HPESx device data structure
+ * @eesize: Size of EEPROM in bytes (calculated from "idt,eecompatible")
+ * @eero: EEPROM Read-only flag
+ * @eeaddr: EEPROM custom address
+ *
+ * @inieecmd: Initial cmd value for EEPROM read/write operations
+ * @inicsrcmd: Initial cmd value for CSR read/write operations
+ * @iniccode: Initialial command code value for IO-operations
+ *
+ * @csr: CSR address to perform read operation
+ *
+ * @smb_write: SMBus write method
+ * @smb_read: SMBus read method
+ * @smb_mtx: SMBus mutex
+ *
+ * @client: i2c client used to perform IO operations
+ *
+ * @ee_file: EEPROM read/write sysfs-file
+ * @csr_file: CSR read/write debugfs-node
+ */
+struct idt_smb_seq;
+struct idt_89hpesx_dev {
+ u32 eesize;
+ bool eero;
+ u8 eeaddr;
+
+ u8 inieecmd;
+ u8 inicsrcmd;
+ u8 iniccode;
+
+ atomic_t csr;
+
+ int (*smb_write)(struct idt_89hpesx_dev *, const struct idt_smb_seq *);
+ int (*smb_read)(struct idt_89hpesx_dev *, struct idt_smb_seq *);
+ struct mutex smb_mtx;
+
+ struct i2c_client *client;
+
+ struct bin_attribute *ee_file;
+ struct dentry *csr_dir;
+ struct dentry *csr_file;
+};
+#define to_pdev_kobj(__kobj) \
+ dev_get_drvdata(container_of(__kobj, struct device, kobj))
+
+/*
+ * struct idt_smb_seq - sequence of data to be read/written from/to IDT 89HPESx
+ * @ccode: SMBus command code
+ * @bytecnt: Byte count of operation
+ * @data: Data to by written
+ */
+struct idt_smb_seq {
+ u8 ccode;
+ u8 bytecnt;
+ u8 *data;
+};
+
+/*
+ * struct idt_eeprom_seq - sequence of data to be read/written from/to EEPROM
+ * @cmd: Transaction CMD
+ * @eeaddr: EEPROM custom address
+ * @memaddr: Internal memory address of EEPROM
+ * @data: Data to be written at the memory address
+ */
+struct idt_eeprom_seq {
+ u8 cmd;
+ u8 eeaddr;
+ u16 memaddr;
+ u8 data;
+} __packed;
+
+/*
+ * struct idt_csr_seq - sequence of data to be read/written from/to CSR
+ * @cmd: Transaction CMD
+ * @csraddr: Internal IDT device CSR address
+ * @data: Data to be read/written from/to the CSR address
+ */
+struct idt_csr_seq {
+ u8 cmd;
+ u16 csraddr;
+ u32 data;
+} __packed;
+
+/*
+ * SMBus command code macros
+ * @CCODE_END: Indicates the end of transaction
+ * @CCODE_START: Indicates the start of transaction
+ * @CCODE_CSR: CSR read/write transaction
+ * @CCODE_EEPROM: EEPROM read/write transaction
+ * @CCODE_BYTE: Supplied data has BYTE length
+ * @CCODE_WORD: Supplied data has WORD length
+ * @CCODE_BLOCK: Supplied data has variable length passed in bytecnt
+ * byte right following CCODE byte
+ */
+#define CCODE_END ((u8)0x01)
+#define CCODE_START ((u8)0x02)
+#define CCODE_CSR ((u8)0x00)
+#define CCODE_EEPROM ((u8)0x04)
+#define CCODE_BYTE ((u8)0x00)
+#define CCODE_WORD ((u8)0x20)
+#define CCODE_BLOCK ((u8)0x40)
+#define CCODE_PEC ((u8)0x80)
+
+/*
+ * EEPROM command macros
+ * @EEPROM_OP_WRITE: EEPROM write operation
+ * @EEPROM_OP_READ: EEPROM read operation
+ * @EEPROM_USA: Use specified address of EEPROM
+ * @EEPROM_NAERR: EEPROM device is not ready to respond
+ * @EEPROM_LAERR: EEPROM arbitration loss error
+ * @EEPROM_MSS: EEPROM misplace start & stop bits error
+ * @EEPROM_WR_CNT: Bytes count to perform write operation
+ * @EEPROM_WRRD_CNT: Bytes count to write before reading
+ * @EEPROM_RD_CNT: Bytes count to perform read operation
+ * @EEPROM_DEF_SIZE: Fall back size of EEPROM
+ * @EEPROM_DEF_ADDR: Defatul EEPROM address
+ * @EEPROM_TOUT: Timeout before retry read operation if eeprom is busy
+ */
+#define EEPROM_OP_WRITE ((u8)0x00)
+#define EEPROM_OP_READ ((u8)0x01)
+#define EEPROM_USA ((u8)0x02)
+#define EEPROM_NAERR ((u8)0x08)
+#define EEPROM_LAERR ((u8)0x10)
+#define EEPROM_MSS ((u8)0x20)
+#define EEPROM_WR_CNT ((u8)5)
+#define EEPROM_WRRD_CNT ((u8)4)
+#define EEPROM_RD_CNT ((u8)5)
+#define EEPROM_DEF_SIZE ((u16)4096)
+#define EEPROM_DEF_ADDR ((u8)0x50)
+#define EEPROM_TOUT (100)
+
+/*
+ * CSR command macros
+ * @CSR_DWE: Enable all four bytes of the operation
+ * @CSR_OP_WRITE: CSR write operation
+ * @CSR_OP_READ: CSR read operation
+ * @CSR_RERR: Read operation error
+ * @CSR_WERR: Write operation error
+ * @CSR_WR_CNT: Bytes count to perform write operation
+ * @CSR_WRRD_CNT: Bytes count to write before reading
+ * @CSR_RD_CNT: Bytes count to perform read operation
+ * @CSR_MAX: Maximum CSR address
+ * @CSR_DEF: Default CSR address
+ * @CSR_REAL_ADDR: CSR real unshifted address
+ */
+#define CSR_DWE ((u8)0x0F)
+#define CSR_OP_WRITE ((u8)0x00)
+#define CSR_OP_READ ((u8)0x10)
+#define CSR_RERR ((u8)0x40)
+#define CSR_WERR ((u8)0x80)
+#define CSR_WR_CNT ((u8)7)
+#define CSR_WRRD_CNT ((u8)3)
+#define CSR_RD_CNT ((u8)7)
+#define CSR_MAX ((u32)0x3FFFF)
+#define CSR_DEF ((u16)0x0000)
+#define CSR_REAL_ADDR(val) ((unsigned int)val << 2)
+
+/*
+ * IDT 89HPESx basic register
+ * @IDT_VIDDID_CSR: PCIe VID and DID of IDT 89HPESx
+ * @IDT_VID_MASK: Mask of VID
+ */
+#define IDT_VIDDID_CSR ((u32)0x0000)
+#define IDT_VID_MASK ((u32)0xFFFF)
+
+/*
+ * IDT 89HPESx can send NACK when new command is sent before previous one
+ * fininshed execution. In this case driver retries operation
+ * certain times.
+ * @RETRY_CNT: Number of retries before giving up and fail
+ * @idt_smb_safe: Generate a retry loop on corresponding SMBus method
+ */
+#define RETRY_CNT (128)
+#define idt_smb_safe(ops, args...) ({ \
+ int __retry = RETRY_CNT; \
+ s32 __sts; \
+ do { \
+ __sts = i2c_smbus_ ## ops ## _data(args); \
+ } while (__retry-- && __sts < 0); \
+ __sts; \
+})
+
+/*===========================================================================
+ * i2c bus level IO-operations
+ *===========================================================================
+ */
+
+/*
+ * idt_smb_write_byte() - SMBus write method when I2C_SMBUS_BYTE_DATA operation
+ * is only available
+ * @pdev: Pointer to the driver data
+ * @seq: Sequence of data to be written
+ */
+static int idt_smb_write_byte(struct idt_89hpesx_dev *pdev,
+ const struct idt_smb_seq *seq)
+{
+ s32 sts;
+ u8 ccode;
+ int idx;
+
+ /* Loop over the supplied data sending byte one-by-one */
+ for (idx = 0; idx < seq->bytecnt; idx++) {
+ /* Collect the command code byte */
+ ccode = seq->ccode | CCODE_BYTE;
+ if (idx == 0)
+ ccode |= CCODE_START;
+ if (idx == seq->bytecnt - 1)
+ ccode |= CCODE_END;
+
+ /* Send data to the device */
+ sts = idt_smb_safe(write_byte, pdev->client, ccode,
+ seq->data[idx]);
+ if (sts != 0)
+ return (int)sts;
+ }
+
+ return 0;
+}
+
+/*
+ * idt_smb_read_byte() - SMBus read method when I2C_SMBUS_BYTE_DATA operation
+ * is only available
+ * @pdev: Pointer to the driver data
+ * @seq: Buffer to read data to
+ */
+static int idt_smb_read_byte(struct idt_89hpesx_dev *pdev,
+ struct idt_smb_seq *seq)
+{
+ s32 sts;
+ u8 ccode;
+ int idx;
+
+ /* Loop over the supplied buffer receiving byte one-by-one */
+ for (idx = 0; idx < seq->bytecnt; idx++) {
+ /* Collect the command code byte */
+ ccode = seq->ccode | CCODE_BYTE;
+ if (idx == 0)
+ ccode |= CCODE_START;
+ if (idx == seq->bytecnt - 1)
+ ccode |= CCODE_END;
+
+ /* Read data from the device */
+ sts = idt_smb_safe(read_byte, pdev->client, ccode);
+ if (sts < 0)
+ return (int)sts;
+
+ seq->data[idx] = (u8)sts;
+ }
+
+ return 0;
+}
+
+/*
+ * idt_smb_write_word() - SMBus write method when I2C_SMBUS_BYTE_DATA and
+ * I2C_FUNC_SMBUS_WORD_DATA operations are available
+ * @pdev: Pointer to the driver data
+ * @seq: Sequence of data to be written
+ */
+static int idt_smb_write_word(struct idt_89hpesx_dev *pdev,
+ const struct idt_smb_seq *seq)
+{
+ s32 sts;
+ u8 ccode;
+ int idx, evencnt;
+
+ /* Calculate the even count of data to send */
+ evencnt = seq->bytecnt - (seq->bytecnt % 2);
+
+ /* Loop over the supplied data sending two bytes at a time */
+ for (idx = 0; idx < evencnt; idx += 2) {
+ /* Collect the command code byte */
+ ccode = seq->ccode | CCODE_WORD;
+ if (idx == 0)
+ ccode |= CCODE_START;
+ if (idx == evencnt - 2)
+ ccode |= CCODE_END;
+
+ /* Send word data to the device */
+ sts = idt_smb_safe(write_word, pdev->client, ccode,
+ *(u16 *)&seq->data[idx]);
+ if (sts != 0)
+ return (int)sts;
+ }
+
+ /* If there is odd number of bytes then send just one last byte */
+ if (seq->bytecnt != evencnt) {
+ /* Collect the command code byte */
+ ccode = seq->ccode | CCODE_BYTE | CCODE_END;
+ if (idx == 0)
+ ccode |= CCODE_START;
+
+ /* Send byte data to the device */
+ sts = idt_smb_safe(write_byte, pdev->client, ccode,
+ seq->data[idx]);
+ if (sts != 0)
+ return (int)sts;
+ }
+
+ return 0;
+}
+
+/*
+ * idt_smb_read_word() - SMBus read method when I2C_SMBUS_BYTE_DATA and
+ * I2C_FUNC_SMBUS_WORD_DATA operations are available
+ * @pdev: Pointer to the driver data
+ * @seq: Buffer to read data to
+ */
+static int idt_smb_read_word(struct idt_89hpesx_dev *pdev,
+ struct idt_smb_seq *seq)
+{
+ s32 sts;
+ u8 ccode;
+ int idx, evencnt;
+
+ /* Calculate the even count of data to send */
+ evencnt = seq->bytecnt - (seq->bytecnt % 2);
+
+ /* Loop over the supplied data reading two bytes at a time */
+ for (idx = 0; idx < evencnt; idx += 2) {
+ /* Collect the command code byte */
+ ccode = seq->ccode | CCODE_WORD;
+ if (idx == 0)
+ ccode |= CCODE_START;
+ if (idx == evencnt - 2)
+ ccode |= CCODE_END;
+
+ /* Read word data from the device */
+ sts = idt_smb_safe(read_word, pdev->client, ccode);
+ if (sts < 0)
+ return (int)sts;
+
+ *(u16 *)&seq->data[idx] = (u16)sts;
+ }
+
+ /* If there is odd number of bytes then receive just one last byte */
+ if (seq->bytecnt != evencnt) {
+ /* Collect the command code byte */
+ ccode = seq->ccode | CCODE_BYTE | CCODE_END;
+ if (idx == 0)
+ ccode |= CCODE_START;
+
+ /* Read last data byte from the device */
+ sts = idt_smb_safe(read_byte, pdev->client, ccode);
+ if (sts < 0)
+ return (int)sts;
+
+ seq->data[idx] = (u8)sts;
+ }
+
+ return 0;
+}
+
+/*
+ * idt_smb_write_block() - SMBus write method when I2C_SMBUS_BLOCK_DATA
+ * operation is available
+ * @pdev: Pointer to the driver data
+ * @seq: Sequence of data to be written
+ */
+static int idt_smb_write_block(struct idt_89hpesx_dev *pdev,
+ const struct idt_smb_seq *seq)
+{
+ u8 ccode;
+
+ /* Return error if too much data passed to send */
+ if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX)
+ return -EINVAL;
+
+ /* Collect the command code byte */
+ ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END;
+
+ /* Send block of data to the device */
+ return idt_smb_safe(write_block, pdev->client, ccode, seq->bytecnt,
+ seq->data);
+}
+
+/*
+ * idt_smb_read_block() - SMBus read method when I2C_SMBUS_BLOCK_DATA
+ * operation is available
+ * @pdev: Pointer to the driver data
+ * @seq: Buffer to read data to
+ */
+static int idt_smb_read_block(struct idt_89hpesx_dev *pdev,
+ struct idt_smb_seq *seq)
+{
+ s32 sts;
+ u8 ccode;
+
+ /* Return error if too much data passed to send */
+ if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX)
+ return -EINVAL;
+
+ /* Collect the command code byte */
+ ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END;
+
+ /* Read block of data from the device */
+ sts = idt_smb_safe(read_block, pdev->client, ccode, seq->data);
+ if (sts != seq->bytecnt)
+ return (sts < 0 ? sts : -ENODATA);
+
+ return 0;
+}
+
+/*
+ * idt_smb_write_i2c_block() - SMBus write method when I2C_SMBUS_I2C_BLOCK_DATA
+ * operation is available
+ * @pdev: Pointer to the driver data
+ * @seq: Sequence of data to be written
+ *
+ * NOTE It's usual SMBus write block operation, except the actual data length is
+ * sent as first byte of data
+ */
+static int idt_smb_write_i2c_block(struct idt_89hpesx_dev *pdev,
+ const struct idt_smb_seq *seq)
+{
+ u8 ccode, buf[I2C_SMBUS_BLOCK_MAX + 1];
+
+ /* Return error if too much data passed to send */
+ if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX)
+ return -EINVAL;
+
+ /* Collect the data to send. Length byte must be added prior the data */
+ buf[0] = seq->bytecnt;
+ memcpy(&buf[1], seq->data, seq->bytecnt);
+
+ /* Collect the command code byte */
+ ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END;
+
+ /* Send length and block of data to the device */
+ return idt_smb_safe(write_i2c_block, pdev->client, ccode,
+ seq->bytecnt + 1, buf);
+}
+
+/*
+ * idt_smb_read_i2c_block() - SMBus read method when I2C_SMBUS_I2C_BLOCK_DATA
+ * operation is available
+ * @pdev: Pointer to the driver data
+ * @seq: Buffer to read data to
+ *
+ * NOTE It's usual SMBus read block operation, except the actual data length is
+ * retrieved as first byte of data
+ */
+static int idt_smb_read_i2c_block(struct idt_89hpesx_dev *pdev,
+ struct idt_smb_seq *seq)
+{
+ u8 ccode, buf[I2C_SMBUS_BLOCK_MAX + 1];
+ s32 sts;
+
+ /* Return error if too much data passed to send */
+ if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX)
+ return -EINVAL;
+
+ /* Collect the command code byte */
+ ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END;
+
+ /* Read length and block of data from the device */
+ sts = idt_smb_safe(read_i2c_block, pdev->client, ccode,
+ seq->bytecnt + 1, buf);
+ if (sts != seq->bytecnt + 1)
+ return (sts < 0 ? sts : -ENODATA);
+ if (buf[0] != seq->bytecnt)
+ return -ENODATA;
+
+ /* Copy retrieved data to the output data buffer */
+ memcpy(seq->data, &buf[1], seq->bytecnt);
+
+ return 0;
+}
+
+/*===========================================================================
+ * EEPROM IO-operations
+ *===========================================================================
+ */
+
+/*
+ * idt_eeprom_read_byte() - read just one byte from EEPROM
+ * @pdev: Pointer to the driver data
+ * @memaddr: Start EEPROM memory address
+ * @data: Data to be written to EEPROM
+ */
+static int idt_eeprom_read_byte(struct idt_89hpesx_dev *pdev, u16 memaddr,
+ u8 *data)
+{
+ struct device *dev = &pdev->client->dev;
+ struct idt_eeprom_seq eeseq;
+ struct idt_smb_seq smbseq;
+ int ret, retry;
+
+ /* Initialize SMBus sequence fields */
+ smbseq.ccode = pdev->iniccode | CCODE_EEPROM;
+ smbseq.data = (u8 *)&eeseq;
+
+ /*
+ * Sometimes EEPROM may respond with NACK if it's busy with previous
+ * operation, so we need to perform a few attempts of read cycle
+ */
+ retry = RETRY_CNT;
+ do {
+ /* Send EEPROM memory address to read data from */
+ smbseq.bytecnt = EEPROM_WRRD_CNT;
+ eeseq.cmd = pdev->inieecmd | EEPROM_OP_READ;
+ eeseq.eeaddr = pdev->eeaddr;
+ eeseq.memaddr = cpu_to_le16(memaddr);
+ ret = pdev->smb_write(pdev, &smbseq);
+ if (ret != 0) {
+ dev_err(dev, "Failed to init eeprom addr 0x%02hhx",
+ memaddr);
+ break;
+ }
+
+ /* Perform read operation */
+ smbseq.bytecnt = EEPROM_RD_CNT;
+ ret = pdev->smb_read(pdev, &smbseq);
+ if (ret != 0) {
+ dev_err(dev, "Failed to read eeprom data 0x%02hhx",
+ memaddr);
+ break;
+ }
+
+ /* Restart read operation if the device is busy */
+ if (retry && (eeseq.cmd & EEPROM_NAERR)) {
+ dev_dbg(dev, "EEPROM busy, retry reading after %d ms",
+ EEPROM_TOUT);
+ msleep(EEPROM_TOUT);
+ continue;
+ }
+
+ /* Check whether IDT successfully read data from EEPROM */
+ if (eeseq.cmd & (EEPROM_NAERR | EEPROM_LAERR | EEPROM_MSS)) {
+ dev_err(dev,
+ "Communication with eeprom failed, cmd 0x%hhx",
+ eeseq.cmd);
+ ret = -EREMOTEIO;
+ break;
+ }
+
+ /* Save retrieved data and exit the loop */
+ *data = eeseq.data;
+ break;
+ } while (retry--);
+
+ /* Return the status of operation */
+ return ret;
+}
+
+/*
+ * idt_eeprom_write() - EEPROM write operation
+ * @pdev: Pointer to the driver data
+ * @memaddr: Start EEPROM memory address
+ * @len: Length of data to be written
+ * @data: Data to be written to EEPROM
+ */
+static int idt_eeprom_write(struct idt_89hpesx_dev *pdev, u16 memaddr, u16 len,
+ const u8 *data)
+{
+ struct device *dev = &pdev->client->dev;
+ struct idt_eeprom_seq eeseq;
+ struct idt_smb_seq smbseq;
+ int ret;
+ u16 idx;
+
+ /* Initialize SMBus sequence fields */
+ smbseq.ccode = pdev->iniccode | CCODE_EEPROM;
+ smbseq.data = (u8 *)&eeseq;
+
+ /* Send data byte-by-byte, checking if it is successfully written */
+ for (idx = 0; idx < len; idx++, memaddr++) {
+ /* Lock IDT SMBus device */
+ mutex_lock(&pdev->smb_mtx);
+
+ /* Perform write operation */
+ smbseq.bytecnt = EEPROM_WR_CNT;
+ eeseq.cmd = pdev->inieecmd | EEPROM_OP_WRITE;
+ eeseq.eeaddr = pdev->eeaddr;
+ eeseq.memaddr = cpu_to_le16(memaddr);
+ eeseq.data = data[idx];
+ ret = pdev->smb_write(pdev, &smbseq);
+ if (ret != 0) {
+ dev_err(dev,
+ "Failed to write 0x%04hx:0x%02hhx to eeprom",
+ memaddr, data[idx]);
+ goto err_mutex_unlock;
+ }
+
+ /*
+ * Check whether the data is successfully written by reading
+ * from the same EEPROM memory address.
+ */
+ eeseq.data = ~data[idx];
+ ret = idt_eeprom_read_byte(pdev, memaddr, &eeseq.data);
+ if (ret != 0)
+ goto err_mutex_unlock;
+
+ /* Check whether the read byte is the same as written one */
+ if (eeseq.data != data[idx]) {
+ dev_err(dev, "Values don't match 0x%02hhx != 0x%02hhx",
+ eeseq.data, data[idx]);
+ ret = -EREMOTEIO;
+ goto err_mutex_unlock;
+ }
+
+ /* Unlock IDT SMBus device */
+err_mutex_unlock:
+ mutex_unlock(&pdev->smb_mtx);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * idt_eeprom_read() - EEPROM read operation
+ * @pdev: Pointer to the driver data
+ * @memaddr: Start EEPROM memory address
+ * @len: Length of data to read
+ * @buf: Buffer to read data to
+ */
+static int idt_eeprom_read(struct idt_89hpesx_dev *pdev, u16 memaddr, u16 len,
+ u8 *buf)
+{
+ int ret;
+ u16 idx;
+
+ /* Read data byte-by-byte, retrying if it wasn't successful */
+ for (idx = 0; idx < len; idx++, memaddr++) {
+ /* Lock IDT SMBus device */
+ mutex_lock(&pdev->smb_mtx);
+
+ /* Just read the byte to the buffer */
+ ret = idt_eeprom_read_byte(pdev, memaddr, &buf[idx]);
+
+ /* Unlock IDT SMBus device */
+ mutex_unlock(&pdev->smb_mtx);
+
+ /* Return error if read operation failed */
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+/*===========================================================================
+ * CSR IO-operations
+ *===========================================================================
+ */
+
+/*
+ * idt_csr_write() - CSR write operation
+ * @pdev: Pointer to the driver data
+ * @csraddr: CSR address (with no two LS bits)
+ * @data: Data to be written to CSR
+ */
+static int idt_csr_write(struct idt_89hpesx_dev *pdev, u16 csraddr,
+ const u32 data)
+{
+ struct device *dev = &pdev->client->dev;
+ struct idt_csr_seq csrseq;
+ struct idt_smb_seq smbseq;
+ int ret;
+
+ /* Initialize SMBus sequence fields */
+ smbseq.ccode = pdev->iniccode | CCODE_CSR;
+ smbseq.data = (u8 *)&csrseq;
+
+ /* Lock IDT SMBus device */
+ mutex_lock(&pdev->smb_mtx);
+
+ /* Perform write operation */
+ smbseq.bytecnt = CSR_WR_CNT;
+ csrseq.cmd = pdev->inicsrcmd | CSR_OP_WRITE;
+ csrseq.csraddr = cpu_to_le16(csraddr);
+ csrseq.data = cpu_to_le32(data);
+ ret = pdev->smb_write(pdev, &smbseq);
+ if (ret != 0) {
+ dev_err(dev, "Failed to write 0x%04x: 0x%04x to csr",
+ CSR_REAL_ADDR(csraddr), data);
+ goto err_mutex_unlock;
+ }
+
+ /* Send CSR address to read data from */
+ smbseq.bytecnt = CSR_WRRD_CNT;
+ csrseq.cmd = pdev->inicsrcmd | CSR_OP_READ;
+ ret = pdev->smb_write(pdev, &smbseq);
+ if (ret != 0) {
+ dev_err(dev, "Failed to init csr address 0x%04x",
+ CSR_REAL_ADDR(csraddr));
+ goto err_mutex_unlock;
+ }
+
+ /* Perform read operation */
+ smbseq.bytecnt = CSR_RD_CNT;
+ ret = pdev->smb_read(pdev, &smbseq);
+ if (ret != 0) {
+ dev_err(dev, "Failed to read csr 0x%04x",
+ CSR_REAL_ADDR(csraddr));
+ goto err_mutex_unlock;
+ }
+
+ /* Check whether IDT successfully retrieved CSR data */
+ if (csrseq.cmd & (CSR_RERR | CSR_WERR)) {
+ dev_err(dev, "IDT failed to perform CSR r/w");
+ ret = -EREMOTEIO;
+ goto err_mutex_unlock;
+ }
+
+ /* Unlock IDT SMBus device */
+err_mutex_unlock:
+ mutex_unlock(&pdev->smb_mtx);
+
+ return ret;
+}
+
+/*
+ * idt_csr_read() - CSR read operation
+ * @pdev: Pointer to the driver data
+ * @csraddr: CSR address (with no two LS bits)
+ * @data: Data to be written to CSR
+ */
+static int idt_csr_read(struct idt_89hpesx_dev *pdev, u16 csraddr, u32 *data)
+{
+ struct device *dev = &pdev->client->dev;
+ struct idt_csr_seq csrseq;
+ struct idt_smb_seq smbseq;
+ int ret;
+
+ /* Initialize SMBus sequence fields */
+ smbseq.ccode = pdev->iniccode | CCODE_CSR;
+ smbseq.data = (u8 *)&csrseq;
+
+ /* Lock IDT SMBus device */
+ mutex_lock(&pdev->smb_mtx);
+
+ /* Send CSR register address before reading it */
+ smbseq.bytecnt = CSR_WRRD_CNT;
+ csrseq.cmd = pdev->inicsrcmd | CSR_OP_READ;
+ csrseq.csraddr = cpu_to_le16(csraddr);
+ ret = pdev->smb_write(pdev, &smbseq);
+ if (ret != 0) {
+ dev_err(dev, "Failed to init csr address 0x%04x",
+ CSR_REAL_ADDR(csraddr));
+ goto err_mutex_unlock;
+ }
+
+ /* Perform read operation */
+ smbseq.bytecnt = CSR_RD_CNT;
+ ret = pdev->smb_read(pdev, &smbseq);
+ if (ret != 0) {
+ dev_err(dev, "Failed to read csr 0x%04hx",
+ CSR_REAL_ADDR(csraddr));
+ goto err_mutex_unlock;
+ }
+
+ /* Check whether IDT successfully retrieved CSR data */
+ if (csrseq.cmd & (CSR_RERR | CSR_WERR)) {
+ dev_err(dev, "IDT failed to perform CSR r/w");
+ ret = -EREMOTEIO;
+ goto err_mutex_unlock;
+ }
+
+ /* Save data retrieved from IDT */
+ *data = le32_to_cpu(csrseq.data);
+
+ /* Unlock IDT SMBus device */
+err_mutex_unlock:
+ mutex_unlock(&pdev->smb_mtx);
+
+ return ret;
+}
+
+/*===========================================================================
+ * Sysfs-nodes IO-operations
+ *===========================================================================
+ */
+
+/*
+ * idt_sysfs_eeprom_write() - EEPROM sysfs-node write callback
+ * @filep: Pointer to the file system node
+ * @kobj: Pointer to the kernel object related to the sysfs-node
+ * @attr: Attributes of the file
+ * @buf: Buffer to write data to
+ * @off: Offset at which data should be written to
+ * @count: Number of bytes to write
+ */
+static ssize_t idt_sysfs_eeprom_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct idt_89hpesx_dev *pdev;
+ int ret;
+
+ /* Retrieve driver data */
+ pdev = to_pdev_kobj(kobj);
+
+ /* Perform EEPROM write operation */
+ ret = idt_eeprom_write(pdev, (u16)off, (u16)count, (u8 *)buf);
+ return (ret != 0 ? ret : count);
+}
+
+/*
+ * idt_sysfs_eeprom_read() - EEPROM sysfs-node read callback
+ * @filep: Pointer to the file system node
+ * @kobj: Pointer to the kernel object related to the sysfs-node
+ * @attr: Attributes of the file
+ * @buf: Buffer to write data to
+ * @off: Offset at which data should be written to
+ * @count: Number of bytes to write
+ */
+static ssize_t idt_sysfs_eeprom_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct idt_89hpesx_dev *pdev;
+ int ret;
+
+ /* Retrieve driver data */
+ pdev = to_pdev_kobj(kobj);
+
+ /* Perform EEPROM read operation */
+ ret = idt_eeprom_read(pdev, (u16)off, (u16)count, (u8 *)buf);
+ return (ret != 0 ? ret : count);
+}
+
+/*
+ * idt_dbgfs_csr_write() - CSR debugfs-node write callback
+ * @filep: Pointer to the file system file descriptor
+ * @buf: Buffer to read data from
+ * @count: Size of the buffer
+ * @offp: Offset within the file
+ *
+ * It accepts either "0x<reg addr>:0x<value>" for saving register address
+ * and writing value to specified DWORD register or "0x<reg addr>" for
+ * just saving register address in order to perform next read operation.
+ *
+ * WARNING No spaces are allowed. Incoming string must be strictly formated as:
+ * "<reg addr>:<value>". Register address must be aligned within 4 bytes
+ * (one DWORD).
+ */
+static ssize_t idt_dbgfs_csr_write(struct file *filep, const char __user *ubuf,
+ size_t count, loff_t *offp)
+{
+ struct idt_89hpesx_dev *pdev = filep->private_data;
+ char *colon_ch, *csraddr_str, *csrval_str;
+ int ret, csraddr_len, csrval_len;
+ u32 csraddr, csrval;
+ char *buf;
+
+ /* Copy data from User-space */
+ buf = kmalloc(count + 1, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = simple_write_to_buffer(buf, count, offp, ubuf, count);
+ if (ret < 0)
+ goto free_buf;
+ buf[count] = 0;
+
+ /* Find position of colon in the buffer */
+ colon_ch = strnchr(buf, count, ':');
+
+ /*
+ * If there is colon passed then new CSR value should be parsed as
+ * well, so allocate buffer for CSR address substring.
+ * If no colon is found, then string must have just one number with
+ * no new CSR value
+ */
+ if (colon_ch != NULL) {
+ csraddr_len = colon_ch - buf;
+ csraddr_str =
+ kmalloc(sizeof(char)*(csraddr_len + 1), GFP_KERNEL);
+ if (csraddr_str == NULL)
+ return -ENOMEM;
+ /* Copy the register address to the substring buffer */
+ strncpy(csraddr_str, buf, csraddr_len);
+ csraddr_str[csraddr_len] = '\0';
+ /* Register value must follow the colon */
+ csrval_str = colon_ch + 1;
+ csrval_len = strnlen(csrval_str, count - csraddr_len);
+ } else /* if (str_colon == NULL) */ {
+ csraddr_str = (char *)buf; /* Just to shut warning up */
+ csraddr_len = strnlen(csraddr_str, count);
+ csrval_str = NULL;
+ csrval_len = 0;
+ }
+
+ /* Convert CSR address to u32 value */
+ ret = kstrtou32(csraddr_str, 0, &csraddr);
+ if (ret != 0)
+ goto free_csraddr_str;
+
+ /* Check whether passed register address is valid */
+ if (csraddr > CSR_MAX || !IS_ALIGNED(csraddr, SZ_4)) {
+ ret = -EINVAL;
+ goto free_csraddr_str;
+ }
+
+ /* Shift register address to the right so to have u16 address */
+ csraddr >>= 2;
+
+ /* Parse new CSR value and send it to IDT, if colon has been found */
+ if (colon_ch != NULL) {
+ ret = kstrtou32(csrval_str, 0, &csrval);
+ if (ret != 0)
+ goto free_csraddr_str;
+
+ ret = idt_csr_write(pdev, (u16)csraddr, csrval);
+ if (ret != 0)
+ goto free_csraddr_str;
+ }
+
+ /* Save CSR address in the data structure for future read operations */
+ atomic_set(&pdev->csr, (int)csraddr);
+
+ /* Free memory only if colon has been found */
+free_csraddr_str:
+ if (colon_ch != NULL)
+ kfree(csraddr_str);
+
+ /* Free buffer allocated for data retrieved from User-space */
+free_buf:
+ kfree(buf);
+
+ return (ret != 0 ? ret : count);
+}
+
+/*
+ * idt_dbgfs_csr_read() - CSR debugfs-node read callback
+ * @filep: Pointer to the file system file descriptor
+ * @buf: Buffer to write data to
+ * @count: Size of the buffer
+ * @offp: Offset within the file
+ *
+ * It just prints the pair "0x<reg addr>:0x<value>" to passed buffer.
+ */
+#define CSRBUF_SIZE ((size_t)32)
+static ssize_t idt_dbgfs_csr_read(struct file *filep, char __user *ubuf,
+ size_t count, loff_t *offp)
+{
+ struct idt_89hpesx_dev *pdev = filep->private_data;
+ u32 csraddr, csrval;
+ char buf[CSRBUF_SIZE];
+ int ret, size;
+
+ /* Read current CSR address */
+ csraddr = atomic_read(&pdev->csr);
+
+ /* Perform CSR read operation */
+ ret = idt_csr_read(pdev, (u16)csraddr, &csrval);
+ if (ret != 0)
+ return ret;
+
+ /* Shift register address to the left so to have real address */
+ csraddr <<= 2;
+
+ /* Print the "0x<reg addr>:0x<value>" to buffer */
+ size = snprintf(buf, CSRBUF_SIZE, "0x%05x:0x%08x\n",
+ (unsigned int)csraddr, (unsigned int)csrval);
+
+ /* Copy data to User-space */
+ return simple_read_from_buffer(ubuf, count, offp, buf, size);
+}
+
+/*
+ * eeprom_attribute - EEPROM sysfs-node attributes
+ *
+ * NOTE Size will be changed in compliance with OF node. EEPROM attribute will
+ * be read-only as well if the corresponding flag is specified in OF node.
+ */
+BIN_ATTR(eeprom, 0644, idt_sysfs_eeprom_read, idt_sysfs_eeprom_write,
+ EEPROM_DEF_SIZE);
+
+/*
+ * csr_dbgfs_ops - CSR debugfs-node read/write operations
+ */
+static const struct file_operations csr_dbgfs_ops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .write = idt_dbgfs_csr_write,
+ .read = idt_dbgfs_csr_read
+};
+
+/*===========================================================================
+ * Driver init/deinit methods
+ *===========================================================================
+ */
+
+/*
+ * idt_set_defval() - set default device data parameters
+ * @pdev: Pointer to the driver data
+ */
+static void idt_set_defval(struct idt_89hpesx_dev *pdev)
+{
+ /* If OF info is missing then use next values */
+ pdev->eesize = EEPROM_DEF_SIZE;
+ pdev->eero = true;
+ pdev->inieecmd = 0;
+ pdev->eeaddr = EEPROM_DEF_ADDR << 1;
+}
+
+#ifdef CONFIG_OF
+/*
+ * idt_get_ofdata() - get IDT i2c-device parameters from device tree
+ * @pdev: Pointer to the driver data
+ */
+static void idt_get_ofdata(struct idt_89hpesx_dev *pdev)
+{
+ struct device_node *node = pdev->client->dev.of_node;
+ struct device *dev = &pdev->client->dev;
+ const __be32 *val;
+
+ /* Read dts node parameters */
+ if (node) {
+ /* Get EEPROM size from 'idt,eesize' */
+ val = of_get_property(node, "idt,eesize", NULL);
+ if (val != NULL) {
+ pdev->eesize = be32_to_cpup(val);
+ if (!is_power_of_2(pdev->eesize))
+ dev_warn(dev,
+ "EEPROM size %u is not power of 2",
+ pdev->eesize);
+ } else /* if (val == NULL) */ {
+ pdev->eesize = EEPROM_DEF_SIZE;
+ dev_warn(dev, "No EEPROM size, set default %u bytes",
+ pdev->eesize);
+ }
+
+ /* Get custom EEPROM address from 'idt,eeaddr' */
+ val = of_get_property(node, "idt,eeaddr", NULL);
+ if (val != NULL) {
+ pdev->inieecmd = EEPROM_USA;
+ pdev->eeaddr = be32_to_cpup(val) << 1;
+ } else /* if (val != NULL) */ {
+ pdev->inieecmd = 0;
+ pdev->eeaddr = EEPROM_DEF_ADDR << 1;
+ }
+
+ /* Check EEPROM 'read-only' flag */
+ if (of_get_property(node, "read-only", NULL))
+ pdev->eero = true;
+ else /* if (!of_get_property(node, "read-only", NULL)) */
+ pdev->eero = false;
+ } else {
+ dev_warn(dev, "No dts node, set default values");
+ idt_set_defval(pdev);
+ }
+}
+#else
+static void idt_get_ofdata(struct idt_89hpesx_dev *pdev)
+{
+ struct device *dev = &pdev->client->dev;
+
+ dev_warn(dev, "OF table is unsupported, set default values");
+
+ /* Nothing we can do, just set the default values */
+ idt_set_defval(pdev);
+}
+#endif /* CONFIG_OF */
+
+/*
+ * idt_create_pdev() - create and init data structure of the driver
+ * @client: i2c client of IDT PCIe-switch device
+ */
+static struct idt_89hpesx_dev *idt_create_pdev(struct i2c_client *client)
+{
+ struct idt_89hpesx_dev *pdev;
+
+ /* Allocate memory for driver data */
+ pdev = devm_kmalloc(&client->dev, sizeof(struct idt_89hpesx_dev),
+ GFP_KERNEL);
+ if (pdev == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ /* Initialize basic fields of the data */
+ pdev->client = client;
+ i2c_set_clientdata(client, pdev);
+
+ /* Read OF nodes information */
+ idt_get_ofdata(pdev);
+
+ /* Initialize basic CSR CMD field - use full DWORD-sized r/w ops */
+ pdev->inicsrcmd = CSR_DWE;
+ atomic_set(&pdev->csr, CSR_DEF);
+
+ /* Enable Packet Error Checking if it's supported by adapter */
+ if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_PEC)) {
+ pdev->iniccode = CCODE_PEC;
+ client->flags |= I2C_CLIENT_PEC;
+ } else /* PEC is unsupported */ {
+ pdev->iniccode = 0;
+ }
+
+ dev_dbg(&client->dev, "IDT 89HPESx data created");
+
+ return pdev;
+}
+
+/*
+ * idt_free_pdev() - free data structure of the driver
+ * @pdev: Pointer to the driver data
+ */
+static void idt_free_pdev(struct idt_89hpesx_dev *pdev)
+{
+ /* Clear driver data from device private field */
+ i2c_set_clientdata(pdev->client, NULL);
+
+ /* Just free memory allocated for data */
+ devm_kfree(&pdev->client->dev, pdev);
+
+ dev_dbg(&pdev->client->dev, "IDT 89HPESx data discarded");
+}
+
+/*
+ * idt_set_smbus_ops() - set supported SMBus operations
+ * @pdev: Pointer to the driver data
+ * Return status of smbus check operations
+ */
+static int idt_set_smbus_ops(struct idt_89hpesx_dev *pdev)
+{
+ struct i2c_adapter *adapter = pdev->client->adapter;
+ struct device *dev = &pdev->client->dev;
+
+ /* Check i2c adapter read functionality */
+ if (i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA)) {
+ pdev->smb_read = idt_smb_read_block;
+ dev_dbg(dev, "SMBus block-read op chosen");
+ } else if (i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+ pdev->smb_read = idt_smb_read_i2c_block;
+ dev_dbg(dev, "SMBus i2c-block-read op chosen");
+ } else if (i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_READ_WORD_DATA) &&
+ i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
+ pdev->smb_read = idt_smb_read_word;
+ dev_warn(dev, "Use slow word/byte SMBus read ops");
+ } else if (i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
+ pdev->smb_read = idt_smb_read_byte;
+ dev_warn(dev, "Use slow byte SMBus read op");
+ } else /* no supported smbus read operations */ {
+ dev_err(dev, "No supported SMBus read op");
+ return -EPFNOSUPPORT;
+ }
+
+ /* Check i2c adapter write functionality */
+ if (i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)) {
+ pdev->smb_write = idt_smb_write_block;
+ dev_dbg(dev, "SMBus block-write op chosen");
+ } else if (i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
+ pdev->smb_write = idt_smb_write_i2c_block;
+ dev_dbg(dev, "SMBus i2c-block-write op chosen");
+ } else if (i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_WRITE_WORD_DATA) &&
+ i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
+ pdev->smb_write = idt_smb_write_word;
+ dev_warn(dev, "Use slow word/byte SMBus write op");
+ } else if (i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
+ pdev->smb_write = idt_smb_write_byte;
+ dev_warn(dev, "Use slow byte SMBus write op");
+ } else /* no supported smbus write operations */ {
+ dev_err(dev, "No supported SMBus write op");
+ return -EPFNOSUPPORT;
+ }
+
+ /* Initialize IDT SMBus slave interface mutex */
+ mutex_init(&pdev->smb_mtx);
+
+ dev_dbg(dev, "SMBus functionality successfully checked");
+
+ return 0;
+}
+
+/*
+ * idt_check_dev() - check whether it's really IDT 89HPESx device
+ * @pdev: Pointer to the driver data
+ * Return status of i2c adapter check operation
+ */
+static int idt_check_dev(struct idt_89hpesx_dev *pdev)
+{
+ struct device *dev = &pdev->client->dev;
+ u32 viddid;
+ int ret;
+
+ /* Read VID and DID directly from IDT memory space */
+ ret = idt_csr_read(pdev, IDT_VIDDID_CSR, &viddid);
+ if (ret != 0) {
+ dev_err(dev, "Failed to read VID/DID");
+ return ret;
+ }
+
+ /* Check whether it's IDT device */
+ if ((viddid & IDT_VID_MASK) != PCI_VENDOR_ID_IDT) {
+ dev_err(dev, "Got unsupported VID/DID: 0x%08x", viddid);
+ return -ENODEV;
+ }
+
+ dev_info(dev, "Found IDT 89HPES device VID:0x%04x, DID:0x%04x",
+ (viddid & IDT_VID_MASK), (viddid >> 16));
+
+ return 0;
+}
+
+/*
+ * idt_create_sysfs_files() - create sysfs attribute files
+ * @pdev: Pointer to the driver data
+ * Return status of operation
+ */
+static int idt_create_sysfs_files(struct idt_89hpesx_dev *pdev)
+{
+ struct device *dev = &pdev->client->dev;
+ int ret;
+
+ /* Allocate memory for attribute file */
+ pdev->ee_file = devm_kmalloc(dev, sizeof(*pdev->ee_file), GFP_KERNEL);
+ if (!pdev->ee_file)
+ return -ENOMEM;
+
+ /* Copy the declared EEPROM attr structure to change some of fields */
+ memcpy(pdev->ee_file, &bin_attr_eeprom, sizeof(*pdev->ee_file));
+
+ /* In case of read-only EEPROM get rid of write ability */
+ if (pdev->eero) {
+ pdev->ee_file->attr.mode &= ~0200;
+ pdev->ee_file->write = NULL;
+ }
+ /* Create EEPROM sysfs file */
+ pdev->ee_file->size = pdev->eesize;
+ ret = sysfs_create_bin_file(&dev->kobj, pdev->ee_file);
+ if (ret != 0) {
+ kfree(pdev->ee_file);
+ dev_err(dev, "Failed to create EEPROM sysfs-node");
+ return ret;
+ }
+
+ dev_dbg(dev, "Sysfs-files created");
+
+ return 0;
+}
+
+/*
+ * idt_remove_sysfs_files() - remove sysfs attribute files
+ * @pdev: Pointer to the driver data
+ */
+static void idt_remove_sysfs_files(struct idt_89hpesx_dev *pdev)
+{
+ struct device *dev = &pdev->client->dev;
+
+ /* Remove EEPROM sysfs file */
+ sysfs_remove_bin_file(&dev->kobj, pdev->ee_file);
+
+ /* Free memory allocated for bin_attribute structure */
+ kfree(pdev->ee_file);
+
+ dev_dbg(dev, "Sysfs-files removed");
+}
+
+/*
+ * idt_create_dbgfs_files() - create debugfs files
+ * @pdev: Pointer to the driver data
+ * Return status of operation
+ */
+#define CSRNAME_LEN ((size_t)32)
+static int idt_create_dbgfs_files(struct idt_89hpesx_dev *pdev)
+{
+ struct device *dev = &pdev->client->dev;
+ struct i2c_client *cli = pdev->client;
+ char fname[CSRNAME_LEN];
+
+ /* Initialize basic value of CSR debugfs dentries */
+ pdev->csr_dir = NULL;
+ pdev->csr_file = NULL;
+
+ /* Return failure if root directory doesn't exist */
+ if (!csr_dbgdir) {
+ dev_dbg(dev, "No Debugfs root directory");
+ return -EINVAL;
+ }
+
+ /* Create Debugfs directory for CSR file */
+ snprintf(fname, CSRNAME_LEN, "%d-%04hx", cli->adapter->nr, cli->addr);
+ pdev->csr_dir = debugfs_create_dir(fname, csr_dbgdir);
+ if (IS_ERR_OR_NULL(pdev->csr_dir)) {
+ dev_err(dev, "Failed to create CSR node directory");
+ return -EINVAL;
+ }
+
+ /* Create Debugfs file for CSR read/write operations */
+ pdev->csr_file = debugfs_create_file(cli->name, 0600,
+ pdev->csr_dir, pdev, &csr_dbgfs_ops);
+ if (IS_ERR_OR_NULL(pdev->csr_file)) {
+ dev_err(dev, "Failed to create CSR dbgfs-node");
+ debugfs_remove_recursive(pdev->csr_dir);
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "Debugfs-files created");
+
+ return 0;
+}
+
+/*
+ * idt_remove_dbgfs_files() - remove debugfs files
+ * @pdev: Pointer to the driver data
+ */
+static void idt_remove_dbgfs_files(struct idt_89hpesx_dev *pdev)
+{
+ /* Remove CSR directory and it sysfs-node */
+ debugfs_remove_recursive(pdev->csr_dir);
+
+ dev_dbg(&pdev->client->dev, "Debugfs-files removed");
+}
+
+/*
+ * idt_probe() - IDT 89HPESx driver probe() callback method
+ */
+static int idt_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct idt_89hpesx_dev *pdev;
+ int ret;
+
+ /* Create driver data */
+ pdev = idt_create_pdev(client);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ /* Set SMBus operations */
+ ret = idt_set_smbus_ops(pdev);
+ if (ret != 0)
+ goto err_free_pdev;
+
+ /* Check whether it is truly IDT 89HPESx device */
+ ret = idt_check_dev(pdev);
+ if (ret != 0)
+ goto err_free_pdev;
+
+ /* Create sysfs files */
+ ret = idt_create_sysfs_files(pdev);
+ if (ret != 0)
+ goto err_free_pdev;
+
+ /* Create debugfs files */
+ (void)idt_create_dbgfs_files(pdev);
+
+ dev_dbg(&client->dev, "IDT %s device probed", id->name);
+
+ return 0;
+
+err_free_pdev:
+ idt_free_pdev(pdev);
+
+ return ret;
+}
+
+/*
+ * idt_remove() - IDT 89HPESx driver remove() callback method
+ */
+static int idt_remove(struct i2c_client *client)
+{
+ struct idt_89hpesx_dev *pdev = i2c_get_clientdata(client);
+
+ /* Remove debugfs files first */
+ idt_remove_dbgfs_files(pdev);
+
+ /* Remove sysfs files */
+ idt_remove_sysfs_files(pdev);
+
+ /* Discard driver data structure */
+ idt_free_pdev(pdev);
+
+ dev_dbg(&client->dev, "IDT 89HPESx device removed");
+
+ return 0;
+}
+
+/*
+ * idt_ids - supported IDT 89HPESx devices
+ */
+static const struct i2c_device_id idt_ids[] = {
+ { "89hpes8nt2", 0 },
+ { "89hpes12nt3", 0 },
+
+ { "89hpes24nt6ag2", 0 },
+ { "89hpes32nt8ag2", 0 },
+ { "89hpes32nt8bg2", 0 },
+ { "89hpes12nt12g2", 0 },
+ { "89hpes16nt16g2", 0 },
+ { "89hpes24nt24g2", 0 },
+ { "89hpes32nt24ag2", 0 },
+ { "89hpes32nt24bg2", 0 },
+
+ { "89hpes12n3", 0 },
+ { "89hpes12n3a", 0 },
+ { "89hpes24n3", 0 },
+ { "89hpes24n3a", 0 },
+
+ { "89hpes32h8", 0 },
+ { "89hpes32h8g2", 0 },
+ { "89hpes48h12", 0 },
+ { "89hpes48h12g2", 0 },
+ { "89hpes48h12ag2", 0 },
+ { "89hpes16h16", 0 },
+ { "89hpes22h16", 0 },
+ { "89hpes22h16g2", 0 },
+ { "89hpes34h16", 0 },
+ { "89hpes34h16g2", 0 },
+ { "89hpes64h16", 0 },
+ { "89hpes64h16g2", 0 },
+ { "89hpes64h16ag2", 0 },
+
+ /* { "89hpes3t3", 0 }, // No SMBus-slave iface */
+ { "89hpes12t3g2", 0 },
+ { "89hpes24t3g2", 0 },
+ /* { "89hpes4t4", 0 }, // No SMBus-slave iface */
+ { "89hpes16t4", 0 },
+ { "89hpes4t4g2", 0 },
+ { "89hpes10t4g2", 0 },
+ { "89hpes16t4g2", 0 },
+ { "89hpes16t4ag2", 0 },
+ { "89hpes5t5", 0 },
+ { "89hpes6t5", 0 },
+ { "89hpes8t5", 0 },
+ { "89hpes8t5a", 0 },
+ { "89hpes24t6", 0 },
+ { "89hpes6t6g2", 0 },
+ { "89hpes24t6g2", 0 },
+ { "89hpes16t7", 0 },
+ { "89hpes32t8", 0 },
+ { "89hpes32t8g2", 0 },
+ { "89hpes48t12", 0 },
+ { "89hpes48t12g2", 0 },
+ { /* END OF LIST */ }
+};
+MODULE_DEVICE_TABLE(i2c, idt_ids);
+
+/*
+ * idt_driver - IDT 89HPESx driver structure
+ */
+static struct i2c_driver idt_driver = {
+ .driver = {
+ .name = IDT_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = idt_probe,
+ .remove = idt_remove,
+ .id_table = idt_ids,
+};
+
+/*
+ * idt_init() - IDT 89HPESx driver init() callback method
+ */
+static int __init idt_init(void)
+{
+ /* Create Debugfs directory first */
+ if (debugfs_initialized())
+ csr_dbgdir = debugfs_create_dir("idt_csr", NULL);
+
+ /* Add new i2c-device driver */
+ return i2c_add_driver(&idt_driver);
+}
+module_init(idt_init);
+
+/*
+ * idt_exit() - IDT 89HPESx driver exit() callback method
+ */
+static void __exit idt_exit(void)
+{
+ /* Discard debugfs directory and all files if any */
+ debugfs_remove_recursive(csr_dbgdir);
+
+ /* Unregister i2c-device driver */
+ i2c_del_driver(&idt_driver);
+}
+module_exit(idt_exit);
--
2.6.6
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v2 0/2] eeprom: Add IDT 89HPESx EEPROM/CSR driver
From: Serge Semin @ 2016-11-28 22:38 UTC (permalink / raw)
To: gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A, andrew-g2DYL2Zd6BY,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8
Cc: Sergey.Semin-vHJ8rsvMqnUPfZBKTuL5GA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Serge Semin
In-Reply-To: <1475450025-29507-1-git-send-email-fancer.lancer-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Following changes are made in accordance with Greg KH notes as well as
fixing some found issues:
- Get rid of dev_*_idt() macros
- IDT CSR debug file is moved to debugfs
- BIN_ATTR is used to declare sysfs binary attribute
- Moved bindings file to a separate patch
- Need to create a specific bin_attribute structure for each device
- Perform a few read retries with delays if EEPROM is busy
Signed-off-by: Serge Semin <fancer.lancer-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Serge Semin (2):
MISC eeprom: Add IDT 89HPESx EEPROM/CSR driver
MISC eeprom: Add IDT 89HPESx driver bindings file
.../devicetree/bindings/misc/idt_89hpesx.txt | 41 +
drivers/misc/eeprom/Kconfig | 10 +
drivers/misc/eeprom/Makefile | 1 +
drivers/misc/eeprom/idt_89hpesx.c | 1577 ++++++++++++++++++++
4 files changed, 1629 insertions(+)
create mode 100644 Documentation/devicetree/bindings/misc/idt_89hpesx.txt
create mode 100644 drivers/misc/eeprom/idt_89hpesx.c
--
2.6.6
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v3 4/4] [media] dt-bindings: add TI VPIF documentation
From: Kevin Hilman @ 2016-11-28 22:30 UTC (permalink / raw)
To: Rob Herring
Cc: linux-media-u79uwXL29TY76Z2rM5mHXA, Hans Verkuil,
devicetree-u79uwXL29TY76Z2rM5mHXA, Sekhar Nori, Axel Haslam,
Bartosz Gołaszewski, Alexandre Bailon, David Lechner
In-Reply-To: <20161128213822.26oeyzkht5jz5gd3@rob-hp-laptop>
Hi Rob,
Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> writes:
> On Tue, Nov 22, 2016 at 07:52:44AM -0800, Kevin Hilman wrote:
>> Signed-off-by: Kevin Hilman <khilman-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
>> ---
>> .../bindings/media/ti,da850-vpif-capture.txt | 65 ++++++++++++++++++++++
>> .../devicetree/bindings/media/ti,da850-vpif.txt | 8 +++
>> 2 files changed, 73 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/media/ti,da850-vpif-capture.txt
>> create mode 100644 Documentation/devicetree/bindings/media/ti,da850-vpif.txt
>>
>> diff --git a/Documentation/devicetree/bindings/media/ti,da850-vpif-capture.txt b/Documentation/devicetree/bindings/media/ti,da850-vpif-capture.txt
>> new file mode 100644
>> index 000000000000..c447ac482c1d
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/media/ti,da850-vpif-capture.txt
>> @@ -0,0 +1,65 @@
>> +Texas Instruments VPIF Capture
>> +------------------------------
>> +
>> +The TI Video Port InterFace (VPIF) capture component is the primary
>> +component for video capture on the DA850 family of TI DaVinci SoCs.
>> +
>> +TI Document number reference: SPRUH82C
>> +
>> +Required properties:
>> +- compatible: must be "ti,da850-vpif-capture"
>> +- reg: physical base address and length of the registers set for the device;
>> +- interrupts: should contain IRQ line for the VPIF
>> +
>> +VPIF capture has a 16-bit parallel bus input, supporting 2 8-bit
>> +channels or a single 16-bit channel. It should contain at least one
>> +port child node with child 'endpoint' node. Please refer to the
>> +bindings defined in
>> +Documentation/devicetree/bindings/media/video-interfaces.txt.
>> +
>> +Example using 2 8-bit input channels, one of which is connected to an
>> +I2C-connected TVP5147 decoder:
>> +
>> + vpif_capture: video-capture@0x00217000 {
>> + reg = <0x00217000 0x1000>;
>> + interrupts = <92>;
>> +
>> + port {
>> + vpif_ch0: endpoint@0 {
>> + reg = <0>;
>> + bus-width = <8>;
>> + remote-endpoint = <&composite>;
>> + };
>> +
>> + vpif_ch1: endpoint@1 {
>
> I think probably channels here should be ports rather than endpoints.
> AIUI, having multiple endpoints is for cases like a mux or 1 to many
> connections. There's only one data flow, but multiple sources or sinks.
Looking at this closer... , I used an endpoint because it's bascially a
16-bit parallel bus, that can be configured as (up to) 2 8-bit
"channels. So, based on the video-interfaces.txt doc, I configured this
as a single port, with (up to) 2 endpoints. That also allows me to
connect output of the decoder directly, using the remote-endpoint
property.
So I guess I'm not fully understanding your suggestion.
Kevin
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v3 4/4] [media] dt-bindings: add TI VPIF documentation
From: Kevin Hilman @ 2016-11-28 22:16 UTC (permalink / raw)
To: Rob Herring
Cc: linux-media-u79uwXL29TY76Z2rM5mHXA, Hans Verkuil,
devicetree-u79uwXL29TY76Z2rM5mHXA, Sekhar Nori, Axel Haslam,
Bartosz Gołaszewski, Alexandre Bailon, David Lechner
In-Reply-To: <20161128213822.26oeyzkht5jz5gd3@rob-hp-laptop>
Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> writes:
> On Tue, Nov 22, 2016 at 07:52:44AM -0800, Kevin Hilman wrote:
>> Signed-off-by: Kevin Hilman <khilman-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
>> ---
>> .../bindings/media/ti,da850-vpif-capture.txt | 65 ++++++++++++++++++++++
>> .../devicetree/bindings/media/ti,da850-vpif.txt | 8 +++
>> 2 files changed, 73 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/media/ti,da850-vpif-capture.txt
>> create mode 100644 Documentation/devicetree/bindings/media/ti,da850-vpif.txt
>>
>> diff --git a/Documentation/devicetree/bindings/media/ti,da850-vpif-capture.txt b/Documentation/devicetree/bindings/media/ti,da850-vpif-capture.txt
>> new file mode 100644
>> index 000000000000..c447ac482c1d
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/media/ti,da850-vpif-capture.txt
>> @@ -0,0 +1,65 @@
>> +Texas Instruments VPIF Capture
>> +------------------------------
>> +
>> +The TI Video Port InterFace (VPIF) capture component is the primary
>> +component for video capture on the DA850 family of TI DaVinci SoCs.
>> +
>> +TI Document number reference: SPRUH82C
>> +
>> +Required properties:
>> +- compatible: must be "ti,da850-vpif-capture"
>> +- reg: physical base address and length of the registers set for the device;
>> +- interrupts: should contain IRQ line for the VPIF
>> +
>> +VPIF capture has a 16-bit parallel bus input, supporting 2 8-bit
>> +channels or a single 16-bit channel. It should contain at least one
>> +port child node with child 'endpoint' node. Please refer to the
>> +bindings defined in
>> +Documentation/devicetree/bindings/media/video-interfaces.txt.
>> +
>> +Example using 2 8-bit input channels, one of which is connected to an
>> +I2C-connected TVP5147 decoder:
>> +
>> + vpif_capture: video-capture@0x00217000 {
>
> Drop the 0x00.
>
>> + compatible = "ti,da850-vpif-capture";
>> + reg = <0x00217000 0x1000>;
>> + interrupts = <92>;
>> +
>> + port {
>> + vpif_ch0: endpoint@0 {
>> + reg = <0>;
>
> This is missing #size-cells and #addr-cells.
>
Yup.
>> + bus-width = <8>;
>> + remote-endpoint = <&composite>;
>> + };
>> +
>> + vpif_ch1: endpoint@1 {
>
> I think probably channels here should be ports rather than endpoints.
> AIUI, having multiple endpoints is for cases like a mux or 1 to many
> connections. There's only one data flow, but multiple sources or sinks.
OK.
>> + reg = <1>;
>> + bus-width = <8>;
>> + data-shift = <8>;
>> + };
>> + };
>> + };
>> +
>> +[ ... ]
>> +
>> +&i2c0 {
>> +
>> + tvp5147@5d {
>> + compatible = "ti,tvp5147";
>> + reg = <0x5d>;
>> + status = "okay";
>> +
>> + port {
>> + composite: endpoint {
>> + hsync-active = <1>;
>> + vsync-active = <1>;
>> + pclk-sample = <0>;
>> +
>> + /* VPIF channel 0 (lower 8-bits) */
>> + remote-endpoint = <&vpif_ch0>;
>> + bus-width = <8>;
>> + };
>> + };
>> + };
>> +
>> +};
>> diff --git a/Documentation/devicetree/bindings/media/ti,da850-vpif.txt b/Documentation/devicetree/bindings/media/ti,da850-vpif.txt
>> new file mode 100644
>> index 000000000000..d004e600aabe
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/media/ti,da850-vpif.txt
>> @@ -0,0 +1,8 @@
>> +Texas Instruments VPIF
>> +----------------------
>> +
>> +The Video Port InterFace (VPIF) is the core component for video output
>> +and capture on DA850 TI Davinci SoCs.
>> +
>> +- compatible: must be "ti,da850-vpif"
>> +- reg: physical base address and length of the registers set for the device;
>
> That's it? How does this block relate to the capture block?
I separated them because the current legacy drivers are separated into 3
different platform drivers.
However, after some discussions with Laurent, I'm going to just create a
single VPIF node with input (capture) and output (display) ports, and
then have to tweak the existing drivers a bit more than I had wanted to.
IOW, I was lazy.
Kevin
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] ALSA SoC MAX98927 driver - Initial release
From: Rob Herring @ 2016-11-28 22:01 UTC (permalink / raw)
To: Ryan Lee
Cc: lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
arnd-r2nGTMty4D4, michael-dyjBcgdgk7Pe9wHmmfpqLFaTQe2KTcn/,
oder_chiou-Rasf1IRRPZFBDgjK7y7TUQ,
yesanishhere-Re5JQEeQqe8AvxtiuMwx3w,
jacob-EZCvousvhKUZux3j3Bed6dkegs52MxvZ,
Damien.Horsley-1AXoQHu6uovQT0dZR+AlfA,
bardliao-Rasf1IRRPZFBDgjK7y7TUQ,
kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
petr-Qh/3xLP0EvwAvxtiuMwx3w, lars-Qo5EllUWu/uELgA04lAiVw,
nh6z-fFIq/eER6g8, alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1479877026-5172-1-git-send-email-RyanS.Lee-zxKO94PEStzToO697jQleEEOCMrvLtNR@public.gmane.org>
On Wed, Nov 23, 2016 at 01:57:06PM +0900, Ryan Lee wrote:
> Signed-off-by: Ryan Lee <ryans.lee-zxKO94PEStzToO697jQleEEOCMrvLtNR@public.gmane.org>
> ---
> .../devicetree/bindings/sound/max98927.txt | 32 +
> sound/soc/codecs/Kconfig | 5 +
> sound/soc/codecs/Makefile | 2 +
> sound/soc/codecs/max98927.c | 954 +++++++++++++++
> sound/soc/codecs/max98927.h | 1253 ++++++++++++++++++++
> 5 files changed, 2246 insertions(+)
> create mode 100755 Documentation/devicetree/bindings/sound/max98927.txt
> mode change 100644 => 100755 sound/soc/codecs/Kconfig
> mode change 100644 => 100755 sound/soc/codecs/Makefile
> create mode 100755 sound/soc/codecs/max98927.c
> create mode 100755 sound/soc/codecs/max98927.h
>
> diff --git a/Documentation/devicetree/bindings/sound/max98927.txt b/Documentation/devicetree/bindings/sound/max98927.txt
> new file mode 100755
> index 0000000..ddcd332
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/max98927.txt
> @@ -0,0 +1,32 @@
> +max98927 audio CODEC
> +
> +This device supports I2C.
> +
> +Required properties:
> +
> + - compatible : "maxim,max98927"
> +
> + - vmon-slot-no : slot number used to send voltage information
> + or in inteleave mode this will be used as
s/inteleave/interleave/
What is the range of values?
> + interleave slot.
> +
> + - imon-slot-no : slot number used to send current information
Range?
> +
> + - interleave-mode : When using two MAX98927 in a system it is
These all need vendor prefix.
> + possible to create ADC data that that will
> + overflow the frame size. Digital Audio Interleave
> + mode provides a means to output VMON and IMON data
> + from two devices on a single DOUT line when running
> + smaller frames sizes such as 32 BCLKS per LRCLK or
> + 48 BCLKS per LRCLK.
> +
> + - reg : the I2C address of the device for I2C
> +
> +Example:
> +
> +codec: max98927@3a {
> + compatible = "maxim,max98927";
> + vmon-slot-no = <1>;
> + imon-slot-no = <0>;
> + reg = <0x3a>;
> +};
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: Question regarding clocks in the DW-HDMI DT bindings
From: Michael Turquette @ 2016-11-28 21:56 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Linux-DT, Stephen Boyd, DRI mailing list, nickey.yang, Andy Yan,
Vladimir Zapolskiy
In-Reply-To: <2404891.arL9itCrmb@avalon>
Hi Laurent, all,
On Fri, Nov 25, 2016 at 7:22 AM, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
> Hi Andy,
>
> On Friday 25 Nov 2016 10:56:53 Andy Yan wrote:
>> On 2016年11月25日 07:26, Laurent Pinchart wrote:
>> > On Friday 25 Nov 2016 00:16:00 Vladimir Zapolskiy wrote:
>> >> On 11/25/2016 12:07 AM, Fabio Estevam wrote:
>> >>> On Thu, Nov 24, 2016 at 7:16 PM, Laurent Pinchart wrote:
>> >>>> Hi Andy,
>> >>>>
>> >>>> As the author of the DW-HDMI DT bindings this question is addressed to
>> >>>> you, but information from anyone is more than welcome.
>> >>>>
>> >>>> The DT bindings specify two clocks named "iahb" and "isfr" but don't
>> >>>> describe them. While I assume that the "isfr" clock corresponds to the
>> >>>> "isfrclk" input signal of the DW HDMI, there is no "iahb" clock
>> >>>> described in the IP core datasheet.
>> >>>
>> >>> i.MX6Q has a DW-HDMI IP block.
>> >>>
>> >>> The names in the devicetree binding matches the ones listed at the
>> >>> i.MX6Q Reference Manual - Table 33-1. HDMI Clocks
>> >>
>> >> correct, for your convenience the table is copied below:
>> >>
>> >> Clock name | Clock Root | Description
>> >> -----------+--------------------+---------------------------------------
>> >> iahbclk | ahb_clk_root | Bus clock
>> >> icecclk | ckil_sync_clk_root | CEC low-frequency clock (32kHZ)
>> >> ihclk | ahb_clk_root | Module clock
>> >> isfrclk | video_27m_clk_root | Internal SFR clock (video clock
>> >> 27MHz)
>> >>
>> >> Here AHB stands for ARM Advanced High-performance Bus.
>> >
>> > That's what I suspected. I believe the "iahb" name is wrong, as the DW
>> > HDMI TX IP core clearly documents the bus clock as being called
>> > "iapbclk". We could rename that in the DT bindings (with compatibility
>> > code in the driver to keep supporting the old name) but it might not be
>> > worth it. The bindings should however document that the "iahb" clock is
>> > the IP core's "iapbclk" bus clock.
>>
>> I got the clock name from I.MX6Q TRM, I also checked the name again
>> with Rockchip IC design team now, hope to get some new information soon.
>
> Thank you. While at it, could you ask them which version of the DW HDMI IP
> used in the SoC ?
>
>> > Another question I have about the bus clock (CC'ing the devicetree mailing
>> > list as well as the clock maintainers) is whether it should be made
>> > optional. The clock is obviously mandatory from a hardware point of view
>> > (given that APB is a synchronous bus and thus requires a clock), but in
>> > some SoCs (specifically for the Renesas SoCs) that clock is always on and
>> > can't be controlled. We already omit bus clocks in DT for most IP cores
>> > when the clock can never be controlled (and we also omit a bunch of other
>> > clocks that we don't even know exist), so it could make sense to make the
>> > clock optional. Otherwise there would be runtime overhead trying to handle
>> > a clock that can't be controlled.
>>
>> If this is the case on Renesas SOCs, we can consider make the clock as
>> optional. Or move all the clock operations to platform specific
>> code(dw_hdmi-rockchip.c/dw_hdmi-imx.c)?
>
> I'd prefer keeping the code generic, otherwise we'd end up with platform-
> specific code that would perform the same operations on most platforms. I'll
> submit a patch soon to make the clock optional, we can discuss it then.
Yes, let's keep the code generic. Absence of a "standard' clock is OK
and we should accept the small overhead incurred in providing a
solution that works for everyone. This prevents hardware-specific
hacks in the driver.
Related: we really should model bus clocks whenever possible. I've
seen other attempts to merge functional/logic and bus clocks into a
single entity (e.g. a single struct clk_hw/clk_core that turns both
clocks on and off) and this defeats some fine-grained power management
scenarios that the hardware designers had in mind when creating
separate controls for the clocks.
Regards,
Mike
>
>> >> By the way while we're discussing DW HDMI bindings specific to iMX,
>> >> I would recommend to remove utterly hackish and iMX only "gpr"
>> >> property from the example in bindings/display/bridge/dw_hdmi.txt
>
> --
> Regards,
>
> Laurent Pinchart
>
--
Michael Turquette
CEO
BayLibre - At the Heart of Embedded Linux
http://baylibre.com/
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH 1/3] devicetree: bindings: pinctrl: Add binding for ti,da850-pupd
From: Rob Herring @ 2016-11-28 21:54 UTC (permalink / raw)
To: David Lechner
Cc: Linus Walleij, Mark Rutland, Sekhar Nori, Kevin Hilman,
linux-gpio, devicetree, linux-kernel, linux-arm-kernel,
Axel Haslam, Alexandre Bailon, Bartosz Gołaszewski
In-Reply-To: <1479871767-20160-2-git-send-email-david@lechnology.com>
On Tue, Nov 22, 2016 at 09:29:25PM -0600, David Lechner wrote:
> Device-tree bindings for TI DA8XX/OMAP-L138/AM18XX pullup/pulldown
> pinconf controller.
>
> Signed-off-by: David Lechner <david@lechnology.com>
> ---
> .../devicetree/bindings/pinctrl/ti,da850-pupd.txt | 55 ++++++++++++++++++++++
> 1 file changed, 55 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/pinctrl/ti,da850-pupd.txt
Acked-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH 3/5] arm64: dts: Enable SDHCI for Nexus 5X (msm8992)
From: Rob Herring @ 2016-11-28 21:53 UTC (permalink / raw)
To: Jeremy McNicoll
Cc: linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
linux-soc-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-mmc-u79uwXL29TY76Z2rM5mHXA,
andy.gross-QSEj5FYQhm4dnm+yROfE0A, sboyd-sgV2jX0FEOL9JmXXK+q4OQ,
arnd-r2nGTMty4D4, bjorn.andersson-QSEj5FYQhm4dnm+yROfE0A,
riteshh-sgV2jX0FEOL9JmXXK+q4OQ
In-Reply-To: <1479863388-23678-4-git-send-email-jeremymc-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
On Tue, Nov 22, 2016 at 05:09:46PM -0800, Jeremy McNicoll wrote:
> Add Nexus 5X (msm8992) SDHCI support, including initial regulator
> entries to support enabling the main SDHCI/MMC.
>
> The msm8994 RPM regulator talks over SMD to the APPS processor.
>
> Signed-off-by: Jeremy McNicoll <jeremymc-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> ---
> .../bindings/regulator/qcom,smd-rpm-regulator.txt | 40 ++++
> .../boot/dts/qcom/msm8992-bullhead-rev-101.dts | 262 +++++++++++++++++++++
> arch/arm64/boot/dts/qcom/msm8992-pins.dtsi | 82 +++++++
> arch/arm64/boot/dts/qcom/msm8992.dtsi | 153 ++++++++++++
> drivers/regulator/qcom_smd-regulator.c | 49 ++++
> 5 files changed, 586 insertions(+)
A few nits, otherwise,
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>
> diff --git a/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt b/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt
> index 1f8d6f8..126989b 100644
> --- a/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt
> +++ b/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt
> @@ -23,6 +23,7 @@ Regulator nodes are identified by their compatible:
> "qcom,rpm-pm8916-regulators"
> "qcom,rpm-pm8941-regulators"
> "qcom,rpm-pma8084-regulators"
> + "qcom,rpm-pm8994-regulators"
>
> - vdd_s1-supply:
> - vdd_s2-supply:
> @@ -97,6 +98,40 @@ Regulator nodes are identified by their compatible:
> Definition: reference to regulator supplying the input pin, as
> described in the data sheet
>
> +- vdd_s1-supply:
> +- vdd_s2-supply:
> +- vdd_s3-supply:
> +- vdd_s4-supply:
> +- vdd_s5-supply:
> +- vdd_s6-supply:
> +- vdd_s7-supply:
> +- vdd_l1_l11-supply:
> +- vdd_l2_l3_l4_l27-supply:
> +- vdd_l5_l7-supply:
> +- vdd_l6_l12_l14_l15_l26-supply:
> +- vdd_l8-supply:
> +- vdd_l9_l10_l13_l20_l23_l24-supply:
> +- vdd_l1_l11-supply:
> +- vdd_l6_l12_l14_l15_l26-supply:
> +- vdd_l16_l25-supply:
> +- vdd_l17-supply:
> +- vdd_l18-supply:
> +- vdd_l19-supply:
> +- vdd_l21-supply:
> +- vdd_l22-supply:
> +- vdd_l16_l25-supply:
> +- vdd_l27-supply:
> +- vdd_l28-supply:
> +- vdd_l29-supply:
> +- vdd_l30-supply:
> +- vdd_l31-supply:
> +- vdd_l32-supply:
> + Usage: optional (pm8994 only)
> + Value type: <phandle>
> + Definition: reference to regulator supplying the input pin, as
> + described in the data sheet.
> +
> +
> The regulator node houses sub-nodes for each regulator within the device. Each
> sub-node is identified using the node's name, with valid values listed for each
> of the pmics below.
> @@ -118,6 +153,11 @@ pma8084:
> l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20,
> l21, l22, l23, l24, l25, l26, l27, lvs1, lvs2, lvs3, lvs4, 5vs1
>
> +pm8994:
> + s1, s2, s3, s4, s5, s6, s7, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11,
> + l12, l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, l26,
> + l27, l28, l29, l30, l31, l32, lvs1, lvs2
> +
> The content of each sub-node is defined by the standard binding for regulators -
> see regulator.txt.
>
> diff --git a/arch/arm64/boot/dts/qcom/msm8992-bullhead-rev-101.dts b/arch/arm64/boot/dts/qcom/msm8992-bullhead-rev-101.dts
> index 4542133..2ce8798 100644
> --- a/arch/arm64/boot/dts/qcom/msm8992-bullhead-rev-101.dts
> +++ b/arch/arm64/boot/dts/qcom/msm8992-bullhead-rev-101.dts
> @@ -39,3 +39,265 @@
> };
> };
> };
> +
> +&smd_rpm {
> + rpm {
> + rpm_requests {
> + pm8994-regulators {
> +
> + vdd_l1-supply = <&pm8994_s1>;
> + vdd_l2_26_28-supply = <&pm8994_s3>;
> + vdd_l3_11-supply = <&pm8994_s3>;
> + vdd_l4_27_31-supply = <&pm8994_s3>;
> + vdd_l5_7-supply = <&pm8994_s3>;
> + vdd_l6_12_32-supply = <&pm8994_s5>;
> + vdd_l8_16_30-supply = <&vreg_vph_pwr>;
> + vdd_l9_10_18_22-supply = <&vreg_vph_pwr>;
> + vdd_l13_19_23_24-supply = <&vreg_vph_pwr>;
> + vdd_l14_15-supply = <&pm8994_s5>;
> + vdd_l17_29-supply = <&vreg_vph_pwr>;
> + vdd_l20_21-supply = <&vreg_vph_pwr>;
> + vdd_l25-supply = <&pm8994_s5>;
> + /*vin_lvs1_2 = <&pm8994_s4>; */
> +
> + s1 {
> + regulator-min-microvolt = <800000>;
> + regulator-max-microvolt = <800000>;
> + };
> +
> + s2 {
> + };
> +
> + s3 {
> + regulator-min-microvolt = <1300000>;
> + regulator-max-microvolt = <1300000>;
> + };
> +
> + s4 {
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + regulator-allow-set-load;
> + regulator-system-load = <325000>;
> + };
> +
> + s5 {
> + regulator-min-microvolt = <2150000>;
> + regulator-max-microvolt = <2150000>;
> + };
> +
> + s7 {
> + regulator-min-microvolt = <1000000>;
> + regulator-max-microvolt = <1000000>;
> + };
> +
> + l1 {
> + regulator-min-microvolt = <1000000>;
> + regulator-max-microvolt = <1000000>;
> + };
> +
> + l2 {
> + regulator-min-microvolt = <1250000>;
> + regulator-max-microvolt = <1250000>;
> + };
> +
> + l3 {
> + regulator-min-microvolt = <1200000>;
> + regulator-max-microvolt = <1200000>;
> + };
> +
> + l4 {
> + regulator-min-microvolt = <1225000>;
> + regulator-max-microvolt = <1225000>;
> + };
> +
> + l5 {
> + };
> +
> + l6 {
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + };
> +
> + l7 {
> + };
> +
> + l8 {
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + };
> +
> + l9 {
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + };
> +
> + l10 {
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + qcom,init-voltage = <1800000>;
> + };
> +
> + l11 {
> + regulator-min-microvolt = <1200000>;
> + regulator-max-microvolt = <1200000>;
> + qcom,init-voltage = <1200000>;
> + };
> +
> + l12 {
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + qcom,init-voltage = <1800000>;
> + proxy-supply = <&pm8994_l12>;
> + qcom,proxy-consumer-enable;
> + qcom,proxy-consumer-current = <10000>;
> + status = "okay";
> + };
> +
> + l13 {
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <2950000>;
> + qcom,init-voltage = <2950000>;
> + status = "okay";
> + };
> +
> + l14 {
> + regulator-min-microvolt = <1200000>;
> + regulator-max-microvolt = <1200000>;
> + qcom,init-voltage = <1200000>;
> + proxy-supply = <&pm8994_l14>;
> + qcom,proxy-consumer-enable;
> + qcom,proxy-consumer-current = <10000>;
> + status = "okay";
> + };
> +
> + l15 {
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + qcom,init-voltage = <1800000>;
> + status = "okay";
> + };
> +
> + l16 {
> + regulator-min-microvolt = <2700000>;
> + regulator-max-microvolt = <2700000>;
> + qcom,init-voltage = <2700000>;
> + status = "okay";
> + };
> +
> + l17 {
> + regulator-min-microvolt = <2700000>;
> + regulator-max-microvolt = <2700000>;
> + qcom,init-voltage = <2700000>;
> + status = "okay";
> + };
> +
> + l18 {
> + regulator-min-microvolt = <3000000>;
> + regulator-max-microvolt = <3000000>;
> + regulator-always-on;
> + qcom,init-voltage = <3000000>;
> + qcom,init-ldo-mode = <1>;
> + };
> +
> + l19 {
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + qcom,init-voltage = <1800000>;
> + status = "okay";
> + };
> +
> + l20 {
> + regulator-min-microvolt = <2950000>;
> + regulator-max-microvolt = <2950000>;
> + regulator-always-on;
> + regulator-boot-on;
> + regulator-allow-set-load;
> + regulator-system-load = <570000>;
> + };
> +
> + l21 {
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + regulator-always-on;
> + qcom,init-voltage = <1800000>;
> + };
> +
> + l22 {
> + regulator-min-microvolt = <3100000>;
> + regulator-max-microvolt = <3100000>;
> + qcom,init-voltage = <3100000>;
> + };
> +
> + l23 {
> + regulator-min-microvolt = <2800000>;
> + regulator-max-microvolt = <2800000>;
> + qcom,init-voltage = <2800000>;
> + };
> +
> + l24 {
> + regulator-min-microvolt = <3075000>;
> + regulator-max-microvolt = <3150000>;
> + qcom,init-voltage = <3075000>;
> + };
> +
> + l25 {
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + qcom,init-voltage = <1800000>;
> + };
> +
> + l26 {
> + /* TODO: value from downstream
> + regulator-min-microvolt = <987500>;
> + fails to apply */
> + };
> +
> + l27 {
> + regulator-min-microvolt = <1050000>;
> + regulator-max-microvolt = <1050000>;
> + qcom,init-voltage = <1050000>;
> + };
> +
> + l28 {
> + regulator-min-microvolt = <1000000>;
> + regulator-max-microvolt = <1000000>;
> + qcom,init-voltage = <1000000>;
> + proxy-supply = <&pm8994_l28>;
> + qcom,proxy-consumer-enable;
> + qcom,proxy-consumer-current = <10000>;
> + };
> +
> + l29 {
> + /* TODO: Unsupported voltage range..
> + regulator-min-microvolt = <2800000>;
> + regulator-max-microvolt = <2800000>;
> + qcom,init-voltage = <2800000>;
> + */
> + };
> +
> + l30 {
> + /* TODO: get this verified
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + qcom,init-voltage = <1800000>;
> + */
> + };
> +
> + l31 {
> + regulator-min-microvolt = <1262500>;
> + regulator-max-microvolt = <1262500>;
> + qcom,init-voltage = <1262500>;
> + };
> +
> + l32 {
> + /* TODO: get this verified
> + regulator-min-microvolt = <1800000>;
> + regulator-max-microvolt = <1800000>;
> + qcom,init-voltage = <1800000>;
> + */
> + };
> +
> + };
> + };
> + };
> +};
> diff --git a/arch/arm64/boot/dts/qcom/msm8992-pins.dtsi b/arch/arm64/boot/dts/qcom/msm8992-pins.dtsi
> index d2a26f0..15202c8 100644
> --- a/arch/arm64/boot/dts/qcom/msm8992-pins.dtsi
> +++ b/arch/arm64/boot/dts/qcom/msm8992-pins.dtsi
> @@ -35,4 +35,86 @@
> bias-pull-down;
> };
> };
> +
> + /* 0-3 for sdc1 4-6 for sdc2 */
> + /* Order of pins */
> + /* SDC1: CLK -> 0, CMD -> 1, DATA -> 2, RCLK -> 3 */
> + /* SDC2: CLK -> 4, CMD -> 5, DATA -> 6 */
> + pmx_sdc1_clk {
> + sdc1_clk_on: clk_on {
Use '-' rather than '_' for node names. (Labels don't matter)
> + pinmux {
> + pins = "sdc1_clk";
> + };
> + pinconf {
> + pins = "sdc1_clk";
> + bias-disable = <0>; /* No pull */
> + drive-strength = <16>; /* 16mA */
> + };
> + };
> + sdc1_clk_off: clk_off {
> + pinmux {
> + pins = "sdc1_clk";
> + };
> + pinconf {
> + pins = "sdc1_clk";
> + bias-disable = <0>; /* No pull */
> + drive-strength = <2>; /* 2mA */
> + };
> + };
> + };
> +
> + pmx_sdc1_cmd {
> + sdc1_cmd_on: cmd_on {
> + pinmux {
> + pins = "sdc1_cmd";
> + };
> + pinconf {
> + pins = "sdc1_cmd";
> + bias-pull-up;
> + drive-strength = <8>;
> + };
> + };
> + sdc1_cmd_off: cmd_off {
> + pinmux {
> + pins = "sdc1_cmd";
> + };
> + pinconf {
> + pins = "sdc1_cmd";
> + bias-pull-up = <0x3>; /* same as 3.10 ?? */
> + drive-strength = <2>; /* 2mA */
> + };
> + };
> + };
> +
> + pmx_sdc1_data {
> + sdc1_data_on: data_on {
> + pinmux {
> + pins = "sdc1_data";
> + };
> + pinconf {
> + pins = "sdc1_data";
> + bias-pull-up;
> + drive-strength = <8>; /* 8mA */
> + };
> + };
> + sdc1_data_off: data_off {
> + pinmux {
> + pins = "sdc1_data";
> + };
> + pinconf {
> + pins = "sdc1_data";
> + bias-pull-up;
> + drive-strength = <2>;
> + };
> + };
> + };
> +
> + pmx_sdc1_rclk {
> + sdc1_rclk_on: rclk_on {
> + bias-pull-down; /* pull down */
> + };
> + sdc1_rclk_off: rclk_off {
> + bias-pull-down; /* pull down */
> + };
> + };
> };
> diff --git a/arch/arm64/boot/dts/qcom/msm8992.dtsi b/arch/arm64/boot/dts/qcom/msm8992.dtsi
> index 44b2d37..d104770 100644
> --- a/arch/arm64/boot/dts/qcom/msm8992.dtsi
> +++ b/arch/arm64/boot/dts/qcom/msm8992.dtsi
> @@ -82,6 +82,12 @@
> <0xf9002000 0x1000>;
> };
>
> + apcs: syscon@0xf900d000 {
Drop the '0x'.
> + compatible = "syscon";
> + reg = <0xf900d000 0x2000>;
> + };
> +
> +
> timer@f9020000 {
> #address-cells = <1>;
> #size-cells = <1>;
> @@ -172,12 +178,159 @@
> #power-domain-cells = <1>;
> reg = <0xfc400000 0x2000>;
> };
> +
> + sdhci1: qcom,sdhci@f9824900 {
mmc@...
> + compatible = "qcom,sdhci-msm-v4";
> + reg = <0xf9824900 0x1a0>, <0xf9824000 0x800>;
> + reg-names = "hc_mem", "core_mem";
> +
> + interrupts = <GIC_SPI 123 IRQ_TYPE_NONE>,
> + <GIC_SPI 138 IRQ_TYPE_NONE>;
> + interrupt-names = "hc_irq", "pwr_irq";
> +
> + clocks = <&clock_gcc GCC_SDCC1_APPS_CLK>,
> + <&clock_gcc GCC_SDCC1_AHB_CLK>;
> + clock-names = "core", "iface";
> +
> + pinctrl-names = "default", "sleep";
> + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on
> + &sdc1_rclk_on>;
> + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off
> + &sdc1_rclk_off>;
> +
> + vdd-supply = <&pm8994_l20>;
> + qcom,vdd-voltage-level = <2950000 2950000>;
> + qcom,vdd-current-level = <200 570000>;
> +
> + vdd-io-supply = <&pm8994_s4>;
> + qcom,vdd-io-voltage-level = <1800000 1800000>;
> + qcom,vdd-io-current-level = <200 325000>;
> +
> + regulator-always-on;
> + bus-width = <8>;
> + mmc-hs400-1_8v;
> + status = "okay";
> + };
> +
> + vreg_vph_pwr: vreg-vph-pwr {
> + compatible = "regulator-fixed";
> + status = "okay";
> + regulator-name = "vph-pwr";
> +
> + regulator-min-microvolt = <3600000>;
> + regulator-max-microvolt = <3600000>;
> +
> + regulator-always-on;
> + };
> +
> + rpm_msg_ram: memory@fc428000 {
> + compatible = "qcom,rpm-msg-ram";
> + reg = <0xfc428000 0x4000>;
> + };
> +
> + sfpb_mutex_regs: syscon@fd484000 {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + compatible = "syscon";
> + reg = <0xfd484000 0x400>;
> + };
> +
> + sfpb_mutex: hwmutex {
> + compatible = "qcom,sfpb-mutex";
> + syscon = <&sfpb_mutex_regs 0x0 0x100>;
> + #hwlock-cells = <1>;
> + };
> +
> + smem {
> + compatible = "qcom,smem";
> + memory-region = <&smem_region>;
> + qcom,rpm-msg-ram = <&rpm_msg_ram>;
> + hwlocks = <&sfpb_mutex 3>;
> + };
> };
>
> memory {
> device_type = "memory";
> reg = <0 0 0 0>; // bootloader will update
> };
> +
> + reserved-memory {
> + #address-cells = <2>;
> + #size-cells = <2>;
> + ranges;
> +
> + smem_region: smem@6a00000 {
> + reg = <0x0 0x6a00000 0x0 0x200000>;
> + no-map;
> + };
> + };
> +
> + smd_rpm: smd {
> + compatible = "qcom,smd";
> +
> + rpm {
> + interrupts = <GIC_SPI 168 IRQ_TYPE_EDGE_RISING>;
> + qcom,ipc = <&apcs 8 0>;
> + qcom,smd-edge = <15>;
> + qcom,local-pid = <0>;
> + qcom,remote-pid = <6>;
> +
> + rpm_requests {
> + compatible = "qcom,rpm-msm8994";
> + qcom,smd-channels = "rpm_requests";
> +
> + rpmcc: qcom,rpmcc {
> + /* TODO: update when rpmcc-msm8994 support added */
> + compatible = "qcom,rpmcc-msm8916",
> + "qcom,rpmcc";
> + #clock-cells = <1>;
> + };
> +
> + smd_rpm_regulators: pm8994-regulators {
> + compatible = "qcom,rpm-pm8994-regulators";
> +
> + pm8994_s1: s1 {};
> + pm8994_s2: s2 {};
> + pm8994_s3: s3 {};
> + pm8994_s4: s4 {};
> + pm8994_s5: s5 {};
> + pm8994_s6: s6 {};
> + pm8994_s7: s7 {};
> +
> + pm8994_l1: l1 {};
> + pm8994_l2: l2 {};
> + pm8994_l3: l3 {};
> + pm8994_l4: l4 {};
> + pm8994_l6: l6 {};
> + pm8994_l8: l8 {};
> + pm8994_l9: l9 {};
> + pm8994_l10: l10 {};
> + pm8994_l11: l11 {};
> + pm8994_l12: l12 {};
> + pm8994_l13: l13 {};
> + pm8994_l14: l14 {};
> + pm8994_l15: l15 {};
> + pm8994_l16: l16 {};
> + pm8994_l17: l17 {};
> + pm8994_l18: l18 {};
> + pm8994_l19: l19 {};
> + pm8994_l20: l20 {};
> + pm8994_l21: l21 {};
> + pm8994_l22: l22 {};
> + pm8994_l23: l23 {};
> + pm8994_l24: l24 {};
> + pm8994_l25: l25 {};
> + pm8994_l26: l26 {};
> + pm8994_l27: l27 {};
> + pm8994_l28: l28 {};
> + pm8994_l29: l29 {};
> + pm8994_l30: l30 {};
> + pm8994_l31: l31 {};
> + pm8994_l32: l32 {};
> + };
> + };
> + };
> + };
> };
>
>
> diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c
> index 8ed46a9..a7e8ce7 100644
> --- a/drivers/regulator/qcom_smd-regulator.c
> +++ b/drivers/regulator/qcom_smd-regulator.c
> @@ -443,11 +443,60 @@ static const struct rpm_regulator_data rpm_pma8084_regulators[] = {
> {}
> };
>
> +static const struct rpm_regulator_data rpm_pm8994_regulators[] = {
> + { "s1", QCOM_SMD_RPM_SMPA, 1, &pma8084_ftsmps, "vdd_s1" },
> + { "s2", QCOM_SMD_RPM_SMPA, 2, &pma8084_ftsmps, "vdd_s2" },
> + { "s3", QCOM_SMD_RPM_SMPA, 3, &pma8084_hfsmps, "vdd_s3" },
> + { "s4", QCOM_SMD_RPM_SMPA, 4, &pma8084_hfsmps, "vdd_s4" },
> + { "s5", QCOM_SMD_RPM_SMPA, 5, &pma8084_hfsmps, "vdd_s5" },
> + { "s6", QCOM_SMD_RPM_SMPA, 6, &pma8084_ftsmps, "vdd_s6" },
> + { "s7", QCOM_SMD_RPM_SMPA, 7, &pma8084_ftsmps, "vdd_s7" },
> +
> + { "l1", QCOM_SMD_RPM_LDOA, 1, &pma8084_nldo, "vdd_l1_l11" },
> + { "l2", QCOM_SMD_RPM_LDOA, 2, &pma8084_nldo, "vdd_l2_l3_l4_l27" },
> + { "l3", QCOM_SMD_RPM_LDOA, 3, &pma8084_nldo, "vdd_l2_l3_l4_l27" },
> + { "l4", QCOM_SMD_RPM_LDOA, 4, &pma8084_nldo, "vdd_l2_l3_l4_l27" },
> + { "l5", QCOM_SMD_RPM_LDOA, 5, &pma8084_pldo, "vdd_l5_l7" },
> + { "l6", QCOM_SMD_RPM_LDOA, 6, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
> + { "l7", QCOM_SMD_RPM_LDOA, 7, &pma8084_pldo, "vdd_l5_l7" },
> + { "l8", QCOM_SMD_RPM_LDOA, 8, &pma8084_pldo, "vdd_l8" },
> + { "l9", QCOM_SMD_RPM_LDOA, 9, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
> + { "l10", QCOM_SMD_RPM_LDOA, 10, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
> + { "l11", QCOM_SMD_RPM_LDOA, 11, &pma8084_nldo, "vdd_l1_l11" },
> + { "l12", QCOM_SMD_RPM_LDOA, 12, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
> + { "l13", QCOM_SMD_RPM_LDOA, 13, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
> + { "l14", QCOM_SMD_RPM_LDOA, 14, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
> + { "l15", QCOM_SMD_RPM_LDOA, 15, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
> + { "l16", QCOM_SMD_RPM_LDOA, 16, &pma8084_pldo, "vdd_l16_l25" },
> + { "l17", QCOM_SMD_RPM_LDOA, 17, &pma8084_pldo, "vdd_l17" },
> + { "l18", QCOM_SMD_RPM_LDOA, 18, &pma8084_pldo, "vdd_l18" },
> + { "l19", QCOM_SMD_RPM_LDOA, 19, &pma8084_pldo, "vdd_l19" },
> + { "l20", QCOM_SMD_RPM_LDOA, 20, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
> + { "l21", QCOM_SMD_RPM_LDOA, 21, &pma8084_pldo, "vdd_l21" },
> + { "l22", QCOM_SMD_RPM_LDOA, 22, &pma8084_pldo, "vdd_l22" },
> + { "l23", QCOM_SMD_RPM_LDOA, 23, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
> + { "l24", QCOM_SMD_RPM_LDOA, 24, &pma8084_pldo, "vdd_l9_l10_l13_l20_l23_l24" },
> + { "l25", QCOM_SMD_RPM_LDOA, 25, &pma8084_pldo, "vdd_l16_l25" },
> + { "l26", QCOM_SMD_RPM_LDOA, 26, &pma8084_pldo, "vdd_l6_l12_l14_l15_l26" },
> + { "l27", QCOM_SMD_RPM_LDOA, 27, &pma8084_nldo, "vdd_l27" },
> + { "l28", QCOM_SMD_RPM_LDOA, 28, &pma8084_nldo, "vdd_l28" },
> + { "l29", QCOM_SMD_RPM_LDOA, 29, &pma8084_nldo, "vdd_l29" },
> + { "l30", QCOM_SMD_RPM_LDOA, 30, &pma8084_nldo, "vdd_l30" },
> + { "l31", QCOM_SMD_RPM_LDOA, 31, &pma8084_nldo, "vdd_l31" },
> + { "l32", QCOM_SMD_RPM_LDOA, 32, &pma8084_nldo, "vdd_l32" },
> +
> + { "lvs1", QCOM_SMD_RPM_VSA, 1, &pma8084_switch },
> + { "lvs2", QCOM_SMD_RPM_VSA, 2, &pma8084_switch },
> +
> + {}
> +};
> +
> static const struct of_device_id rpm_of_match[] = {
> { .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators },
> { .compatible = "qcom,rpm-pm8916-regulators", .data = &rpm_pm8916_regulators },
> { .compatible = "qcom,rpm-pm8941-regulators", .data = &rpm_pm8941_regulators },
> { .compatible = "qcom,rpm-pma8084-regulators", .data = &rpm_pma8084_regulators },
> + { .compatible = "qcom,rpm-pm8994-regulators", .data = &rpm_pm8994_regulators },
> {}
> };
> MODULE_DEVICE_TABLE(of, rpm_of_match);
> --
> 2.6.1
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox