1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (C) 2018 ROHM Semiconductors 3 4 #include <linux/kernel.h> 5 #include <linux/module.h> 6 #include <linux/init.h> 7 #include <linux/err.h> 8 #include <linux/platform_device.h> 9 #include <linux/slab.h> 10 #include <linux/mfd/rohm-generic.h> 11 #include <linux/clk-provider.h> 12 #include <linux/clkdev.h> 13 #include <linux/regmap.h> 14 15 /* clk control registers */ 16 /* BD71815 */ 17 #define BD71815_REG_OUT32K 0x1d 18 /* BD70528 */ 19 #define BD70528_REG_OUT32K 0x2c 20 /* BD71828 */ 21 #define BD71828_REG_OUT32K 0x4B 22 /* BD71837 and BD71847 */ 23 #define BD718XX_REG_OUT32K 0x2E 24 25 /* 26 * BD71837, BD71847, BD70528 and BD71828 all use bit [0] to clk output control 27 */ 28 #define CLK_OUT_EN_MASK BIT(0) 29 30 31 struct bd718xx_clk { 32 struct clk_hw hw; 33 u8 reg; 34 u8 mask; 35 struct platform_device *pdev; 36 struct regmap *regmap; 37 }; 38 39 static int bd71837_clk_set(struct bd718xx_clk *c, unsigned int status) 40 { 41 return regmap_update_bits(c->regmap, c->reg, c->mask, status); 42 } 43 44 static void bd71837_clk_disable(struct clk_hw *hw) 45 { 46 int rv; 47 struct bd718xx_clk *c = container_of(hw, struct bd718xx_clk, hw); 48 49 rv = bd71837_clk_set(c, 0); 50 if (rv) 51 dev_dbg(&c->pdev->dev, "Failed to disable 32K clk (%d)\n", rv); 52 } 53 54 static int bd71837_clk_enable(struct clk_hw *hw) 55 { 56 struct bd718xx_clk *c = container_of(hw, struct bd718xx_clk, hw); 57 58 return bd71837_clk_set(c, 0xffffffff); 59 } 60 61 static int bd71837_clk_is_enabled(struct clk_hw *hw) 62 { 63 int enabled; 64 int rval; 65 struct bd718xx_clk *c = container_of(hw, struct bd718xx_clk, hw); 66 67 rval = regmap_read(c->regmap, c->reg, &enabled); 68 69 if (rval) 70 return rval; 71 72 return enabled & c->mask; 73 } 74 75 static const struct clk_ops bd71837_clk_ops = { 76 .prepare = &bd71837_clk_enable, 77 .unprepare = &bd71837_clk_disable, 78 .is_prepared = &bd71837_clk_is_enabled, 79 }; 80 81 static int bd71837_clk_probe(struct platform_device *pdev) 82 { 83 struct bd718xx_clk *c; 84 int rval = -ENOMEM; 85 const char *parent_clk; 86 struct device *parent = pdev->dev.parent; 87 struct clk_init_data init = { 88 .name = "bd718xx-32k-out", 89 .ops = &bd71837_clk_ops, 90 }; 91 enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data; 92 93 c = devm_kzalloc(&pdev->dev, sizeof(*c), GFP_KERNEL); 94 if (!c) 95 return -ENOMEM; 96 97 c->regmap = dev_get_regmap(pdev->dev.parent, NULL); 98 if (!c->regmap) 99 return -ENODEV; 100 101 init.num_parents = 1; 102 parent_clk = of_clk_get_parent_name(parent->of_node, 0); 103 104 init.parent_names = &parent_clk; 105 if (!parent_clk) { 106 dev_err(&pdev->dev, "No parent clk found\n"); 107 return -EINVAL; 108 } 109 switch (chip) { 110 case ROHM_CHIP_TYPE_BD71837: 111 case ROHM_CHIP_TYPE_BD71847: 112 c->reg = BD718XX_REG_OUT32K; 113 c->mask = CLK_OUT_EN_MASK; 114 break; 115 case ROHM_CHIP_TYPE_BD71828: 116 c->reg = BD71828_REG_OUT32K; 117 c->mask = CLK_OUT_EN_MASK; 118 break; 119 case ROHM_CHIP_TYPE_BD70528: 120 c->reg = BD70528_REG_OUT32K; 121 c->mask = CLK_OUT_EN_MASK; 122 break; 123 case ROHM_CHIP_TYPE_BD71815: 124 c->reg = BD71815_REG_OUT32K; 125 c->mask = CLK_OUT_EN_MASK; 126 break; 127 default: 128 dev_err(&pdev->dev, "Unknown clk chip\n"); 129 return -EINVAL; 130 } 131 c->pdev = pdev; 132 c->hw.init = &init; 133 134 of_property_read_string_index(parent->of_node, 135 "clock-output-names", 0, &init.name); 136 137 rval = devm_clk_hw_register(&pdev->dev, &c->hw); 138 if (rval) { 139 dev_err(&pdev->dev, "failed to register 32K clk"); 140 return rval; 141 } 142 rval = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get, 143 &c->hw); 144 if (rval) 145 dev_err(&pdev->dev, "adding clk provider failed\n"); 146 147 return rval; 148 } 149 150 static const struct platform_device_id bd718x7_clk_id[] = { 151 { "bd71837-clk", ROHM_CHIP_TYPE_BD71837 }, 152 { "bd71847-clk", ROHM_CHIP_TYPE_BD71847 }, 153 { "bd70528-clk", ROHM_CHIP_TYPE_BD70528 }, 154 { "bd71828-clk", ROHM_CHIP_TYPE_BD71828 }, 155 { "bd71815-clk", ROHM_CHIP_TYPE_BD71815 }, 156 { }, 157 }; 158 MODULE_DEVICE_TABLE(platform, bd718x7_clk_id); 159 160 static struct platform_driver bd71837_clk = { 161 .driver = { 162 .name = "bd718xx-clk", 163 }, 164 .probe = bd71837_clk_probe, 165 .id_table = bd718x7_clk_id, 166 }; 167 168 module_platform_driver(bd71837_clk); 169 170 MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); 171 MODULE_DESCRIPTION("BD718(15/18/28/37/47/50) and BD70528 chip clk driver"); 172 MODULE_LICENSE("GPL"); 173 MODULE_ALIAS("platform:bd718xx-clk"); 174