aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-omap2/am33xx/clk_synthesizer.c
blob: ff1bfaf84b69e5b260f4590bbc86c7306de8657b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// SPDX-License-Identifier: GPL-2.0+
/*
 * clk-synthesizer.c
 *
 * Clock synthesizer apis
 *
 * Copyright (C) 2016, Texas Instruments, Incorporated - http://www.ti.com/
 */


#include <common.h>
#include <asm/arch/clk_synthesizer.h>
#include <i2c.h>

/**
 * clk_synthesizer_reg_read - Read register from synthesizer.
 * dev:		i2c bus device (not used if CONFIG_DM_I2C is not set)
 * @addr:	addr within the i2c device
 * buf:		Buffer to which value is to be read.
 *
 * For reading the register from this clock synthesizer, a command needs to
 * be send along with enabling byte read more, and then read can happen.
 * Returns 0 on success
 */
static int clk_synthesizer_reg_read(struct udevice *dev, int addr, u8 *buf)
{
	int rc;

	/* Enable Bye read */
	addr = addr | CLK_SYNTHESIZER_BYTE_MODE;

#ifndef CONFIG_DM_I2C
	/* Send the command byte */
	rc = i2c_write(CLK_SYNTHESIZER_I2C_ADDR, addr, 1, buf, 1);
	if (rc)
		printf("Failed to send command to clock synthesizer\n");

	/* Read the Data */
	return i2c_read(CLK_SYNTHESIZER_I2C_ADDR, addr, 1, buf, 1);
#else
	/* Send the command byte */
	rc = dm_i2c_reg_write(dev, addr, *buf);
	if (rc)
		printf("Failed to send command to clock synthesizer\n");

	/* Read the Data */
	rc = dm_i2c_reg_read(dev, addr);
	if (rc < 0)
		return rc;

	*buf = (u8)rc;
	return 0;
#endif

}

/**
 * clk_synthesizer_reg_write - Write a value to register in synthesizer.
 * dev:		i2c bus device (not used if CONFIG_DM_I2C is not set)
 * @addr:	addr within the i2c device
 * val:		Value to be written in the addr.
 *
 * Enable the byte read mode in the address and start the i2c transfer.
 * Returns 0 on success
 */
static int clk_synthesizer_reg_write(struct udevice *dev, int addr, u8 val)
{
	u8 cmd[2];
	int rc = 0;

	/* Enable byte write */
	cmd[0] = addr | CLK_SYNTHESIZER_BYTE_MODE;
	cmd[1] = val;

#ifndef CONFIG_DM_I2C
	rc = i2c_write(CLK_SYNTHESIZER_I2C_ADDR, addr, 1, cmd, 2);
#else
	rc = dm_i2c_write(dev, addr, cmd, 2);
#endif
	if (rc)
		printf("Clock synthesizer reg write failed at addr = 0x%x\n",
		       addr);
	return rc;
}

/**
 * setup_clock_syntherizer - Program the clock synthesizer to get the desired
 *				frequency.
 * @data: Data containing the desired output
 *
 * This is a PLL-based high performance synthesizer which gives 3 outputs
 * as per the PLL_DIV and load capacitor programmed.
 */
int setup_clock_synthesizer(struct clk_synth *data)
{
	int rc;
	u8 val = 0;
	struct udevice *dev = NULL;
#ifndef CONFIG_DM_I2C
	rc =  i2c_probe(CLK_SYNTHESIZER_I2C_ADDR);
	if (rc) {
		printf("i2c probe failed at address 0x%x\n",
		       CLK_SYNTHESIZER_I2C_ADDR);
		return rc;
	}
#else
	rc = i2c_get_chip_for_busnum(0, CLK_SYNTHESIZER_I2C_ADDR, 1, &dev);
	if (rc) {
		printf("failed to get device for synthesizer at address 0x%x\n",
		       CLK_SYNTHESIZER_I2C_ADDR);
		return rc;
	}
#endif
	rc = clk_synthesizer_reg_read(dev, CLK_SYNTHESIZER_ID_REG, &val);
	if (val != data->id)
		return rc;

	/* Crystal Load capacitor selection */
	rc = clk_synthesizer_reg_write(dev, CLK_SYNTHESIZER_XCSEL,
				       data->capacitor);
	if (rc)
		return rc;
	rc = clk_synthesizer_reg_write(dev, CLK_SYNTHESIZER_MUX_REG,
				       data->mux);
	if (rc)
		return rc;
	rc = clk_synthesizer_reg_write(dev, CLK_SYNTHESIZER_PDIV2_REG,
				       data->pdiv2);
	if (rc)
		return rc;
	rc = clk_synthesizer_reg_write(dev, CLK_SYNTHESIZER_PDIV3_REG,
				       data->pdiv3);
	if (rc)
		return rc;

	return 0;
}