* [PATCH v5 1/2] Add OV5647 device tree documentation
From: Ramiro Oliveira @ 2016-12-05 17:36 UTC (permalink / raw)
To: mchehab-DgEjT+Ai2ygdnm+yROfE0A,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-media-u79uwXL29TY76Z2rM5mHXA,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: davem-fT/PcQaiUtIeIZ0/mPfg9Q,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ,
akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
linux-0h96xk9xTtrk1uMJSBkQmQ, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
dheitmueller-eb9eJ82Ua7k9XoPSrs7Ehg,
slongerbeam-Re5JQEeQqe8AvxtiuMwx3w, lars-Qo5EllUWu/uELgA04lAiVw,
robert.jarzmik-GANU6spQydw, pavel-+ZI9xUNit7I,
pali.rohar-Re5JQEeQqe8AvxtiuMwx3w,
sakari.ailus-VuQAYsv1563Yd54FQh9/CA, mark.rutland-5wv7dgnIgG8,
Ramiro.Oliveira-HKixBCOQz3hWk0Htik3J/w,
CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w
In-Reply-To: <cover.1480958609.git.roliveir-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
Add device tree documentation.
Signed-off-by: Ramiro Oliveira <roliveir-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
---
.../devicetree/bindings/media/i2c/ov5647.txt | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/i2c/ov5647.txt
diff --git a/Documentation/devicetree/bindings/media/i2c/ov5647.txt b/Documentation/devicetree/bindings/media/i2c/ov5647.txt
new file mode 100644
index 0000000..4c91b3b
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/ov5647.txt
@@ -0,0 +1,19 @@
+Omnivision OV5647 raw image sensor
+---------------------------------
+
+OV5647 is a raw image sensor with MIPI CSI-2 and CCP2 image data interfaces
+and CCI (I2C compatible) control bus.
+
+Required properties:
+
+- compatible : "ovti,ov5647";
+- reg : I2C slave address of the sensor;
+
+The common video interfaces bindings (see video-interfaces.txt) should be
+used to specify link to the image data receiver. The OV5647 device
+node should contain one 'port' child node with an 'endpoint' subnode.
+
+Following properties are valid for the endpoint node:
+
+- data-lanes : (optional) specifies MIPI CSI-2 data lanes as covered in
+ video-interfaces.txt. The sensor supports only two data lanes.
--
2.10.2
--
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 v5 2/2] Add support for OV5647 sensor
From: Ramiro Oliveira @ 2016-12-05 17:36 UTC (permalink / raw)
To: mchehab-DgEjT+Ai2ygdnm+yROfE0A,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-media-u79uwXL29TY76Z2rM5mHXA,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: davem-fT/PcQaiUtIeIZ0/mPfg9Q,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ,
akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
linux-0h96xk9xTtrk1uMJSBkQmQ, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
dheitmueller-eb9eJ82Ua7k9XoPSrs7Ehg,
slongerbeam-Re5JQEeQqe8AvxtiuMwx3w, lars-Qo5EllUWu/uELgA04lAiVw,
robert.jarzmik-GANU6spQydw, pavel-+ZI9xUNit7I,
pali.rohar-Re5JQEeQqe8AvxtiuMwx3w,
sakari.ailus-VuQAYsv1563Yd54FQh9/CA, mark.rutland-5wv7dgnIgG8,
Ramiro.Oliveira-HKixBCOQz3hWk0Htik3J/w,
CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w
In-Reply-To: <cover.1480958609.git.roliveir-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
Add support for OV5647 sensor.
Modes supported:
- 640x480 RAW 8
Signed-off-by: Ramiro Oliveira <roliveir-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
---
MAINTAINERS | 7 +
drivers/media/i2c/Kconfig | 12 +
drivers/media/i2c/Makefile | 1 +
drivers/media/i2c/ov5647.c | 866 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 886 insertions(+)
create mode 100644 drivers/media/i2c/ov5647.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 52cc077..72e828a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8923,6 +8923,13 @@ M: Harald Welte <laforge-TgoAw6mPHtdg9hUCZPvPmw@public.gmane.org>
S: Maintained
F: drivers/char/pcmcia/cm4040_cs.*
+OMNIVISION OV5647 SENSOR DRIVER
+M: Ramiro Oliveira <roliveir-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
+L: linux-media-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
+T: git git://linuxtv.org/media_tree.git
+S: Maintained
+F: drivers/media/i2c/ov5647.c
+
OMNIVISION OV7670 SENSOR DRIVER
M: Jonathan Corbet <corbet-T1hC0tSOHrs@public.gmane.org>
L: linux-media-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index b31fa6f..c1b78e5 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -531,6 +531,18 @@ config VIDEO_OV2659
To compile this driver as a module, choose M here: the
module will be called ov2659.
+config VIDEO_OV5647
+ tristate "OmniVision OV5647 sensor support"
+ depends on OF
+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ depends on MEDIA_CAMERA_SUPPORT
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the OmniVision
+ OV5647 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ov5647.
+
config VIDEO_OV7640
tristate "OmniVision OV7640 sensor support"
depends on I2C && VIDEO_V4L2
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 92773b2..0d9014c 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -82,3 +82,4 @@ obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o
obj-$(CONFIG_VIDEO_OV2659) += ov2659.o
obj-$(CONFIG_VIDEO_TC358743) += tc358743.o
+obj-$(CONFIG_VIDEO_OV5647) += ov5647.o
diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
new file mode 100644
index 0000000..2aae806
--- /dev/null
+++ b/drivers/media/i2c/ov5647.c
@@ -0,0 +1,866 @@
+/*
+ * A V4L2 driver for OmniVision OV5647 cameras.
+ *
+ * Based on Samsung S5K6AAFX SXGA 1/6" 1.3M CMOS Image Sensor driver
+ * Copyright (C) 2011 Sylwester Nawrocki <s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ *
+ * Based on Omnivision OV7670 Camera Driver
+ * Copyright (C) 2006-7 Jonathan Corbet <corbet-T1hC0tSOHrs@public.gmane.org>
+ *
+ * Copyright (C) 2016, Synopsys, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-image-sizes.h>
+#include <media/v4l2-of.h>
+#include <linux/io.h>
+
+#define SENSOR_NAME "ov5647"
+
+#define OV5647_SW_RESET 0x1003
+#define OV5647_REG_CHIPID_H 0x300A
+#define OV5647_REG_CHIPID_L 0x300B
+
+#define REG_TERM 0xfffe
+#define VAL_TERM 0xfe
+#define REG_DLY 0xffff
+
+#define OV5647_ROW_START 0x01
+#define OV5647_ROW_START_MIN 0
+#define OV5647_ROW_START_MAX 2004
+#define OV5647_ROW_START_DEF 54
+
+#define OV5647_COLUMN_START 0x02
+#define OV5647_COLUMN_START_MIN 0
+#define OV5647_COLUMN_START_MAX 2750
+#define OV5647_COLUMN_START_DEF 16
+
+#define OV5647_WINDOW_HEIGHT 0x03
+#define OV5647_WINDOW_HEIGHT_MIN 2
+#define OV5647_WINDOW_HEIGHT_MAX 2006
+#define OV5647_WINDOW_HEIGHT_DEF 1944
+
+#define OV5647_WINDOW_WIDTH 0x04
+#define OV5647_WINDOW_WIDTH_MIN 2
+#define OV5647_WINDOW_WIDTH_MAX 2752
+#define OV5647_WINDOW_WIDTH_DEF 2592
+
+struct regval_list {
+ u16 addr;
+ u8 data;
+};
+
+struct cfg_array {
+ struct regval_list *regs;
+ int size;
+};
+
+struct sensor_win_size {
+ int width;
+ int height;
+ unsigned int hoffset;
+ unsigned int voffset;
+ unsigned int hts;
+ unsigned int vts;
+ unsigned int pclk;
+ unsigned int mipi_bps;
+ unsigned int fps_fixed;
+ unsigned int bin_factor;
+ unsigned int intg_min;
+ unsigned int intg_max;
+ void *regs;
+ int regs_size;
+ int (*set_size)(struct v4l2_subdev *sd);
+};
+
+
+struct ov5647 {
+ struct device *dev;
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+ struct mutex lock;
+ struct v4l2_mbus_framefmt format;
+ struct sensor_format_struct *fmt;
+ unsigned int width;
+ unsigned int height;
+ unsigned int capture_mode;
+ int hue;
+ struct v4l2_fract tpf;
+ struct sensor_win_size *current_wins;
+};
+
+static inline struct ov5647 *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct ov5647, sd);
+}
+
+static struct regval_list sensor_oe_disable_regs[] = {
+ {0x3000, 0x00},
+ {0x3001, 0x00},
+ {0x3002, 0x00},
+};
+
+static struct regval_list sensor_oe_enable_regs[] = {
+ {0x3000, 0x0f},
+ {0x3001, 0xff},
+ {0x3002, 0xe4},
+};
+
+static struct regval_list ov5647_640x480[] = {
+ {0x0100, 0x00},
+ {0x0103, 0x01},
+ {0x3034, 0x08},
+ {0x3035, 0x21},
+ {0x3036, 0x46},
+ {0x303c, 0x11},
+ {0x3106, 0xf5},
+ {0x3821, 0x07},
+ {0x3820, 0x41},
+ {0x3827, 0xec},
+ {0x370c, 0x0f},
+ {0x3612, 0x59},
+ {0x3618, 0x00},
+ {0x5000, 0x06},
+ {0x5001, 0x01},
+ {0x5002, 0x41},
+ {0x5003, 0x08},
+ {0x5a00, 0x08},
+ {0x3000, 0x00},
+ {0x3001, 0x00},
+ {0x3002, 0x00},
+ {0x3016, 0x08},
+ {0x3017, 0xe0},
+ {0x3018, 0x44},
+ {0x301c, 0xf8},
+ {0x301d, 0xf0},
+ {0x3a18, 0x00},
+ {0x3a19, 0xf8},
+ {0x3c01, 0x80},
+ {0x3b07, 0x0c},
+ {0x380c, 0x07},
+ {0x380d, 0x68},
+ {0x380e, 0x03},
+ {0x380f, 0xd8},
+ {0x3814, 0x31},
+ {0x3815, 0x31},
+ {0x3708, 0x64},
+ {0x3709, 0x52},
+ {0x3808, 0x02},
+ {0x3809, 0x80},
+ {0x380a, 0x01},
+ {0x380b, 0xE0},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x0a},
+ {0x3805, 0x3f},
+ {0x3806, 0x07},
+ {0x3807, 0xa1},
+ {0x3811, 0x08},
+ {0x3813, 0x02},
+ {0x3630, 0x2e},
+ {0x3632, 0xe2},
+ {0x3633, 0x23},
+ {0x3634, 0x44},
+ {0x3636, 0x06},
+ {0x3620, 0x64},
+ {0x3621, 0xe0},
+ {0x3600, 0x37},
+ {0x3704, 0xa0},
+ {0x3703, 0x5a},
+ {0x3715, 0x78},
+ {0x3717, 0x01},
+ {0x3731, 0x02},
+ {0x370b, 0x60},
+ {0x3705, 0x1a},
+ {0x3f05, 0x02},
+ {0x3f06, 0x10},
+ {0x3f01, 0x0a},
+ {0x3a08, 0x01},
+ {0x3a09, 0x27},
+ {0x3a0a, 0x00},
+ {0x3a0b, 0xf6},
+ {0x3a0d, 0x04},
+ {0x3a0e, 0x03},
+ {0x3a0f, 0x58},
+ {0x3a10, 0x50},
+ {0x3a1b, 0x58},
+ {0x3a1e, 0x50},
+ {0x3a11, 0x60},
+ {0x3a1f, 0x28},
+ {0x4001, 0x02},
+ {0x4004, 0x02},
+ {0x4000, 0x09},
+ {0x4837, 0x24},
+ {0x4050, 0x6e},
+ {0x4051, 0x8f},
+ {0x0100, 0x01},
+};
+
+struct sensor_format_struct;
+
+/**
+ * @short I2C Write operation
+ * @param[in] i2c_client I2C client
+ * @param[in] reg register address
+ * @param[in] val value to write
+ * @return Error code
+ */
+static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val)
+{
+ int ret;
+ unsigned char data[3] = { reg >> 8, reg & 0xff, val};
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ ret = i2c_master_send(client, data, 3);
+ if (ret != 3) {
+ dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
+ __func__, reg);
+ return ret < 0 ? ret : -EIO;
+ }
+ return 0;
+}
+
+/**
+ * @short I2C Read operation
+ * @param[in] i2c_client I2C client
+ * @param[in] reg register address
+ * @param[out] val value read
+ * @return Error code
+ */
+static int ov5647_read(struct v4l2_subdev *sd, u16 reg, u8 *val)
+{
+ int ret;
+ unsigned char data_w[2] = { reg >> 8, reg & 0xff };
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+
+ ret = i2c_master_send(client, data_w, 2);
+
+ if (ret < 2) {
+ dev_dbg(&client->dev, "%s: i2c read error, reg: %x\n",
+ __func__, reg);
+ return ret < 0 ? ret : -EIO;
+ }
+
+
+ ret = i2c_master_recv(client, val, 1);
+
+ if (ret < 1) {
+ dev_dbg(&client->dev, "%s: i2c read error, reg: %x\n",
+ __func__, reg);
+ return ret < 0 ? ret : -EIO;
+ }
+ return 0;
+}
+
+static int ov5647_write_array(struct v4l2_subdev *sd,
+ struct regval_list *regs, int array_size)
+{
+ int i = 0;
+ int ret = 0;
+
+ if (!regs)
+ return -EINVAL;
+
+ while (i < array_size) {
+ ret = ov5647_write(sd, regs->addr, regs->data);
+ if (ret < 0)
+ return ret;
+ i++;
+ regs++;
+ }
+ return 0;
+}
+
+static void ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
+{
+ u8 channel_id;
+
+ ov5647_read(sd, 0x4814, &channel_id);
+ channel_id &= ~(3 << 6);
+ ov5647_write(sd, 0x4814, channel_id | (channel << 6));
+}
+
+void ov5647_stream_on(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ ov5647_write(sd, 0x4202, 0x00);
+ dev_dbg(&client->dev, "Stream on");
+ ov5647_write(sd, 0x300D, 0x00);
+}
+
+void ov5647_stream_off(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ ov5647_write(sd, 0x4202, 0x0f);
+ dev_dbg(&client->dev, "Stream off");
+ ov5647_write(sd, 0x300D, 0x01);
+}
+
+/****************************************************************************/
+
+/**
+ * @short Set SW standby
+ * @param[in] sd v4l2 sd
+ * @param[in] stanby standby mode status (on or off)
+ * @return Error code
+ */
+static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
+{
+ int ret;
+ unsigned char rdval;
+
+ ret = ov5647_read(sd, 0x0100, &rdval);
+ if (ret != 0)
+ return ret;
+
+ if (standby)
+ rdval &= 0xfe;
+ else
+ rdval |= 0x01;
+
+ ret = ov5647_write(sd, 0x0100, rdval);
+
+ return ret;
+}
+
+/**
+ * @short Store information about the video data format.
+ */
+static struct sensor_format_struct {
+ u8 *desc;
+ u32 mbus_code;
+ struct regval_list *regs;
+ int regs_size;
+ int bpp;
+} sensor_formats[] = {
+ {
+ .desc = "Raw RGB Bayer",
+ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .regs = ov5647_640x480,
+ .regs_size = ARRAY_SIZE(ov5647_640x480),
+ .bpp = 1
+ },
+};
+#define N_FMTS ARRAY_SIZE(sensor_formats)
+
+/* ----------------------------------------------------------------------- */
+
+/**
+ * @short Initialize sensor
+ * @param[in] sd v4l2 subdev
+ * @param[in] val not used
+ * @return Error code
+ */
+static int __sensor_init(struct v4l2_subdev *sd)
+{
+ int ret;
+ u8 resetval;
+ u8 rdval;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ dev_dbg(&client->dev, "sensor init\n");
+
+ ret = ov5647_read(sd, 0x0100, &rdval);
+ if (ret != 0)
+ return ret;
+
+ ov5647_write(sd, 0x4800, 0x25);
+ ov5647_stream_off(sd);
+
+ ret = ov5647_write_array(sd, ov5647_640x480,
+ ARRAY_SIZE(ov5647_640x480));
+ if (ret < 0) {
+ dev_err(&client->dev, "write sensor_default_regs error\n");
+ return ret;
+ }
+
+ ov5647_set_virtual_channel(sd, 0);
+
+ ov5647_read(sd, 0x0100, &resetval);
+ if (!(resetval & 0x01)) {
+ dev_err(&client->dev, "Device was in SW standby");
+ ov5647_write(sd, 0x0100, 0x01);
+ }
+
+ ov5647_write(sd, 0x4800, 0x04);
+ ov5647_stream_on(sd);
+
+ return 0;
+}
+
+/**
+ * @short Control sensor power state
+ * @param[in] sd v4l2 subdev
+ * @param[in] on Sensor power
+ * @return Error code
+ */
+static int sensor_power(struct v4l2_subdev *sd, int on)
+{
+ int ret;
+ struct ov5647 *ov5647 = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ ret = 0;
+ mutex_lock(&ov5647->lock);
+
+ if (on) {
+ dev_dbg(&client->dev, "OV5647 power on\n");
+
+ ret = ov5647_write_array(sd, sensor_oe_enable_regs,
+ ARRAY_SIZE(sensor_oe_enable_regs));
+
+ ret = __sensor_init(sd);
+
+ if (ret < 0)
+ dev_err(&client->dev,
+ "Camera not available, check Power\n");
+ } else {
+ dev_dbg(&client->dev, "OV5647 power off\n");
+
+ dev_dbg(&client->dev, "disable oe\n");
+ ret = ov5647_write_array(sd, sensor_oe_disable_regs,
+ ARRAY_SIZE(sensor_oe_disable_regs));
+
+ if (ret < 0)
+ dev_dbg(&client->dev, "disable oe failed\n");
+
+ ret = set_sw_standby(sd, true);
+
+ if (ret < 0)
+ dev_dbg(&client->dev, "soft stby failed\n");
+
+ }
+
+ mutex_unlock(&ov5647->lock);
+
+ return ret;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/**
+ * @short Get register value
+ * @param[in] sd v4l2 subdev
+ * @param[in] reg register struct
+ * @return Error code
+ */
+static int sensor_get_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ unsigned char val = 0;
+ int ret;
+
+ ret = ov5647_read(sd, reg->reg & 0xff, &val);
+ if (ret != 0)
+ return ret;
+
+ reg->val = val;
+ reg->size = 1;
+
+ return ret;
+}
+
+/**
+ * @short Set register value
+ * @param[in] sd v4l2 subdev
+ * @param[in] reg register struct
+ * @return Error code
+ */
+static int sensor_set_register(struct v4l2_subdev *sd,
+ const struct v4l2_dbg_register *reg)
+{
+ return ov5647_write(sd, reg->reg & 0xff, reg->val & 0xff);
+}
+#endif
+
+/* ----------------------------------------------------------------------- */
+
+/**
+ * @short Subdev core operations registration
+ */
+static const struct v4l2_subdev_core_ops sensor_core_ops = {
+ .s_power = sensor_power,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = sensor_get_register,
+ .s_register = sensor_set_register,
+#endif
+};
+
+/* ----------------------------------------------------------------------- */
+
+
+
+/**
+ * @short Enumerate available image formats
+ * @param[in] sd v4l2 subdev
+ * @param[in] index index
+ * @param[in] code MBUS Pixel code
+ * @return Error code
+ */
+static int sensor_enum_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->pad || code->index >= N_FMTS)
+ return -EINVAL;
+
+ code->code = sensor_formats[code->index].mbus_code;
+ return 0;
+}
+
+/**
+ * @short Try frame format internal function
+ * @param[in] sd v4l2 subdev
+ * @param[in] fmt frame format
+ * @return Error code
+ */
+static int sensor_try_fmt_internal(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt, struct sensor_format_struct **ret_fmt,
+ struct sensor_win_size **ret_wsize)
+{
+ int index;
+
+ for (index = 0; index < N_FMTS; index++)
+ if (sensor_formats[index].mbus_code == fmt->code)
+ break;
+
+ if (index >= N_FMTS)
+ return -EINVAL;
+
+ if (ret_fmt != NULL)
+ *ret_fmt = sensor_formats + index;
+
+ fmt->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+/**
+ * @short Set frame format
+ * @param[in] sd v4l2 subdev
+ * @param[in] fmt frame format
+ * @return Error code
+ */
+static int sensor_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ int ret;
+ struct sensor_format_struct *sensor_fmt;
+ struct sensor_win_size *wsize;
+ struct ov5647 *info = to_state(sd);
+
+ ov5647_write_array(sd, sensor_oe_disable_regs,
+ ARRAY_SIZE(sensor_oe_disable_regs));
+
+ ret = sensor_try_fmt_internal(sd, &fmt->format,
+ &sensor_fmt, &wsize);
+ if (ret)
+ return ret;
+
+ ov5647_write_array(sd, sensor_fmt->regs, sensor_fmt->regs_size);
+
+ ret = 0;
+
+ if (wsize->regs)
+ ov5647_write_array(sd, wsize->regs, wsize->regs_size);
+
+ if (wsize->set_size)
+ wsize->set_size(sd);
+
+ info->fmt = sensor_fmt;
+ info->width = wsize->width;
+ info->height = wsize->height;
+
+ ov5647_write_array(sd, sensor_oe_enable_regs,
+ ARRAY_SIZE(sensor_oe_enable_regs));
+
+ return 0;
+}
+
+/**
+ * @short Set stream parameters
+ * @param[in] sd v4l2 subdev
+ * @param[in] parms stream parameters
+ * @return Error code
+ */
+static int sensor_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+ struct v4l2_captureparm *cp = &parms->parm.capture;
+ struct ov5647 *info = to_state(sd);
+
+ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (info->tpf.numerator == 0)
+ return -EINVAL;
+
+ info->capture_mode = cp->capturemode;
+
+ return 0;
+}
+
+/**
+ * @short Get stream parameters
+ * @param[in] sd v4l2 subdev
+ * @param[in] parms stream parameters
+ * @return Error code
+ */
+static int sensor_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+ struct v4l2_captureparm *cp = &parms->parm.capture;
+ struct ov5647 *info = to_state(sd);
+
+ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ memset(cp, 0, sizeof(struct v4l2_captureparm));
+ cp->capability = V4L2_CAP_TIMEPERFRAME;
+ cp->capturemode = info->capture_mode;
+
+ return 0;
+}
+
+/**
+ * @short Subdev video operations registration
+ *
+ */
+static const struct v4l2_subdev_video_ops sensor_video_ops = {
+ .s_parm = sensor_s_parm,
+ .g_parm = sensor_g_parm,
+};
+
+/* ----------------------------------------------------------------------- */
+
+/**
+ * @short Subdev operations registration
+ *
+ */
+static const struct v4l2_subdev_ops subdev_ops = {
+ .core = &sensor_core_ops,
+ .video = &sensor_video_ops,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev internal operations
+ */
+
+/**
+ * @short Detect camera version and model
+ * @param[in] sd v4l2 subdev
+ * @return Error code
+ */
+int ov5647_detect(struct v4l2_subdev *sd)
+{
+ unsigned char v;
+ int ret;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ ret = ov5647_write(sd, OV5647_SW_RESET, 0x01);
+ if (ret < 0)
+ return ret;
+ ret = ov5647_read(sd, OV5647_REG_CHIPID_H, &v);
+ if (ret < 0)
+ return ret;
+ if (v != 0x56) {
+ dev_err(&client->dev, "Wrong model version detected");
+ return -ENODEV;
+ }
+ ret = ov5647_read(sd, OV5647_REG_CHIPID_L, &v);
+ if (ret < 0)
+ return ret;
+ if (v != 0x47) {
+ dev_err(&client->dev, "Wrong model version detected");
+ return -ENODEV;
+ }
+
+ ret = ov5647_write(sd, OV5647_SW_RESET, 0x00);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/**
+ * @short Detect if camera is registered
+ * @param[in] sd v4l2 subdev
+ * @return Error code
+ */
+static int ov5647_registered(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ dev_info(&client->dev, "OV5647 detected at address 0x%02x\n",
+ client->addr);
+
+ return 0;
+}
+
+/**
+ * @short Open device
+ * @param[in] sd v4l2 subdev
+ * @param[in] fh v4l2 file handler
+ * @return Error code
+ */
+static int ov5647_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_mbus_framefmt *format =
+ v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ struct v4l2_rect *crop =
+ v4l2_subdev_get_try_crop(sd, fh->pad, 0);
+
+ crop->left = OV5647_COLUMN_START_DEF;
+ crop->top = OV5647_ROW_START_DEF;
+ crop->width = OV5647_WINDOW_WIDTH_DEF;
+ crop->height = OV5647_WINDOW_HEIGHT_DEF;
+
+ format->code = MEDIA_BUS_FMT_SBGGR8_1X8;
+
+ format->width = OV5647_WINDOW_WIDTH_DEF;
+ format->height = OV5647_WINDOW_HEIGHT_DEF;
+ format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_SRGB;
+
+ return sensor_power(sd, true);
+}
+
+/**
+ * @short Open device
+ * @param[in] sd v4l2 subdev
+ * @param[in] fh v4l2 file handler
+ * @return Error code
+ */
+static int ov5647_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ return sensor_power(sd, false);
+}
+
+/**
+ * @short Subdev internal operations registration
+ *
+ */
+static const struct v4l2_subdev_internal_ops ov5647_subdev_internal_ops = {
+ .registered = ov5647_registered,
+ .open = ov5647_open,
+ .close = ov5647_close,
+};
+
+/**
+ * @short Initialization routine - Entry point of the driver
+ * @param[in] client pointer to the i2c client structure
+ * @param[in] id pointer to the i2c device id structure
+ * @return 0 on success and a negative number on failure
+ */
+static int ov5647_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct ov5647 *sensor;
+ int ret = 0;
+ struct v4l2_subdev *sd;
+
+ dev_info(&client->dev, "Installing OmniVision OV5647 camera driver\n");
+
+ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
+ if (sensor == NULL)
+ return -ENOMEM;
+
+ mutex_init(&sensor->lock);
+ sensor->dev = dev;
+
+ sd = &sensor->sd;
+ v4l2_i2c_subdev_init(sd, client, &subdev_ops);
+ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sd->entity, 1, &sensor->pad);
+ if (ret < 0)
+ goto mutex_remove;
+
+ ret = ov5647_detect(sd);
+ if (ret < 0)
+ goto error;
+
+ ret = v4l2_async_register_subdev(sd);
+ if (ret < 0)
+ goto error;
+
+ return 0;
+error:
+ media_entity_cleanup(&sd->entity);
+mutex_remove:
+ mutex_destroy(&sensor->lock);
+ return ret;
+}
+
+/**
+ * @short Exit routine - Exit point of the driver
+ * @param[in] client pointer to the i2c client structure
+ * @return 0 on success and a negative number on failure
+ */
+static int ov5647_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov5647 *ov5647 = to_state(sd);
+
+ v4l2_async_unregister_subdev(&ov5647->sd);
+ media_entity_cleanup(&ov5647->sd.entity);
+ v4l2_device_unregister_subdev(sd);
+ mutex_destroy(&ov5647->lock);
+
+ return 0;
+}
+
+static const struct i2c_device_id ov5647_id[] = {
+ { "ov5647", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ov5647_id);
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id ov5647_of_match[] = {
+ { .compatible = "ovti,ov5647" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ov5647_of_match);
+#endif
+
+/**
+ * @short i2c driver structure
+ */
+static struct i2c_driver ov5647_driver = {
+ .driver = {
+ .of_match_table = of_match_ptr(ov5647_of_match),
+ .owner = THIS_MODULE,
+ .name = "ov5647",
+ },
+ .probe = ov5647_probe,
+ .remove = ov5647_remove,
+ .id_table = ov5647_id,
+};
+
+module_i2c_driver(ov5647_driver);
+
+MODULE_AUTHOR("Ramiro Oliveira <roliveir-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>");
+MODULE_DESCRIPTION("A low-level driver for OmniVision ov5647 sensors");
+MODULE_LICENSE("GPL v2");
--
2.10.2
--
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
* Re: [PATCH 1/6] net: ethernet: ti: netcp: add support of cpts
From: Grygorii Strashko @ 2016-12-05 18:25 UTC (permalink / raw)
To: Rob Herring
Cc: David S. Miller, netdev, Mugunthan V N, Richard Cochran,
Sekhar Nori, linux-kernel, linux-omap, devicetree,
Murali Karicheri, Wingman Kwok
In-Reply-To: <20161205144918.oj4jpj65aha3x5gf@rob-hp-laptop>
On 12/05/2016 08:49 AM, Rob Herring wrote:
> On Mon, Nov 28, 2016 at 05:04:23PM -0600, Grygorii Strashko wrote:
>> From: WingMan Kwok <w-kwok2@ti.com>
>>
>> This patch adds support of the cpts device found in the
>> gbe and 10gbe ethernet switches on the keystone 2 SoCs
>> (66AK2E/L/Hx, 66AK2Gx).
>>
>> Signed-off-by: WingMan Kwok <w-kwok2@ti.com>
>> Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
>> ---
>> .../devicetree/bindings/net/keystone-netcp.txt | 9 +
>> drivers/net/ethernet/ti/Kconfig | 7 +-
>> drivers/net/ethernet/ti/netcp.h | 2 +-
>> drivers/net/ethernet/ti/netcp_core.c | 18 +-
>> drivers/net/ethernet/ti/netcp_ethss.c | 437 ++++++++++++++++++++-
>> 5 files changed, 459 insertions(+), 14 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/net/keystone-netcp.txt b/Documentation/devicetree/bindings/net/keystone-netcp.txt
>> index 04ba1dc..c37b54e 100644
>> --- a/Documentation/devicetree/bindings/net/keystone-netcp.txt
>> +++ b/Documentation/devicetree/bindings/net/keystone-netcp.txt
>> @@ -113,6 +113,15 @@ Optional properties:
>> will only initialize these ports and attach PHY
>> driver to them if needed.
>>
>> + Properties related to cpts configurations.
>> + - cpts_clock_mult/cpts_clock_shift:
>
> Needs vendor prefix. Don't use '_'.
This module is used as part of OMAP and Keystone SoCs, so names for
this props is ABI already :(
>
>> + used for converting time counter cycles to ns as in
>> +
>> + ns = (cycles * clock_mult) >> _shift
>> +
>> + Defaults: clock_mult, clock_shift = calculated from
>> + CPTS refclk
>
> What does this mean?
>
I'll add more description here.
>> +
>> NetCP interface properties: Interface specification for NetCP sub-modules.
>> Required properties:
>> - rx-channel: the navigator packet dma channel name for rx.
--
regards,
-grygorii
^ permalink raw reply
* Re: [PATCH v3 00/13] net: ethernet: ti: cpts: update and fixes
From: Grygorii Strashko @ 2016-12-05 18:31 UTC (permalink / raw)
To: Richard Cochran
Cc: David S. Miller, netdev-u79uwXL29TY76Z2rM5mHXA, Mugunthan V N,
Sekhar Nori, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
devicetree-u79uwXL29TY76Z2rM5mHXA, Murali Karicheri, Wingman Kwok,
Thomas Gleixner
In-Reply-To: <20161203092211.GA2762@netboy>
On 12/03/2016 03:22 AM, Richard Cochran wrote:
> On Fri, Dec 02, 2016 at 02:30:10PM -0600, Grygorii Strashko wrote:
>> 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 v3:
>> - patches reordered: fixes and small updates moved first
>> - added comments in code about cpts->cc_mult
>> - conversation range (maxsec) limited to 10sec
>
> On net-next:
>
> $ git am ~/grygorii.strashko
> Applying: net: ethernet: ti: cpts: switch to readl/writel_relaxed()
> Applying: net: ethernet: ti: allow cpts to be built separately
> error: patch failed: drivers/net/ethernet/ti/cpsw.c:1963
> error: drivers/net/ethernet/ti/cpsw.c: patch does not apply
> Patch failed at 0002 net: ethernet: ti: allow cpts to be built separately
Sorry for that, also there build error due to patch reordering :(
>
> Also, you have the order of the SOB tags wrong. The author's SOB goes
> first.
Will fix and resend, sorry again.
--
regards,
-grygorii
--
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] of/irq: improve error report on irq discovery process failure
From: Guilherme G. Piccoli @ 2016-12-05 19:01 UTC (permalink / raw)
To: Rob Herring
Cc: linux-pci@vger.kernel.org, devicetree@vger.kernel.org,
linuxppc-dev, Mark Rutland, Benjamin Herrenschmidt, Frank Rowand,
Marc Zyngier
In-Reply-To: <CAL_JsqKg4+SANVuhfjFQRrC4Ax7OhAjwuBpo0Xes9UFevFAdWg@mail.gmail.com>
On 12/05/2016 12:28 PM, Rob Herring wrote:
> On Mon, Dec 5, 2016 at 7:59 AM, Guilherme G. Piccoli
> <gpiccoli@linux.vnet.ibm.com> wrote:
>> On PowerPC machines some PCI slots might not have level triggered
>> interrupts capability (also know as level signaled interrupts),
>> leading of_irq_parse_pci() to complain by presenting error messages
>> on the kernel log - in this case, the properties "interrupt-map" and
>> "interrupt-map-mask" are not present on device's node in the device
>> tree.
>>
>> This patch introduces a different message for this specific case,
>> and also reduces its level from error to warning. Besides, we warn
>> (once) that possibly some PCI slots on the system have no level
>> triggered interrupts available.
>> We changed some error return codes too on function of_irq_parse_raw()
>> in order other failure's cases can be presented in a more precise way.
>>
>> Before this patch, when an adapter was plugged in a slot without level
>> interrupts capabilitiy on PowerPC, we saw a generic error message
>> like this:
>>
>> [54.239] pci 002d:70:00.0: of_irq_parse_pci() failed with rc=-22
>>
>> Now, with this applied, we see the following specific message:
>>
>> [16.154] pci 0014:60:00.1: of_irq_parse_pci: no interrupt-map found,
>> INTx interrupts not available
>>
>> Finally, we standardize the error path in of_irq_parse_raw() by always
>> taking the fail path instead of returning directly from the loop.
>>
>> Signed-off-by: Guilherme G. Piccoli <gpiccoli@linux.vnet.ibm.com>
>> ---
>>
>> v2:
>> * Changed function return code to always return negative values;
>
> Are you sure this is safe? This is tricky because of differing values
> of NO_IRQ (0 or -1).
Thanks Rob, but this is purely bad wording from myself. I'm sorry - I
meant to say that I changed only my positive return code (that was
suggested to be removed in the prior revision) to negative return code!
So, I changed only code I added myself in v1 =)
>
>> * Improved/simplified warning outputs;
>> * Changed some return codes and some error paths in of_irq_parse_raw()
>> in order to be more precise/consistent;
>
> This too could have some side effects on callers.
>
> Not saying don't do these changes, just need some assurances this has
> been considered.
Thanks for your attention. I performed a quick investigation before
changing this, all the places that use the return values are just
getting "true/false" information from that, meaning they just are
comparing to 0 basically. So change -EINVAL to -ENOENT wouldn't hurt any
user of these return values, it'll only become more informative IMHO.
Now, regarding the only error path that was changed: for some reason,
this was the only place in which we didn't goto fail label in case of
failure - it was added by a legacy commit from Ben, dated from 2006:
006b64de60 ("[POWERPC] Make OF irq map code detect more error cases").
Then it was carried by Grant Likely's commit 7dc2e1134a ("of/irq: merge
irq mapping code"), 6-year old commit.
I wasn't able to imagine a scenario in which changing this would break
something; I believe the change improve consistency, but I'd remove it
if you or somebody else thinks it worth be removed.
Cheers,
Guilherme
>
> Rob
>
^ permalink raw reply
* Re: [PATCH v2 2/2] eeprom: Add IDT 89HPESx driver bindings file
From: Serge Semin @ 2016-12-05 19:04 UTC (permalink / raw)
To: Rob Herring
Cc: Greg Kroah-Hartman, Srinivas Kandagatla, Andrew Lunn,
Mark Rutland, Sergey.Semin-vHJ8rsvMqnUPfZBKTuL5GA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CAL_JsqLbMGXSRLtTiD2d3Bsu4qc4bE029gieRN8x+QxPs=VbcA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On Mon, Dec 05, 2016 at 11:27:07AM -0600, Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> On Mon, Dec 5, 2016 at 9:25 AM, Serge Semin <fancer.lancer-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> > On Mon, Dec 05, 2016 at 08:46:21AM -0600, Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> >> On Tue, Nov 29, 2016 at 01:38:21AM +0300, Serge Semin wrote:
> >> > See cover-letter for changelog
> >> >
> >> > Signed-off-by: Serge Semin <fancer.lancer-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> >> >
> >> > ---
> >> > .../devicetree/bindings/misc/idt_89hpesx.txt | 41 ++++++++++++++++++++++
> >>
> >> There's not a better location for this? I can't tell because you don't
> >> describe what the device is.
> >>
> >
> > The device is PCIe-switch EEPROM driver with additional debug-interface to
> > access the switch CSRs. EEPROM is accesses via a separate i2c-slave
> > interface of the switch.
> >
> > There might be another place to put the binding file in. There is a special
> > location for EEPROM drivers bindings - Documentation/devicetree/bindings/eeprom/ .
> > But as far as I understood from the files put in there, it's intended for
> > pure EEPROM drivers only. On the other hand the directory I've chosen:
> > Documentation/devicetree/bindings/misc/
> > mostly intended for some unusual devices. My device isn't usual, since it
> > has CSRs debug-interface as well. Additionally I've found
> > eeprom-93xx46.txt binding file there, which describes EEPROM bindings.
> >
> > Anyway if you find the file should be placed in
> > Documentation/devicetree/bindings/eeprom/ instead, I'll move it, it's not
> > that a big problem.
> >
What about this comment? Shall the file be left at the path I placed it?
> >> > 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-
> >>
> >> Driver capabilties are irrelevant to bindings.
> >>
> >
> > Why? I've told in the comment, that the devices actually differ by the CSRs
> > map. Even though it's not reflected in the code at the moment, the CSRs
> > read/write restrictions can be added by some concerned programmer in
> > future. But If I left something like "compatible : idt,89hpesx" device
> > only, it will be problematic to add that functionality.
>
> Bindings describe the h/w, not what the Linux, FreeBSD, etc. driver
> does. You don't want to be changing the binding doc when the driver
> changes.
>
> > Howbeit If you think it's not necessary and "compatible = idt,89hpesx" is
> > ok, it's perfectly fine for me to make it this way. The property will be
> > even simpler, than current approach.
>
> NO! That's not at all what I'm suggesting. Specific compatible strings
> are the right way to go for the reasons you give. You just don't need
> to state why here (because it is true for all bindings).
>
Oh, I just misunderstood what you said. I'll discard the comment.
> >> > + 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)
> >>
> >> Don't we already have standard EEPROM properties that could be used
> >> here?
> >>
> >
> > If we do, just tell me which one. There are standard options:
>
> You can grep thru bindings as easily as I can. I can't do that for
> everyone's binding.
>
It won't be necessary due to the next comment.
> > "compatible, reg, pagesize, read-only". There isn't any connected with
> > EEPROM actual size.
> > Why so? Because standard EEPROM-drivers determine the device size from the
> > compatible-string name. Such approach won't work in this case, because
> > PCIe-switch and it EEPROM are actually two different devices. Look at the
> > chain of the usual platform board design:
> > Host <--- i2c ----> i2c-slave iface |PCIe-switch| i2c-master iface <--- i2c ---> EEPROM
> >
> > As you cas see the Host reaches EEPROM through the set of PCIe-switch
> > i2c-interfaces. In order to properly get data from it my driver needs actual
> > EEPROM size and it address in the i2c-master bus of the PCIe-switch, in
> > addition to the standard reg-field, which is address of PCIe-switch i2c-slave
> > interface and read-only parameter if EEPROM-device has got WP pin asserted.
>
> Ah, this needs to be much different than I thought. You need to model
> (i.e. use the same binding) the EEPROM node just like it was directly
> attached to the host. So this means you need the 2nd i2c bus modeled
> which means you need the PCIe switch modeled. A rough outline of the
> nodes would look like this:
>
> host-i2c: i2c {
> compatible ="host-i2c"
> };
>
> pcie {
> pcie-switch {
> i2c-bus = <&host-i2c>;
> i2c-bus {
> eeprom@50 {
> };
> };
> };
> };
>
> So this models the PCIe switch as a PCIe device, it has a phandle back
> to it's controller since it's not a child of the i2c controller. Then
> the devices on switches i2c bus are modeled as children of the switch.
>
> Alternatively, it could be described all as children of host-i2c node.
> It's common for i2c devices to have downstream i2c buses. I2C muxes
> are one example and there are bindings defined for all this. There's
> also chips like mpu-6050 that have slave buses.
>
> Rob
I think I understand what you says. However let me just bring some details
to make things clear.
First of all the driver doesn't do any PCI-Express-related work. The device
!IDT PCI Express switch! just has two additional i2c interfaces: i2c-slave
and i2c-master. As it is obvious from the bus-names i2c-slave is the interface,
where IDT PCIe-switch device is actually slave. This interface can be reached
from the host by ordinary i2c buses. i2c-master interface is connected to an
i2c-bus, where IDT PCIe-switch is single master. This bus can have just one
EEPROM device to store some initialization data. Host can send some specific
smbus-packets to i2c-slave interface of IDT PCIe-switch in order to
preinitialize EEPROM data, connected to i2c-master interface of the device.
Additionally IDT PCIe-switch handles some special smbus packets coming to it
i2c-slave interface to read/write its internal CSR. This interface can be
used to debug the device, when there are problems with it usual PCI Express
related functioning.
So to speak, it wouldn't be good to have PCIe-switch declared in dts as a
PCI-device, since PCI-bus is actually dynamically populated by PCI-core
subsystem.
According to what you said and the device/driver design I described, the
following bindings can be suggested:
i2c0: i2c@FFFF0000 {
compatible = "vendor,i2c-adapter";
#address-cells = <1>;
#size-cells = <0>;
idt_i2c_iface: idt@60 {
compatible = "idt,89hpes32nt8ag2";
reg = <0x60>;
#address-cells = <1>;
#size-cells = <0>;
eeprom@51 {
compatible = "at,24c64";
reg = <0x51>;
read-only;
};
};
};
Suppose there is some host-i2c adapter like "vendor,i2c-adapter" and
i2c-slave interface of IDT PCIe-switch is connected to it. In this way
i2c-slave interface will be visible like ordinary i2c-device with just
one subnode. This subnode explains the actual EEPROM connected to
IDT PCIe-switch i2c-master interface.
Does it look acceptable? It seems like your last suggestion. Is it?
Thanks,
-Sergey
--
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 1/6] net: ethernet: ti: netcp: add support of cpts
From: Richard Cochran @ 2016-12-05 19:30 UTC (permalink / raw)
To: Grygorii Strashko
Cc: Rob Herring, David S. Miller, netdev, Mugunthan V N, Sekhar Nori,
linux-kernel, linux-omap, devicetree, Murali Karicheri,
Wingman Kwok
In-Reply-To: <7a484f9c-a47d-3ccd-9611-d00b86feabdd@ti.com>
On Mon, Dec 05, 2016 at 12:25:57PM -0600, Grygorii Strashko wrote:
> >> --- a/Documentation/devicetree/bindings/net/keystone-netcp.txt
> >> +++ b/Documentation/devicetree/bindings/net/keystone-netcp.txt
> >> @@ -113,6 +113,15 @@ Optional properties:
> >> will only initialize these ports and attach PHY
> >> driver to them if needed.
> >>
> >> + Properties related to cpts configurations.
> >> + - cpts_clock_mult/cpts_clock_shift:
> >
> > Needs vendor prefix. Don't use '_'.
>
> This module is used as part of OMAP and Keystone SoCs, so names for
> this props is ABI already :(
Your automatic calculation makes these unnecessary, and so you can
drop these altogether.
Also, maybe you should mark them as deprecated in cpsw.txt?
(The underscores were my fault, sorry)
Thanks,
Richard
^ permalink raw reply
* [PATCH v4 00/13] net: ethernet: ti: cpts: update and fixes
From: Grygorii Strashko @ 2016-12-05 20:05 UTC (permalink / raw)
To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
Cc: Sekhar Nori, linux-kernel, linux-omap, devicetree,
Murali Karicheri, Wingman Kwok, Thomas Gleixner,
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 v4:
- fixed build error in patch
"net: ethernet: ti: cpts: clean up event list if event pool is empty"
- rebased on top of net-next
Changes in v3:
- patches reordered: fixes and small updates moved first
- added comments in code about cpts->cc_mult
- conversation range (maxsec) limited to 10sec
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"
Links on prev versions:
v3: https://www.spinics.net/lists/devicetree/msg153474.html
v2: http://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1282034.html
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: drop excessive writes to CTRL and INT_EN regs
net: ethernet: ti: cpts: rework initialization/deinitialization
net: ethernet: ti: cpts: move dt props parsing to cpts driver
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 | 239 +++++++++++++++++++------
drivers/net/ethernet/ti/cpts.h | 80 ++++++++-
kernel/time/clocksource.c | 1 +
8 files changed, 304 insertions(+), 115 deletions(-)
--
2.10.1
^ permalink raw reply
* [PATCH v4 01/13] net: ethernet: ti: cpts: switch to readl/writel_relaxed()
From: Grygorii Strashko @ 2016-12-05 20:05 UTC (permalink / raw)
To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
Cc: Sekhar Nori, linux-kernel, linux-omap, devicetree,
Murali Karicheri, Wingman Kwok, Thomas Gleixner,
Grygorii Strashko
In-Reply-To: <20161205200525.16664-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>
Acked-by: Richard Cochran <richardcochran@gmail.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 v4 02/13] net: ethernet: ti: allow cpts to be built separately
From: Grygorii Strashko @ 2016-12-05 20:05 UTC (permalink / raw)
To: David S. Miller, netdev-u79uwXL29TY76Z2rM5mHXA, Mugunthan V N,
Richard Cochran
Cc: Sekhar Nori, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Murali Karicheri, Wingman Kwok,
Thomas Gleixner, Grygorii Strashko
In-Reply-To: <20161205200525.16664-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 | 16 ++++++++--------
drivers/net/ethernet/ti/cpts.h | 18 ++++++++++++++----
5 files changed, 42 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 3f96c57..323174d 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -1594,7 +1594,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)
{
@@ -1742,7 +1742,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)
@@ -1755,12 +1764,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)
@@ -2100,10 +2107,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 =
@@ -2120,7 +2127,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 |
@@ -2128,9 +2140,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_link_ksettings(struct net_device *ndev,
struct ethtool_link_ksettings *ecmd)
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index a42c449..8cb0369 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,21 @@ 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 driver");
+MODULE_AUTHOR("Richard Cochran <richardcochran-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>");
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 v4 03/13] net: ethernet: ti: cpsw: minimize direct access to struct cpts
From: Grygorii Strashko @ 2016-12-05 20:05 UTC (permalink / raw)
To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
Cc: Sekhar Nori, linux-kernel, linux-omap, devicetree,
Murali Karicheri, Wingman Kwok, Thomas Gleixner,
Grygorii Strashko
In-Reply-To: <20161205200525.16664-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 323174d..ec05e20 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -1562,7 +1562,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);
@@ -1601,7 +1601,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;
}
@@ -1609,10 +1610,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);
@@ -1635,20 +1636,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;
}
@@ -1684,7 +1685,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:
@@ -1700,14 +1701,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:
@@ -1736,8 +1737,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 v4 04/13] net: ethernet: ti: cpts: fix unbalanced clk api usage in cpts_register/unregister
From: Grygorii Strashko @ 2016-12-05 20:05 UTC (permalink / raw)
To: David S. Miller, netdev-u79uwXL29TY76Z2rM5mHXA, Mugunthan V N,
Richard Cochran
Cc: Sekhar Nori, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Murali Karicheri, Wingman Kwok,
Thomas Gleixner, Grygorii Strashko
In-Reply-To: <20161205200525.16664-1-grygorii.strashko-l0cyMroinI0@public.gmane.org>
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-l0cyMroinI0@public.gmane.org>
Acked-by: Richard Cochran <richardcochran-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
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 8cb0369..61198f1 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
--
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 v4 05/13] net: ethernet: ti: cpts: fix registration order
From: Grygorii Strashko @ 2016-12-05 20:05 UTC (permalink / raw)
To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
Cc: Sekhar Nori, linux-kernel, linux-omap, devicetree,
Murali Karicheri, Wingman Kwok, Thomas Gleixner,
Grygorii Strashko
In-Reply-To: <20161205200525.16664-1-grygorii.strashko@ti.com>
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@ti.com>
Acked-by: Richard Cochran <richardcochran@gmail.com>
---
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 61198f1..3dda6d5 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
^ permalink raw reply related
* [PATCH v4 06/13] net: ethernet: ti: cpts: disable cpts when unregistered
From: Grygorii Strashko @ 2016-12-05 20:05 UTC (permalink / raw)
To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
Cc: Sekhar Nori, linux-kernel, linux-omap, devicetree,
Murali Karicheri, Wingman Kwok, Thomas Gleixner,
Grygorii Strashko
In-Reply-To: <20161205200525.16664-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>
Acked-by: Richard Cochran <richardcochran@gmail.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 3dda6d5..d3c1ac5 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 v4 07/13] net: ethernet: ti: cpts: clean up event list if event pool is empty
From: Grygorii Strashko @ 2016-12-05 20:05 UTC (permalink / raw)
To: David S. Miller, netdev-u79uwXL29TY76Z2rM5mHXA, Mugunthan V N,
Richard Cochran
Cc: Sekhar Nori, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Murali Karicheri, Wingman Kwok,
Thomas Gleixner, Grygorii Strashko
In-Reply-To: <20161205200525.16664-1-grygorii.strashko-l0cyMroinI0@public.gmane.org>
From: WingMan Kwok <w-kwok2-l0cyMroinI0@public.gmane.org>
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-l0cyMroinI0@public.gmane.org>
Signed-off-by: Grygorii Strashko <grygorii.strashko-l0cyMroinI0@public.gmane.org>
---
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 d3c1ac5..7ab1fa7 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)
+ pr_debug("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)) {
+ pr_err("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
--
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 v4 08/13] net: ethernet: ti: cpts: drop excessive writes to CTRL and INT_EN regs
From: Grygorii Strashko @ 2016-12-05 20:05 UTC (permalink / raw)
To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
Cc: Sekhar Nori, linux-kernel, linux-omap, devicetree,
Murali Karicheri, Wingman Kwok, Thomas Gleixner,
Grygorii Strashko
In-Reply-To: <20161205200525.16664-1-grygorii.strashko@ti.com>
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@ti.com>
Acked-by: Richard Cochran <richardcochran@gmail.com>
---
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 7ab1fa7..fe1bb7f 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
^ permalink raw reply related
* [PATCH v4 09/13] net: ethernet: ti: cpts: rework initialization/deinitialization
From: Grygorii Strashko @ 2016-12-05 20:05 UTC (permalink / raw)
To: David S. Miller, netdev-u79uwXL29TY76Z2rM5mHXA, Mugunthan V N,
Richard Cochran
Cc: Sekhar Nori, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Murali Karicheri, Wingman Kwok,
Thomas Gleixner, Grygorii Strashko
In-Reply-To: <20161205200525.16664-1-grygorii.strashko-l0cyMroinI0@public.gmane.org>
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-l0cyMroinI0@public.gmane.org>
---
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 ec05e20..deb008a 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -1486,9 +1486,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");
}
@@ -2796,6 +2794,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;
@@ -2823,12 +2822,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)) {
@@ -2916,7 +2909,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;
@@ -2930,7 +2923,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;
@@ -2997,6 +2990,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");
@@ -3112,6 +3113,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 fe1bb7f..9356803 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -248,24 +248,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)
{
@@ -372,34 +354,27 @@ 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);
+ /* reinitialize cc.mult to original value as it can be modified
+ * by cpts_ptp_adjfreq().
+ */
+ 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;
@@ -412,27 +387,72 @@ 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;
+
+ 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 driver");
MODULE_AUTHOR("Richard Cochran <richardcochran-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>");
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
--
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 v4 10/13] net: ethernet: ti: cpts: move dt props parsing to cpts driver
From: Grygorii Strashko @ 2016-12-05 20:05 UTC (permalink / raw)
To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
Cc: Sekhar Nori, linux-kernel, linux-omap, devicetree,
Murali Karicheri, Wingman Kwok, Thomas Gleixner,
Grygorii Strashko
In-Reply-To: <20161205200525.16664-1-grygorii.strashko@ti.com>
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@ti.com>
---
drivers/net/ethernet/ti/cpsw.c | 16 +---------------
drivers/net/ethernet/ti/cpsw.h | 2 --
drivers/net/ethernet/ti/cpts.c | 32 +++++++++++++++++++++++++++++---
drivers/net/ethernet/ti/cpts.h | 5 +++--
4 files changed, 33 insertions(+), 22 deletions(-)
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index deb008a..259c717 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -2524,18 +2524,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);
@@ -2990,9 +2978,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 9356803..59c09a4 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -409,10 +409,34 @@ 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;
+ /* save cc.mult original value as it can be modified
+ * by cpts_ptp_adjfreq().
+ */
+ 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;
cpts = devm_kzalloc(dev, sizeof(*cpts), GFP_KERNEL);
if (!cpts)
@@ -423,6 +447,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");
@@ -433,8 +461,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
^ permalink raw reply related
* [PATCH v4 11/13] clocksource: export the clocks_calc_mult_shift to use by timestamp code
From: Grygorii Strashko @ 2016-12-05 20:05 UTC (permalink / raw)
To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
Cc: Sekhar Nori, linux-kernel, linux-omap, devicetree,
Murali Karicheri, Wingman Kwok, Thomas Gleixner, John Stultz,
Grygorii Strashko
In-Reply-To: <20161205200525.16664-1-grygorii.strashko@ti.com>
From: Murali Karicheri <m-karicheri2@ti.com>
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@linaro.org>
Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
---
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
^ permalink raw reply related
* [PATCH v4 12/13] net: ethernet: ti: cpts: calc mult and shift from refclk freq
From: Grygorii Strashko @ 2016-12-05 20:05 UTC (permalink / raw)
To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
Cc: Sekhar Nori, linux-kernel, linux-omap, devicetree,
Murali Karicheri, Wingman Kwok, Thomas Gleixner,
Grygorii Strashko, John Stultz
In-Reply-To: <20161205200525.16664-1-grygorii.strashko@ti.com>
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@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
Documentation/devicetree/bindings/net/cpsw.txt | 8 ++--
drivers/net/ethernet/ti/cpts.c | 53 +++++++++++++++++++++++---
2 files changed, 52 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 59c09a4..361d13a 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -409,21 +409,60 @@ 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);
+ /* limit conversation rate to 10 sec as higher values will produce
+ * too small mult factors and so reduce the conversion accuracy
+ */
+ if (maxsec > 10)
+ maxsec = 10;
+
+ 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;
/* save cc.mult original value as it can be modified
* by cpts_ptp_adjfreq().
*/
- 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;
@@ -463,6 +502,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
^ permalink raw reply related
* [PATCH v4 13/13] net: ethernet: ti: cpts: fix overflow check period
From: Grygorii Strashko @ 2016-12-05 20:05 UTC (permalink / raw)
To: David S. Miller, netdev, Mugunthan V N, Richard Cochran
Cc: Sekhar Nori, linux-kernel, linux-omap, devicetree,
Murali Karicheri, Wingman Kwok, Thomas Gleixner,
Grygorii Strashko, John Stultz
In-Reply-To: <20161205200525.16664-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>
Acked-by: Richard Cochran <richardcochran@gmail.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 361d13a..a60d837 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,
@@ -382,8 +382,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:
@@ -427,6 +426,11 @@ static void cpts_calc_mult_shift(struct cpts *cpts)
if (maxsec > 10)
maxsec = 10;
+ /* 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
* Re: [PATCH] ARM: dts: imx7d: fix LCDIF clock assignment
From: Stefan Agner @ 2016-12-05 20:29 UTC (permalink / raw)
To: Uwe Kleine-König
Cc: Shawn Guo, Mark Rutland, devicetree, Fabio Estevam, linux-kernel,
robh+dt, Peter Chen, Sascha Hauer, Fabio Estevam, Liu Ying,
linux-arm-kernel, gary.bisson
In-Reply-To: <20161205070609.a6t7hzh3m3l2t37s@pengutronix.de>
On 2016-12-04 23:06, Uwe Kleine-König wrote:
> Hello Stefan,
>
> On Sun, Dec 04, 2016 at 05:26:58PM -0800, Stefan Agner wrote:
>> Since this fixes a kernel freeze, is there a chance to get this still in
>> 4.9?
>
> a Fixes:-Line would be nice then.
Good point.
Fixes: e8ed73f691bd ("ARM: dts: imx7d: add lcdif support")
--
Stefan
^ permalink raw reply
* Re: [PATCH 39/39] mtd: nand: denali_dt: add compatible strings for UniPhier SoC variants
From: Dinh Nguyen @ 2016-12-05 20:51 UTC (permalink / raw)
To: Marek Vasut
Cc: Masahiro Yamada, Rob Herring, linux-mtd@lists.infradead.org,
devicetree@vger.kernel.org, Linux Kernel Mailing List,
Boris Brezillon, Brian Norris, Richard Weinberger,
David Woodhouse, Cyrille Pitchen, Mark Rutland, Dinh Nguyen,
Alan Tull, Chin Liang See, Dinh Nguyen
In-Reply-To: <19bc0efe-bf1f-8251-7ff2-4dc5a5b61fce@gmail.com>
On Sun, Dec 4, 2016 at 10:22 PM, Marek Vasut <marek.vasut@gmail.com> wrote:
> On 12/05/2016 05:10 AM, Masahiro Yamada wrote:
>> Hi Marek,
>>
>>
>> 2016-12-05 12:44 GMT+09:00 Marek Vasut <marek.vasut@gmail.com>:
>>> On 12/05/2016 04:30 AM, Masahiro Yamada wrote:
>>>> Hi Dinh,
>>>>
>>>>
>>>> 2016-12-04 7:08 GMT+09:00 Dinh Nguyen <dinh.linux@gmail.com>:
>>>>> Hi,
>>>>>
>>>>> On Fri, Dec 2, 2016 at 8:49 PM, Marek Vasut <marek.vasut@gmail.com> wrote:
>>>>>> On 12/03/2016 03:41 AM, Masahiro Yamada wrote:
>>>>>>> Hi Rob,
>>>>>>
>>>>>> Hi!
>>>>>>
>>>>>>> 2016-12-03 1:26 GMT+09:00 Rob Herring <robh@kernel.org>:
>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> (Plan A)
>>>>>>>>> "denali,socfpga-nand" (for Altera SOCFPGA variant)
>>>>>>>>> "denali,uniphier-nand-v1" (for old Socionext UniPhier family variant)
>>>>>>>>> "denali,uniphier-nand-v2" (for new Socionext UniPhier family variant)
>>>>>>>>>
>>>>>>>>> (Plan B)
>>>>>>>>> "altera,denali-nand" (for Altera SOCFPGA variant)
>>>>>>>>> "socionext,denali-nand-v5a" (for old Socionext UniPhier family variant)
>>>>>>>>> "socionext,denali-nand-v5b" (for new Socionext UniPhier family variant)
>>>>>>>
>>>>>>>> Let the Altera folks worry about their stuff. At least for soft IP in
>>>>>>>> FPGA, it's a bit of a special case. The old string can remain as bad
>>>>>>>> as it is.
>>>>>>>
>>>>>>>
>>>>>>> Hmm, I am not sure if this IP would fit in FPGA
>>>>>>> (to use it along with NIOS-II?)
>>>>>>>
>>>>>>> (even if it happened, nothing of this IP would be customizable on users' side.
>>>>>>> When buying the IP, SoC vendors submit a list of desired features.
>>>>>>> Denali (now Cadence) generates the RTL according to the configuration sheet.
>>>>>>> The function is fixed at this point. So, generic compatible would be
>>>>>>> useless anyway.)
>>>>>>>
>>>>>>>
>>>>>>> If we are talking about SOCFPGA,
>>>>>>> SOCFPGA is not only FPGA. Rather "SOC" + "FPGA".
>>>>>>> It consists of two parts:
>>>>>>> [1] SOC part (Cortex-A9 + various hard-wired peripherals such UART,
>>>>>>> USB, SD, NAND, ...)
>>>>>>> [2] FPGA part (User design logic)
>>>>>>>
>>>>>>> The Denali NAND controller is included in [1].
>>>>>>> So, as far as we talk about the Denali on SOCFPGA,
>>>>>>> it is as hard-wired as Intel, Socionext's ones.
>>>>>>
>>>>>> That's correct, the Denali NAND IP in altera socfpga is a hardware
>>>>>> block. You can make it available to the fabric too, but by default
>>>>>> it's used by the ARM part of the chip, so for this discussion, you
>>>>>> can forget that the FPGA part exists altogether.
>>>>>>
>>>>>> I would be in favor of plan B, since it seems to be the more often
>>>>>> taken approach. A nice example is ci-hdrc:
>>>>>>
>>>>>> $ git grep compatible drivers/usb/chipidea/
>>>>>>
>>>>>>>> I simply would do "socionext,uniphier-v5b-nand" (and v5a).
>>>>>>>> The fact that it is denali is part of the documentation.
>>>>>>>>
>>>>>>>
>>>>>>> Let me think about this.
>>>>>>>
>>>>>>> Socionext bought two version of Denali IP,
>>>>>>> and we are now re-using the newer one (v5b) for several SoCs.
>>>>>>> Socionext has some more product lines other than Uniphier SoC family,
>>>>>>> perhaps wider re-use might happen in the future.
>>>>>>>
>>>>>>> At first, I included "uniphier" in compatible, but I am still wondering
>>>>>>> if such a specific string is good or not.
>>>>>>>
>>>>>>> Also, comments from Altera engineers are appreciated.
>>>>>
>>>>> Sorry, it's taken me a while to add comments. My altera email is very spotty now
>>>>> that the Intel merge is completed. Please use dinguyen@kernel.org for any future
>>>>> communications.
>>>>>
>>>>> Yes, everything that is said so far for the NAND controller on the
>>>>> SoCFPGA is correct. I added the binding for the controller a while
>>>>> back, but unfortunately, we never added the NAND interface to the
>>>>> devkit, so we did not do much in terms of enabling it.
>>>>>
>>>>> I think the only SoCFPGA board I know that has the NAND interface active is
>>>>> the TRCom board, but I have never seen that board.
>>>>>
>>>>> I don't have any strong opinions on this matter, just as long as the
>>>>> original binding
>>>>> "denali,denali-nand-dt" is kept, and I think Rob was ok with keeping
>>>>> that binding.
>>>>>
>>>>
>>>> I am proposing to add "altera,denali-nand" for Altera.
>>>> For what, do you need the generic compatible?
>>>> This IP has no default for it to fallback to.
>>>
>>> IMO just for compatibility reasons with old DTs .
>>
>> We generally contribute for
>> a "working driver" (at least, should be functional to some extent)
>> and "DT binding" bundled together.
>>
>> However, Altera upstreamed the DT binding first
>> (then some parts of the DT binding turned out wrong),
>> but they did not upstream needed driver changes in the end.
>>
>> So, the mainline driver has never worked on SOCFPGA, right?
>
> Most likely it never worked, yes.
>
Right, looking through our downstream support, we may need to upstream a
few changes to make upstream driver work on SoCFPGA.
>> Removing "denali,denali-nand-dt" is not breakage at all,
>> so I do not owe anything to them, right?
>
> I don't think I'm really qualified to answer this one. But, there is
> drivers/mtd/nand/denali_dt.c , which handles this compatible string
> and it's documented in
> Documentation/devicetree/bindings/mtd/denali-nand.txt, so doesn't that
> make it part of the ABI ? I think we should
> at least keep it as a fallback, that should be pretty harmless.
>
I would like to propose "altr,denali-nand" as the binding we use to support the
driver going forward on SoCFPGA hardware. It's pretty much the same as
"altera,denali-nand", just with the correct vendor prefix.
If we can please keep, "denali,denali-nand-dt" only because SoCFPGA is using
this binding downstream, but I know that is a weak argument.
Dinh
^ permalink raw reply
* Re: [PATCH v3 1/2] dt-bindings: drm/bridge: adv7511: Add regulator bindings
From: Bjorn Andersson @ 2016-12-05 21:11 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Archit Taneja, linux-arm-msm, robh, dri-devel, devicetree,
Mark Brown
In-Reply-To: <3929994.7YhJtsl9c3@avalon>
On Tue 29 Nov 01:11 PST 2016, Laurent Pinchart wrote:
> Hi Archit,
>
> (CC'ing Mark Brown)
>
> On Tuesday 29 Nov 2016 13:41:33 Archit Taneja wrote:
> > On 11/29/2016 12:03 PM, Laurent Pinchart wrote:
> > > On Tuesday 29 Nov 2016 11:37:41 Archit Taneja wrote:
> > >> Add the regulator supply properties needed by ADV7511 and ADV7533.
> > >>
> > >> The regulators are specified as optional properties since there can
> > >> be boards which have a fixed supply directly routed to the pins, and
> > >> these may not be modelled as regulator supplies.
> > >
> > > That's why we have support for dummy supplies in the kernel, isn't it ?
> > > Isn't it better to make the supplies mandatory in the bindings (and
> > > obviously handling them as optional in the driver for
> > > backward-compatibility) ?
> >
> > I'm a bit unclear on this.
> >
> > I thought we couldn't add mandatory properties once the device is already
> > present in DT for one or more platforms.
>
> You can, as long as you treat them as optional in the driver to retain
> backward compatibility. The DT bindings should document the properties
> expected from a new platform (older versions of the bindings will always be
> available in the git history).
If you document them as required and don't do anything special in the
implementation (i.e. just call devm_regulator_get() as usual) it will
just work, in the absence of the property you will get a dummy regulator
from the framework.
And then add the fixed-voltage regulators to the new DT to make that
properly describe the hardware.
>
> > Say, if we do make it mandatory for future additions, we would need to have
> > DT property for the supplies for the new platforms. If the regulators on
> > these boards are fixed supplies, they would be need to be modeled
> > using "regulator-fixed", possibly without any input supply. Is that
> > what you're suggesting?
>
> That's the idea, yes. Clock maintainers have a similar opinion regarding the
> clock bindings, where a clock that is not optional at the hardware level
> should be specified in DT even if it's always present.
>
Further more, a DT binding for a particular block should describe that
block; so if we have three different 1.8V pins then the DT binding
should reflect this - even if our current platform have them wired to
the same regulator.
(And the supply names would preferably be based on the pin names in the
component data sheet)
Regards,
Bjorn
^ permalink raw reply
* Re: [PATCH v3 1/2] dt-bindings: drm/bridge: adv7511: Add regulator bindings
From: Laurent Pinchart @ 2016-12-05 21:16 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Archit Taneja, linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
robh-DgEjT+Ai2ygdnm+yROfE0A,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
devicetree-u79uwXL29TY76Z2rM5mHXA, Mark Brown
In-Reply-To: <20161205211151.GA30492@tuxbot>
Hi Bjorn,
On Monday 05 Dec 2016 13:11:51 Bjorn Andersson wrote:
> On Tue 29 Nov 01:11 PST 2016, Laurent Pinchart wrote:
> > On Tuesday 29 Nov 2016 13:41:33 Archit Taneja wrote:
> >> On 11/29/2016 12:03 PM, Laurent Pinchart wrote:
> >>> On Tuesday 29 Nov 2016 11:37:41 Archit Taneja wrote:
> >>>> Add the regulator supply properties needed by ADV7511 and ADV7533.
> >>>>
> >>>> The regulators are specified as optional properties since there can
> >>>> be boards which have a fixed supply directly routed to the pins, and
> >>>> these may not be modelled as regulator supplies.
> >>>
> >>> That's why we have support for dummy supplies in the kernel, isn't it
> >>> ? Isn't it better to make the supplies mandatory in the bindings (and
> >>> obviously handling them as optional in the driver for
> >>> backward-compatibility) ?
> >>
> >> I'm a bit unclear on this.
> >>
> >> I thought we couldn't add mandatory properties once the device is
> >> already present in DT for one or more platforms.
> >
> > You can, as long as you treat them as optional in the driver to retain
> > backward compatibility. The DT bindings should document the properties
> > expected from a new platform (older versions of the bindings will always
> > be available in the git history).
>
> If you document them as required and don't do anything special in the
> implementation (i.e. just call devm_regulator_get() as usual) it will
> just work, in the absence of the property you will get a dummy regulator
> from the framework.
>
> And then add the fixed-voltage regulators to the new DT to make that
> properly describe the hardware.
>
> >> Say, if we do make it mandatory for future additions, we would need to
> >> have DT property for the supplies for the new platforms. If the
> >> regulators on these boards are fixed supplies, they would be need to be
> >> modeled using "regulator-fixed", possibly without any input supply. Is
> >> that what you're suggesting?
> >
> > That's the idea, yes. Clock maintainers have a similar opinion regarding
> > the clock bindings, where a clock that is not optional at the hardware
> > level should be specified in DT even if it's always present.
>
> Further more, a DT binding for a particular block should describe that
> block; so if we have three different 1.8V pins then the DT binding
> should reflect this - even if our current platform have them wired to
> the same regulator.
This has been discussed previously, and Rob agreed that if the datasheet
recommends to power all supplies from the same regulator we can take that as a
good hint that a single supply should be enough. In the very unlikely event
that a board would require control of more regulators we can always extend the
DT bindings later without breaking backward compatibility.
> (And the supply names would preferably be based on the pin names in the
> component data sheet)
--
Regards,
Laurent Pinchart
--
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