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

Commit 6c6ff145 authored by Akinobu Mita's avatar Akinobu Mita Committed by Alexandre Belloni
Browse files

rtc: ds1307: add clock provider support for DS3231



DS3231 has programmable square-wave output signal.
This enables to use this feature as a clock provider of
common clock framework.

Signed-off-by: default avatarAkinobu Mita <akinobu.mita@gmail.com>
Reviewed-by: default avatarMichael Turquette <mturquette@baylibre.com>
Signed-off-by: default avatarAlexandre Belloni <alexandre.belloni@free-electrons.com>
parent f3937549
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
* Maxim DS3231 Real Time Clock

Required properties:
see: Documentation/devicetree/bindings/i2c/trivial-devices.txt

Optional property:
- #clock-cells: Should be 1.
- clock-output-names:
  overwrite the default clock names "ds3231_clk_sqw" and "ds3231_clk_32khz".

Each clock is assigned an identifier and client nodes can use this identifier
to specify the clock which they consume. Following indices are allowed:
    - 0: square-wave output on the SQW pin
    - 1: square-wave output on the 32kHz pin

- interrupts: rtc alarm/event interrupt. When this property is selected,
  clock on the SQW pin cannot be used.

Example:

ds3231: ds3231@51 {
	compatible = "maxim,ds3231";
	reg = <0x68>;
	#clock-cells = <1>;
};

device1 {
...
	clocks = <&ds3231 0>;
...
};

device2 {
...
	clocks = <&ds3231 1>;
...
};
+295 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <linux/string.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/clk-provider.h>

/*
 * We can't determine type by probing, but if we expect pre-Linux code
@@ -91,6 +92,7 @@ enum ds_type {
#	define DS1340_BIT_OSF		0x80
#define DS1337_REG_STATUS	0x0f
#	define DS1337_BIT_OSF		0x80
#	define DS3231_BIT_EN32KHZ	0x08
#	define DS1337_BIT_A2I		0x02
#	define DS1337_BIT_A1I		0x01
#define DS1339_REG_ALARM1_SECS	0x07
@@ -120,6 +122,9 @@ struct ds1307 {
			       u8 length, u8 *values);
	s32 (*write_block_data)(const struct i2c_client *client, u8 command,
				u8 length, const u8 *values);
#ifdef CONFIG_COMMON_CLK
	struct clk_hw		clks[2];
#endif
};

struct chip_desc {
@@ -926,7 +931,295 @@ static void ds1307_hwmon_register(struct ds1307 *ds1307)
{
}

#endif
#endif /* CONFIG_RTC_DRV_DS1307_HWMON */

/*----------------------------------------------------------------------*/

/*
 * Square-wave output support for DS3231
 * Datasheet: https://datasheets.maximintegrated.com/en/ds/DS3231.pdf
 */
#ifdef CONFIG_COMMON_CLK

enum {
	DS3231_CLK_SQW = 0,
	DS3231_CLK_32KHZ,
};

#define clk_sqw_to_ds1307(clk)	\
	container_of(clk, struct ds1307, clks[DS3231_CLK_SQW])
#define clk_32khz_to_ds1307(clk)	\
	container_of(clk, struct ds1307, clks[DS3231_CLK_32KHZ])

static int ds3231_clk_sqw_rates[] = {
	1,
	1024,
	4096,
	8192,
};

static int ds1337_write_control(struct ds1307 *ds1307, u8 mask, u8 value)
{
	struct i2c_client *client = ds1307->client;
	struct mutex *lock = &ds1307->rtc->ops_lock;
	int control;
	int ret;

	mutex_lock(lock);

	control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
	if (control < 0) {
		ret = control;
		goto out;
	}

	control &= ~mask;
	control |= value;

	ret = i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, control);
out:
	mutex_unlock(lock);

	return ret;
}

static unsigned long ds3231_clk_sqw_recalc_rate(struct clk_hw *hw,
						unsigned long parent_rate)
{
	struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
	int control;
	int rate_sel = 0;

	control = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_CONTROL);
	if (control < 0)
		return control;
	if (control & DS1337_BIT_RS1)
		rate_sel += 1;
	if (control & DS1337_BIT_RS2)
		rate_sel += 2;

	return ds3231_clk_sqw_rates[rate_sel];
}

static long ds3231_clk_sqw_round_rate(struct clk_hw *hw, unsigned long rate,
					unsigned long *prate)
{
	int i;

	for (i = ARRAY_SIZE(ds3231_clk_sqw_rates) - 1; i >= 0; i--) {
		if (ds3231_clk_sqw_rates[i] <= rate)
			return ds3231_clk_sqw_rates[i];
	}

	return 0;
}

static int ds3231_clk_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
					unsigned long parent_rate)
{
	struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
	int control = 0;
	int rate_sel;

	for (rate_sel = 0; rate_sel < ARRAY_SIZE(ds3231_clk_sqw_rates);
			rate_sel++) {
		if (ds3231_clk_sqw_rates[rate_sel] == rate)
			break;
	}

	if (rate_sel == ARRAY_SIZE(ds3231_clk_sqw_rates))
		return -EINVAL;

	if (rate_sel & 1)
		control |= DS1337_BIT_RS1;
	if (rate_sel & 2)
		control |= DS1337_BIT_RS2;

	return ds1337_write_control(ds1307, DS1337_BIT_RS1 | DS1337_BIT_RS2,
				control);
}

static int ds3231_clk_sqw_prepare(struct clk_hw *hw)
{
	struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);

	return ds1337_write_control(ds1307, DS1337_BIT_INTCN, 0);
}

