Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cf03e961 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: emac: export sysfs nodes for RTC control"

parents 039e9ed4 9a6a7422
Loading
Loading
Loading
Loading
+135 −3
Original line number Diff line number Diff line
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -338,7 +338,7 @@ static int emac_ptp_sysfs_tstamp_show(struct device *dev,
		return retval;

	getnstimeofday(&ts_now);
	retval = snprintf(buf, count,
	retval = scnprintf(buf, count,
			  "%12u.%09u tstamp  %12u.%08u time-of-day\n",
			  (int)ts.tv_sec, (int)ts.tv_nsec,
			  (int)ts_now.tv_sec, (int)ts_now.tv_nsec);
@@ -346,15 +346,147 @@ static int emac_ptp_sysfs_tstamp_show(struct device *dev,
	return retval;
}

/* display ethernet mac time as well as the time of the next mac pps pulse */
static int emac_ptp_sysfs_mtnp_show(
	struct device *dev,
	struct device_attribute *attr,
	char *buf)
{
	struct emac_adapter *adpt = netdev_priv(to_net_dev(dev));
	int                  count = PAGE_SIZE;
	struct timespec      ts;
	int                  ret;

	ret = emac_ptp_gettime(&adpt->hw, &ts);
	if (ret)
		return ret;

	return scnprintf(buf, count, "%ld %ld %ld %ld\n",
			 ts.tv_sec,
			 ts.tv_nsec,
			 (ts.tv_nsec != 0) ? ts.tv_sec : ts.tv_sec + 1,
			 NSEC_PER_SEC - ts.tv_nsec);
}

/* Do a "slam" of a very particular time into the time registers... */
static int emac_ptp_sysfs_slam(
	struct device *dev,
	struct device_attribute *attr,
	const char *buf,
	size_t count)
{
	struct emac_adapter *adpt = netdev_priv(to_net_dev(dev));
	uint32_t             sec = 0;
	uint32_t             nsec = 0;
	int                  ret = -EINVAL;

	if (sscanf(buf, "%u %u", &sec, &nsec) == 2) {
		struct timespec ts = {sec, nsec};
		ret = emac_ptp_settime(&adpt->hw, &ts);
		if (ret) {
			pr_err("%s: emac_ptp_settime failed.\n", __func__);
			return ret;
		}
		ret = count;
	} else
		pr_err("%s: sscanf failed.\n", __func__);

	return ret;
}

/* Do a coarse time ajustment (ie. coarsely adjust (+/-) the time
 * registers by the passed offset)
 */
static int emac_ptp_sysfs_cadj(
	struct device *dev,
	struct device_attribute *attr,
	const char *buf,
	size_t count)
{
	struct emac_adapter *adpt = netdev_priv(to_net_dev(dev));
	int64_t              offset = 0;
	int                  ret = -EINVAL;

	if (sscanf(buf, "%lld", &offset) == 1) {
		struct timespec ts;
		uint64_t        new_offset;
		uint32_t        sec;
		uint32_t        nsec;

		ret = emac_ptp_gettime(&adpt->hw, &ts);
		if (ret) {
			pr_err("%s: emac_ptp_gettime failed.\n", __func__);
			return ret;
		}

		sec  = ts.tv_sec;
		nsec = ts.tv_nsec;

		new_offset = (((uint64_t) sec * NSEC_PER_SEC) +
			      (uint64_t) nsec) + offset;

		nsec = do_div(new_offset, NSEC_PER_SEC);
		sec  = new_offset;

		ts.tv_sec  = sec;
		ts.tv_nsec = nsec;

		ret = emac_ptp_settime(&adpt->hw, &ts);
		if (ret) {
			pr_err("%s: emac_ptp_settime failed.\n", __func__);
			return ret;
		}
		ret = count;
	} else
		pr_err("%s: sscanf failed.\n", __func__);

	return ret;
}

/* Do a fine time ajustment (ie. have the timestamp registers adjust
 * themselves by the passed amount).
 */
static int emac_ptp_sysfs_fadj(
	struct device *dev,
	struct device_attribute *attr,
	const char *buf,
	size_t count)
{
	struct emac_adapter *adpt = netdev_priv(to_net_dev(dev));
	int64_t              offset = 0;
	int                  ret = -EINVAL;

	if (sscanf(buf, "%lld", &offset) == 1) {
		ret = emac_ptp_adjtime(&adpt->hw, offset);
		if (ret) {
			pr_err("%s: emac_ptp_adjtime failed.\n", __func__);
			return ret;
		}
		ret = count;
	} else {
		pr_err("%s: sscanf failed.\n", __func__);
	}

	return ret;
}

static DEVICE_ATTR(cmd, 0222, NULL, emac_ptp_sysfs_cmd);
static DEVICE_ATTR(tstamp, 0444, emac_ptp_sysfs_tstamp_show, NULL);
static DEVICE_ATTR(mtnp, 0444, emac_ptp_sysfs_mtnp_show, NULL);
static DEVICE_ATTR(slam, 0222, NULL, emac_ptp_sysfs_slam);
static DEVICE_ATTR(cadj, 0222, NULL, emac_ptp_sysfs_cadj);
static DEVICE_ATTR(fadj, 0222, NULL, emac_ptp_sysfs_fadj);

static void emac_ptp_sysfs_create(struct net_device *netdev)
{
	struct emac_adapter *adpt = netdev_priv(netdev);

	if (device_create_file(&netdev->dev, &dev_attr_cmd) ||
	    device_create_file(&netdev->dev, &dev_attr_tstamp))
	    device_create_file(&netdev->dev, &dev_attr_tstamp) ||
	    device_create_file(&netdev->dev, &dev_attr_mtnp) ||
	    device_create_file(&netdev->dev, &dev_attr_slam) ||
	    device_create_file(&netdev->dev, &dev_attr_cadj) ||
	    device_create_file(&netdev->dev, &dev_attr_fadj))
		emac_err(adpt, "emac_ptp: failed to create sysfs files\n");
}