Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: RK808: add clkout driver for RK808

This is the initial version of the RK808 PMIC. This is a power management
IC for multimedia products. It provides regulators that are able to
supply power to processor cores and other components. The chip provides
other modules including RTC, Clockout.

Signed-off-by: Chris Zhong <zyw@rock-chips.com>
Reviewed-by: Doug Anderson <dianders@chromium.org>
Tested-by: Doug Anderson <dianders@chromium.org>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Samuel Ortiz <sameo@linux.intel.com> says:
Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: Olof Johansson <olof@lixom.net>
Cc: Dmitry Torokhov <dtor@chromium.org>
Cc: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Cc: Kever Yang <kever.yang@rock-chips.com>
Cc: Li Zhong <zhong@linux.vnet.ibm.com>
Cc: Russell King <rmk@arm.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Chris Zhong and committed by
Linus Torvalds
038b892a 3ca1e326

+180
+9
drivers/clk/Kconfig
··· 38 38 ---help--- 39 39 This driver supports Maxim 77686 crystal oscillator clock. 40 40 41 + config COMMON_CLK_RK808 42 + tristate "Clock driver for RK808" 43 + depends on MFD_RK808 44 + ---help--- 45 + This driver supports RK808 crystal oscillator clock. These 46 + multi-function devices have two fixed-rate oscillators, 47 + clocked at 32KHz each. Clkout1 is always on, Clkout2 can off 48 + by control register. 49 + 41 50 config COMMON_CLK_SI5351 42 51 tristate "Clock driver for SiLabs 5351A/B/C" 43 52 depends on I2C
+1
drivers/clk/Makefile
··· 28 28 obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o 29 29 obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o 30 30 obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o 31 + obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o 31 32 obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o 32 33 obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o 33 34 obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o
+170
drivers/clk/clk-rk808.c
··· 1 + /* 2 + * Clkout driver for Rockchip RK808 3 + * 4 + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd 5 + * 6 + * Author:Chris Zhong <zyw@rock-chips.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify it 9 + * under the terms and conditions of the GNU General Public License, 10 + * version 2, as published by the Free Software Foundation. 11 + * 12 + * This program is distributed in the hope it will be useful, but WITHOUT 13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 + * more details. 16 + */ 17 + 18 + #include <linux/clk.h> 19 + #include <linux/clk-provider.h> 20 + #include <linux/module.h> 21 + #include <linux/slab.h> 22 + #include <linux/platform_device.h> 23 + #include <linux/mfd/rk808.h> 24 + #include <linux/i2c.h> 25 + 26 + #define RK808_NR_OUTPUT 2 27 + 28 + struct rk808_clkout { 29 + struct rk808 *rk808; 30 + struct clk_onecell_data clk_data; 31 + struct clk_hw clkout1_hw; 32 + struct clk_hw clkout2_hw; 33 + }; 34 + 35 + static unsigned long rk808_clkout_recalc_rate(struct clk_hw *hw, 36 + unsigned long parent_rate) 37 + { 38 + return 32768; 39 + } 40 + 41 + static int rk808_clkout2_enable(struct clk_hw *hw, bool enable) 42 + { 43 + struct rk808_clkout *rk808_clkout = container_of(hw, 44 + struct rk808_clkout, 45 + clkout2_hw); 46 + struct rk808 *rk808 = rk808_clkout->rk808; 47 + 48 + return regmap_update_bits(rk808->regmap, RK808_CLK32OUT_REG, 49 + CLK32KOUT2_EN, enable ? CLK32KOUT2_EN : 0); 50 + } 51 + 52 + static int rk808_clkout2_prepare(struct clk_hw *hw) 53 + { 54 + return rk808_clkout2_enable(hw, true); 55 + } 56 + 57 + static void rk808_clkout2_unprepare(struct clk_hw *hw) 58 + { 59 + rk808_clkout2_enable(hw, false); 60 + } 61 + 62 + static int rk808_clkout2_is_prepared(struct clk_hw *hw) 63 + { 64 + struct rk808_clkout *rk808_clkout = container_of(hw, 65 + struct rk808_clkout, 66 + clkout2_hw); 67 + struct rk808 *rk808 = rk808_clkout->rk808; 68 + uint32_t val; 69 + 70 + int ret = regmap_read(rk808->regmap, RK808_CLK32OUT_REG, &val); 71 + 72 + if (ret < 0) 73 + return ret; 74 + 75 + return (val & CLK32KOUT2_EN) ? 1 : 0; 76 + } 77 + 78 + static const struct clk_ops rk808_clkout1_ops = { 79 + .recalc_rate = rk808_clkout_recalc_rate, 80 + }; 81 + 82 + static const struct clk_ops rk808_clkout2_ops = { 83 + .prepare = rk808_clkout2_prepare, 84 + .unprepare = rk808_clkout2_unprepare, 85 + .is_prepared = rk808_clkout2_is_prepared, 86 + .recalc_rate = rk808_clkout_recalc_rate, 87 + }; 88 + 89 + static int rk808_clkout_probe(struct platform_device *pdev) 90 + { 91 + struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent); 92 + struct i2c_client *client = rk808->i2c; 93 + struct device_node *node = client->dev.of_node; 94 + struct clk_init_data init = {}; 95 + struct clk **clk_table; 96 + struct rk808_clkout *rk808_clkout; 97 + 98 + rk808_clkout = devm_kzalloc(&client->dev, 99 + sizeof(*rk808_clkout), GFP_KERNEL); 100 + if (!rk808_clkout) 101 + return -ENOMEM; 102 + 103 + rk808_clkout->rk808 = rk808; 104 + 105 + clk_table = devm_kcalloc(&client->dev, RK808_NR_OUTPUT, 106 + sizeof(struct clk *), GFP_KERNEL); 107 + if (!clk_table) 108 + return -ENOMEM; 109 + 110 + init.flags = CLK_IS_ROOT; 111 + init.parent_names = NULL; 112 + init.num_parents = 0; 113 + init.name = "rk808-clkout1"; 114 + init.ops = &rk808_clkout1_ops; 115 + rk808_clkout->clkout1_hw.init = &init; 116 + 117 + /* optional override of the clockname */ 118 + of_property_read_string_index(node, "clock-output-names", 119 + 0, &init.name); 120 + 121 + clk_table[0] = devm_clk_register(&client->dev, 122 + &rk808_clkout->clkout1_hw); 123 + if (IS_ERR(clk_table[0])) 124 + return PTR_ERR(clk_table[0]); 125 + 126 + init.name = "rk808-clkout2"; 127 + init.ops = &rk808_clkout2_ops; 128 + rk808_clkout->clkout2_hw.init = &init; 129 + 130 + /* optional override of the clockname */ 131 + of_property_read_string_index(node, "clock-output-names", 132 + 1, &init.name); 133 + 134 + clk_table[1] = devm_clk_register(&client->dev, 135 + &rk808_clkout->clkout2_hw); 136 + if (IS_ERR(clk_table[1])) 137 + return PTR_ERR(clk_table[1]); 138 + 139 + rk808_clkout->clk_data.clks = clk_table; 140 + rk808_clkout->clk_data.clk_num = RK808_NR_OUTPUT; 141 + 142 + return of_clk_add_provider(node, of_clk_src_onecell_get, 143 + &rk808_clkout->clk_data); 144 + } 145 + 146 + static int rk808_clkout_remove(struct platform_device *pdev) 147 + { 148 + struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent); 149 + struct i2c_client *client = rk808->i2c; 150 + struct device_node *node = client->dev.of_node; 151 + 152 + of_clk_del_provider(node); 153 + 154 + return 0; 155 + } 156 + 157 + static struct platform_driver rk808_clkout_driver = { 158 + .probe = rk808_clkout_probe, 159 + .remove = rk808_clkout_remove, 160 + .driver = { 161 + .name = "rk808-clkout", 162 + }, 163 + }; 164 + 165 + module_platform_driver(rk808_clkout_driver); 166 + 167 + MODULE_DESCRIPTION("Clkout driver for the rk808 series PMICs"); 168 + MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>"); 169 + MODULE_LICENSE("GPL"); 170 + MODULE_ALIAS("platform:rk808-clkout");