static void ds3231_clk_sqw_unprepare(struct clk_hw *hw)
{
	struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);

	ds1337_write_control(ds1307, DS1337_BIT_INTCN, DS1337_BIT_INTCN);
}

static int ds3231_clk_sqw_is_prepared(struct clk_hw *hw)
{
	struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
	int control;

	control = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_CONTROL);
	if (control < 0)
		return control;

	return !(control & DS1337_BIT_INTCN);
}

static const struct clk_ops ds3231_clk_sqw_ops = {
	.prepare = ds3231_clk_sqw_prepare,
	.unprepare = ds3231_clk_sqw_unprepare,
	.is_prepared = ds3231_clk_sqw_is_prepared,
	.recalc_rate = ds3231_clk_sqw_recalc_rate,
	.round_rate = ds3231_clk_sqw_round_rate,
	.set_rate = ds3231_clk_sqw_set_rate,
};

static unsigned long ds3231_clk_32khz_recalc_rate(struct clk_hw *hw,
						unsigned long parent_rate)
{
	return 32768;
}

static int ds3231_clk_32khz_control(struct ds1307 *ds1307, bool enable)
{
	struct i2c_client *client = ds1307->client;
	struct mutex *lock = &ds1307->rtc->ops_lock;
	int status;
	int ret;

	mutex_lock(lock);

	status = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS);
	if (status < 0) {
		ret = status;
		goto out;
	}

	if (enable)
		status |= DS3231_BIT_EN32KHZ;
	else
		status &= ~DS3231_BIT_EN32KHZ;

	ret = i2c_smbus_write_byte_data(client, DS1337_REG_STATUS, status);
out:
	mutex_unlock(lock);

	return ret;
}

static int ds3231_clk_32khz_prepare(struct clk_hw *hw)
{
	struct ds1307 *ds1307 = clk_32khz_to_ds1307(hw);

	return ds3231_clk_32khz_control(ds1307, true);
}

static void ds3231_clk_32khz_unprepare(struct clk_hw *hw)
{
	struct ds1307 *ds1307 = clk_32khz_to_ds1307(hw);

	ds3231_clk_32khz_control(ds1307, false);
}

static int ds3231_clk_32khz_is_prepared(struct clk_hw *hw)
{
	struct ds1307 *ds1307 = clk_32khz_to_ds1307(hw);
	int status;

	status = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_STATUS);
	if (status < 0)
		return status;

	return !!(status & DS3231_BIT_EN32KHZ);
}

static const struct clk_ops ds3231_clk_32khz_ops = {
	.prepare = ds3231_clk_32khz_prepare,
	.unprepare = ds3231_clk_32khz_unprepare,
	.is_prepared = ds3231_clk_32khz_is_prepared,
	.recalc_rate = ds3231_clk_32khz_recalc_rate,
};

static struct clk_init_data ds3231_clks_init[] = {
	[DS3231_CLK_SQW] = {
		.name = "ds3231_clk_sqw",
		.ops = &ds3231_clk_sqw_ops,
		.flags = CLK_IS_ROOT,
	},
	[DS3231_CLK_32KHZ] = {
		.name = "ds3231_clk_32khz",
		.ops = &ds3231_clk_32khz_ops,
		.flags = CLK_IS_ROOT,
	},
};

static int ds3231_clks_register(struct ds1307 *ds1307)
{
	struct i2c_client *client = ds1307->client;
	struct device_node *node = client->dev.of_node;
	struct clk_onecell_data	*onecell;
	int i;

	onecell = devm_kzalloc(&client->dev, sizeof(*onecell), GFP_KERNEL);
	if (!onecell)
		return -ENOMEM;

	onecell->clk_num = ARRAY_SIZE(ds3231_clks_init);
	onecell->clks = devm_kcalloc(&client->dev, onecell->clk_num,
					sizeof(onecell->clks[0]), GFP_KERNEL);
	if (!onecell->clks)
		return -ENOMEM;

	for (i = 0; i < ARRAY_SIZE(ds3231_clks_init); i++) {
		struct clk_init_data init = ds3231_clks_init[i];

		/*
		 * Interrupt signal due to alarm conditions and square-wave
		 * output share same pin, so don't initialize both.
		 */
		if (i == DS3231_CLK_SQW && test_bit(HAS_ALARM, &ds1307->flags))
			continue;

		/* optional override of the clockname */
		of_property_read_string_index(node, "clock-output-names", i,
						&init.name);
		ds1307->clks[i].init = &init;

		onecell->clks[i] = devm_clk_register(&client->dev,
							&ds1307->clks[i]);
		if (IS_ERR(onecell->clks[i]))
			return PTR_ERR(onecell->clks[i]);
	}

	if (!node)
		return 0;

	of_clk_add_provider(node, of_clk_src_onecell_get, onecell);

	return 0;
}

static void ds1307_clks_register(struct ds1307 *ds1307)
{
	int ret;

	if (ds1307->type != ds_3231)
		return;

	ret = ds3231_clks_register(ds1307);
	if (ret) {
		dev_warn(&ds1307->client->dev,
			"unable to register clock device %d\n", ret);
	}
}

#else

static void ds1307_clks_register(struct ds1307 *ds1307)
{
}

#endif /* CONFIG_COMMON_CLK */

static int ds1307_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
@@ -1294,6 +1587,7 @@ static int ds1307_probe(struct i2c_client *client,
	}

	ds1307_hwmon_register(ds1307);
	ds1307_clks_register(ds1307);

	return 0;